Skip to content

Commit 65ad2ea

Browse files
committed
Analyser: fix 32/64 bit issues
* use `getBaseType` for conversion checks to convert ISize/USize to 32/64 bit * fix conversion errors: signed types to smaller unsigned type is loss of integer precision rather than signedness change. * fix C type generation for isize/usize
1 parent 97a7d09 commit 65ad2ea

File tree

4 files changed

+57
-26
lines changed

4 files changed

+57
-26
lines changed

analyser/conversion_checker.c2

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ const u8[elemsof(TypeKind)][elemsof(TypeKind)] Conversions = {
6666
// 5 = float -> integer
6767
// 6 = loss of FP-precision
6868
// 7 = ok, no conversion needed (eg. char -> u8, isize -> i64, i32 -> bool)
69+
// No need to adjust for 32-bit as ISize and USize are converted before the lookup
6970
const u8[elemsof(BuiltinKind)][elemsof(BuiltinKind)] BuiltinConversions = {
7071
// Char Int8 Int16 Int32 Int64 UInt8 UInt16 UInt32 UInt64 Flt32 Flt64 ISize USize Bool Void
7172
// 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
@@ -74,19 +75,19 @@ const u8[elemsof(BuiltinKind)][elemsof(BuiltinKind)] BuiltinConversions = {
7475
// Int8 ->
7576
{ 3, 0, 1, 1, 1, 3, 3, 3, 3, 1, 1, 1, 3, 7, 2 },
7677
// Int16 ->
77-
{ 4, 4, 0, 1, 1, 3, 3, 3, 3, 1, 1, 1, 3, 7, 2 },
78+
{ 4, 4, 0, 1, 1, 4, 3, 3, 3, 1, 1, 1, 3, 7, 2 },
7879
// Int32 ->
79-
{ 4, 4, 4, 0, 1, 3, 3, 3, 3, 1, 1, 1, 3, 7, 2 },
80+
{ 4, 4, 4, 7, 1, 4, 4, 3, 3, 1, 1, 1, 3, 7, 2 },
8081
// Int64 ->
81-
{ 4, 4, 4, 4, 0, 3, 3, 3, 3, 1, 1, 7, 3, 7, 2 },
82+
{ 4, 4, 4, 4, 7, 4, 4, 4, 3, 1, 1, 7, 3, 7, 2 },
8283
// UInt8 ->
83-
{ 1, 3, 3, 3, 3, 0, 1, 1, 1, 1, 1, 3, 1, 7, 2 },
84+
{ 1, 3, 1, 1, 1, 0, 1, 1, 1, 1, 1, 3, 1, 7, 2 },
8485
// UInt16 ->
85-
{ 4, 4, 3, 3, 3, 4, 0, 1, 1, 1, 1, 3, 1, 7, 2 },
86+
{ 4, 4, 3, 1, 1, 4, 0, 1, 1, 1, 1, 3, 1, 7, 2 },
8687
// UInt32 ->
87-
{ 4, 4, 4, 3, 3, 4, 4, 0, 1, 1, 1, 3, 1, 7, 2 },
88+
{ 4, 4, 4, 3, 1, 4, 4, 7, 1, 1, 1, 3, 1, 7, 2 },
8889
// UInt64 ->
89-
{ 4, 4, 4, 4, 3, 4, 4, 4, 0, 1, 1, 3, 7, 7, 2 },
90+
{ 4, 4, 4, 4, 3, 4, 4, 4, 7, 1, 1, 3, 7, 7, 2 },
9091
// Flt32 ->
9192
{ 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 1, 5, 5, 2, 2 },
9293
// Flt64 ->
@@ -227,7 +228,7 @@ fn bool Checker.checkBuiltins(Checker* c, const Type* lcanon, const Type* rcanon
227228
return true;
228229
}
229230

230-
u8 res = BuiltinConversions[rbuiltin.getKind()][lbuiltin.getKind()];
231+
u8 res = BuiltinConversions[rbuiltin.getBaseKind()][lbuiltin.getBaseKind()];
231232
switch (res) {
232233
case 0: // should not happen
233234
c.diags.error(c.loc, "BUILTIN SHOULD NOT HAPPEN (%d - %d)\n", lcanon.getKind(), rcanon.getKind());
@@ -613,6 +614,7 @@ fn bool Checker.checkPointer2BuiltinCast(Checker* c, const Type* lcanon, const T
613614
}
614615

615616
// Just takes smallest type, dont promote both sides to i32
617+
// No need to adjust for 32-bit as ISize and USize are converted before the lookup
616618
const u8[elemsof(BuiltinKind)][elemsof(BuiltinKind)] ConditionalOperatorResult = {
617619
// Char Int8 Int16 Int32 Int64 UInt8 UInt16 UInt32 UInt64 Flt32 Flt64 ISize USize Bool Void
618620
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
@@ -653,7 +655,7 @@ public fn QualType get_common_arithmetic_type(QualType t1, QualType t2) {
653655

654656
BuiltinType* bi1 = t1.getBuiltin();
655657
BuiltinType* bi2 = t2.getBuiltin();
656-
BuiltinKind kind = (BuiltinKind)ConditionalOperatorResult[bi2.getKind()][bi1.getKind()];
658+
BuiltinKind kind = (BuiltinKind)ConditionalOperatorResult[bi2.getBaseKind()][bi1.getBaseKind()];
657659
return ast.builtins[kind];
658660
}
659661

@@ -668,6 +670,7 @@ public fn QualType get_common_arithmetic_type(QualType t1, QualType t2) {
668670
6 error,
669671
*/
670672
// See ISO/IEC 9899:201x 6.3.1
673+
// No need to adjust for 32-bit as ISize and USize are converted before the lookup
671674
const u8[elemsof(BuiltinKind)][elemsof(BuiltinKind)] UsualArithmeticConversions = {
672675
// Char Int8 Int16 Int32 Int64 UInt8 UInt16 UInt32 UInt64 Flt32 Flt64 ISize USize Bool Void
673676
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14

ast/builtin_type.c2

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ const bool[] BuiltinType_integer = {
136136
}
137137
static_assert(elemsof(BuiltinKind), elemsof(BuiltinType_integer));
138138

139+
// Default builtin type sizes (adjusted for 32-bit in globals)
139140
const u32[] BuiltinType_default_sizes = {
140141
[BuiltinKind.Char] = 1,
141142
[BuiltinKind.Int8] = 1,
@@ -148,13 +149,14 @@ const u32[] BuiltinType_default_sizes = {
148149
[BuiltinKind.UInt64] = 8,
149150
[BuiltinKind.Float32] = 4,
150151
[BuiltinKind.Float64] = 8,
151-
[BuiltinKind.ISize] = 8, // ISize <- need to change for ARCH
152-
[BuiltinKind.USize] = 8, // USize <- need to change for ARCH
152+
[BuiltinKind.ISize] = 8, // adjusted in global
153+
[BuiltinKind.USize] = 8, // adjusted in global
153154
[BuiltinKind.Bool] = 1,
154155
[BuiltinKind.Void] = 0,
155156
}
156157
static_assert(elemsof(BuiltinKind), elemsof(BuiltinType_default_sizes));
157158

159+
// Default builtin type widths (adjusted for 32-bit in globals)
158160
const u32[] BuiltinType_default_widths = {
159161
[BuiltinKind.Char] = 8,
160162
[BuiltinKind.Int8] = 7,
@@ -167,13 +169,14 @@ const u32[] BuiltinType_default_widths = {
167169
[BuiltinKind.UInt64] = 64,
168170
[BuiltinKind.Float32] = 0,
169171
[BuiltinKind.Float64] = 0,
170-
[BuiltinKind.ISize] = 63, // ISize <- need to change for ARCH
171-
[BuiltinKind.USize] = 64, // USize <- need to change for ARCH
172+
[BuiltinKind.ISize] = 63, // adjusted in global
173+
[BuiltinKind.USize] = 64, // adjusted in global
172174
[BuiltinKind.Bool] = 1,
173175
[BuiltinKind.Void] = 0,
174176
}
175177
static_assert(elemsof(BuiltinKind), elemsof(BuiltinType_default_widths));
176178

179+
// Default builtin bitfield widths (adjusted for 32-bit in globals)
177180
const u32[] BuiltinType_bitfield_sizes = {
178181
[BuiltinKind.Char] = 8,
179182
[BuiltinKind.Int8] = 8,
@@ -186,8 +189,8 @@ const u32[] BuiltinType_bitfield_sizes = {
186189
[BuiltinKind.UInt64] = 64,
187190
[BuiltinKind.Float32] = 0,
188191
[BuiltinKind.Float64] = 0,
189-
[BuiltinKind.ISize] = 64, // ISize <- need to change for ARCH
190-
[BuiltinKind.USize] = 64, // USize <- need to change for ARCH
192+
[BuiltinKind.ISize] = 64, // adjusted in global
193+
[BuiltinKind.USize] = 64, // adjusted in global
191194
[BuiltinKind.Bool] = 1,
192195
[BuiltinKind.Void] = 0,
193196
}

generator/c/c_generator.c2

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1325,11 +1325,9 @@ const char[] C_types =
13251325
typedef unsigned short uint16_t;
13261326
typedef signed int int32_t;
13271327
typedef unsigned int uint32_t;
1328-
// FIXME: these should be target dependent
1329-
typedef signed long int64_t;
1330-
typedef unsigned long uint64_t;
1331-
typedef long ssize_t;
1332-
typedef unsigned long size_t;
1328+
```;
1329+
const char[] C_defines =
1330+
```c
13331331
#define true 1
13341332
#define false 0
13351333

@@ -1378,6 +1376,33 @@ fn void Generator.emit_external_header(Generator* gen, bool enable_asserts, cons
13781376
out.add(Include_guard1);
13791377
out.add(Warning_control);
13801378
out.add(C_types);
1379+
if (ast.getWordSize() == 4) {
1380+
// ILP32 (32-bit int, long and pointers)
1381+
out.add(```c
1382+
typedef signed long long int64_t;
1383+
typedef unsigned long long uint64_t;
1384+
typedef signed long ssize_t;
1385+
typedef unsigned long size_t;
1386+
```);
1387+
} else {
1388+
// LP64 (64-bit long and pointers)
1389+
out.add(```c
1390+
typedef signed long int64_t;
1391+
typedef unsigned long uint64_t;
1392+
typedef signed long ssize_t;
1393+
typedef unsigned long size_t;
1394+
```);
1395+
#if 0
1396+
// TODO support LLP64 (64-bit long long and pointers, but 32-bit long)
1397+
out.add(```c
1398+
typedef signed long long int64_t;
1399+
typedef unsigned long long uint64_t;
1400+
typedef signed long long ssize_t;
1401+
typedef unsigned long long size_t;
1402+
```);
1403+
#endif
1404+
}
1405+
out.add(C_defines);
13811406
#if 1
13821407
// __builtin_offsetof is supported by gcc and clang and is necessary
13831408
// for -fsanitary=undefined to prevent null pointer arithmetics warnings.

test/types/conversion/integer_types.c2

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ fn void test_i16(i16 a) {
4949
i16 s = a;
5050
i32 i = a;
5151
i64 l = a;
52-
u8 m2 = a; // @error{implicit conversion changes signedness: 'i16' to 'u8'}
52+
u8 m2 = a; // @error{implicit conversion loses integer precision: 'i16' to 'u8'}
5353
u16 s2 = a; // @error{implicit conversion changes signedness: 'i16' to 'u16'}
5454
u32 i2 = a; // @error{implicit conversion changes signedness: 'i16' to 'u32'}
5555
u64 l2 = a; // @error{implicit conversion changes signedness: 'i16' to 'u64'}
@@ -63,8 +63,8 @@ fn void test_i32(i32 a) {
6363
i16 s = a; // @error{implicit conversion loses integer precision: 'i32' to 'i16'}
6464
i32 i = a;
6565
i64 l = a;
66-
u8 m2 = a; // @error{implicit conversion changes signedness: 'i32' to 'u8'}
67-
u16 s2 = a; // @error{implicit conversion changes signedness: 'i32' to 'u16'}
66+
u8 m2 = a; // @error{implicit conversion loses integer precision: 'i32' to 'u8'}
67+
u16 s2 = a; // @error{implicit conversion loses integer precision: 'i32' to 'u16'}
6868
u32 i2 = a; // @error{implicit conversion changes signedness: 'i32' to 'u32'}
6969
u64 l2 = a; // @error{implicit conversion changes signedness: 'i32' to 'u64'}
7070
isize is = a;
@@ -77,9 +77,9 @@ fn void test_i64(i64 a) {
7777
i16 s = a; // @error{implicit conversion loses integer precision: 'i64' to 'i16'}
7878
i32 i = a; // @error{implicit conversion loses integer precision: 'i64' to 'i32'}
7979
i64 l = a;
80-
u8 m2 = a; // @error{implicit conversion changes signedness: 'i64' to 'u8'}
81-
u16 s2 = a; // @error{implicit conversion changes signedness: 'i64' to 'u16'}
82-
u32 i2 = a; // @error{implicit conversion changes signedness: 'i64' to 'u32'}
80+
u8 m2 = a; // @error{implicit conversion loses integer precision: 'i64' to 'u8'}
81+
u16 s2 = a; // @error{implicit conversion loses integer precision: 'i64' to 'u16'}
82+
u32 i2 = a; // @error{implicit conversion loses integer precision: 'i64' to 'u32'}
8383
u64 l2 = a; // @error{implicit conversion changes signedness: 'i64' to 'u64'}
8484
isize is = a;
8585
usize us = a; // @error{implicit conversion changes signedness: 'i64' to 'usize'}

0 commit comments

Comments
 (0)