Deprecate uXX and iXX bit suffixes.

Add experimental LL / ULL suffixes for int128 and uint128 literals.
This commit is contained in:
Christoffer Lerno
2025-05-13 23:48:59 +02:00
parent c528f53d58
commit abe4727c3a
25 changed files with 126 additions and 68 deletions

View File

@@ -581,10 +581,10 @@ fn DString join(Allocator allocator, String[] s, String joiner)
}
DString res = new_with_capacity(allocator, total_size);
res.append(s[0]);
foreach (String* &str : s[1..])
foreach (String str : s[1..])
{
res.append(joiner);
res.append(*str);
res.append(str);
}
return res;
}

View File

@@ -143,7 +143,7 @@ uint128 x86_features;
fn void add_feature_if_bit(X86Feature feature, uint register, int bit)
{
if (register & 1U << bit) x86_features |= 1u128 << feature.ordinal;
if (register & 1U << bit) x86_features |= 1ULL << feature.ordinal;
}
fn void x86_initialize_cpu_features()

View File

@@ -507,7 +507,7 @@ macro bool is_finite(x)
$case float16:
return bitcast((float)x, uint) & 0x7fffffff < 0x7f800000;
$default:
return bitcast((double)x, ulong) & (~0u64 >> 1) < 0x7ffu64 << 52;
return bitcast((double)x, ulong) & (~0UL >> 1) < 0x7ffUL << 52;
$endswitch
}
@@ -521,7 +521,7 @@ macro is_nan(x)
$case float16:
return bitcast((float)x, uint) & 0x7fffffff > 0x7f800000;
$default:
return bitcast((double)x, ulong) & (~0u64 >> 1) > 0x7ffu64 << 52;
return bitcast((double)x, ulong) & (~0UL >> 1) > 0x7ffUL << 52;
$endswitch
}
@@ -535,7 +535,7 @@ macro is_inf(x)
$case float16:
return bitcast((float)x, uint) & 0x7fffffff == 0x7f800000;
$default:
return bitcast((double)x, ulong) & (~0u64 >> 1) == 0x7ffu64 << 52;
return bitcast((double)x, ulong) & (~0UL >> 1) == 0x7ffUL << 52;
$endswitch
}
@@ -1053,8 +1053,8 @@ fn double _frexp(double x, int* e)
return x;
default:
*e = ee - 0x3fe;
i &= 0x800fffffffffffffu64;
i |= 0x3fe0000000000000u64;
i &= 0x800fffffffffffffUL;
i |= 0x3fe0000000000000UL;
return bitcast(i, double);
}
}
@@ -1079,8 +1079,8 @@ fn float _frexpf(float x, int* e)
return x;
default:
*e = ee - 0x7e;
i &= 0x807fffffu32;
i |= 0x3f000000u32;
i &= 0x807fffffU;
i |= 0x3f000000U;
return bitcast(i, float);
}
}

View File

@@ -47,13 +47,13 @@ fn double _exp2_specialcase(double tmp, ulong sbits, ulong ki) @private
if (ki & 0x80000000 == 0)
{
// k > 0, the exponent of scale might have overflowed by 1.
sbits -= 1u64 << 52;
sbits -= 1UL << 52;
double scale = bitcast(sbits, double);
double y = 2 * (scale + scale * tmp);
return y;
}
// k < 0, need special care in the subnormal range.
sbits += 1022u64 << 52;
sbits += 1022UL << 52;
double scale = bitcast(sbits, double);
double y = scale + scale * tmp;
if (y >= 1.0)

View File

@@ -31,4 +31,4 @@ fn char SimpleRandom.next_byte(&self) @dynamic => (char)self.next_int();
const long SIMPLE_RANDOM_MULTIPLIER @local = 0x5DEECE66D;
const long SIMPLE_RANDOM_ADDEND @local = 0xB;
const long SIMPLE_RANDOM_MASK @local = (1u64 << 48) - 1;
const long SIMPLE_RANDOM_MASK @local = (1UL << 48) - 1;

View File

@@ -315,15 +315,15 @@ macro float_from_i128($Type, a) @private
const MANT_DIG = math::DOUBLE_MANT_DIG;
const SIGNIFICANT_BITS = 52;
const EXP_BIAS = 1023;
const MANTISSA_MASK = 0xFFFFF_FFFF_FFFFu64;
const SIGN_BIT = 1u64 << 63;
const MANTISSA_MASK = 0xFFFFF_FFFF_FFFFUL;
const SIGN_BIT = 1UL << 63;
$case float:
$Rep = uint;
const MANT_DIG = math::FLOAT_MANT_DIG;
const EXP_BIAS = 127;
const SIGNIFICANT_BITS = 23;
const MANTISSA_MASK = 0x7F_FFFFu32;
const SIGN_BIT = 1u32 << 31;
const MANTISSA_MASK = 0x7F_FFFFU;
const SIGN_BIT = 1U << 31;
$case float16:
$Rep = ushort;
const MANT_DIG = math::HALF_MANT_DIG;
@@ -352,7 +352,7 @@ macro float_from_i128($Type, a) @private
a |= (uint128)((a & 4) != 0);
a++;
a >>= 2;
if (a & (1i128 << MANT_DIG))
if (a & (1LL << MANT_DIG))
{
a >>= 1;
e++;
@@ -374,13 +374,13 @@ macro float_from_u128($Type, a) @private
const MANT_DIG = math::DOUBLE_MANT_DIG;
const SIGNIFICANT_BITS = 52;
const EXP_BIAS = 1023;
const MANTISSA_MASK = 0xFFFFF_FFFF_FFFFu64;
const MANTISSA_MASK = 0xFFFFF_FFFF_FFFFUL;
$case float:
$Rep = uint;
const MANT_DIG = math::FLOAT_MANT_DIG;
const EXP_BIAS = 127;
const SIGNIFICANT_BITS = 23;
const MANTISSA_MASK = 0x7F_FFFFu32;
const MANTISSA_MASK = 0x7F_FFFFU;
$case float16:
$Rep = ushort;
const MANT_DIG = math::HALF_MANT_DIG;
@@ -406,7 +406,7 @@ macro float_from_u128($Type, a) @private
a |= (uint128)((a & 4) != 0);
a++;
a >>= 2;
if (a & (1i128 << MANT_DIG))
if (a & (1LL << MANT_DIG))
{
a >>= 1;
e++;
@@ -458,8 +458,8 @@ macro fixuint(a) @private
int sign = rep & SIGN_BIT ? -1 : 1;
int exponent = (int)((abs >> SIGNIFICANT_BITS) - EXPONENT_BIAS);
$Rep significand = (abs & SIGNIFICANT_MASK) | IMPLICIT_BIT;
if (sign == -1 || exponent < 0) return 0u128;
if ((uint)exponent >= uint128.sizeof * 8) return ~0u128;
if (sign == -1 || exponent < 0) return 0ULL;
if ((uint)exponent >= uint128.sizeof * 8) return ~0ULL;
if (exponent < SIGNIFICANT_BITS) return (uint128)significand >> (SIGNIFICANT_BITS - exponent);
return (uint128)significand << (exponent - SIGNIFICANT_BITS);
}

View File

@@ -5,13 +5,13 @@ fn Time native_timestamp()
{
TimeSpec ts;
posix::clock_gettime(posix::CLOCK_REALTIME, &ts);
return (Time)(ts.s * 1_000_000i64 + ts.ns / 1_000i64);
return (Time)(ts.s * 1_000_000L + ts.ns / 1_000L);
}
fn Clock native_clock() @if(!env::DARWIN)
{
TimeSpec ts;
posix::clock_gettime(posix::CLOCK_MONOTONIC, &ts);
return (Clock)((ulong)ts.s * 1_000_000_000u64 + (ulong)ts.ns);
return (Clock)((ulong)ts.s * 1_000_000_000UL + (ulong)ts.ns);
}

View File

@@ -3,7 +3,7 @@ import std::os::win32;
import std::math;
const ulong WINDOWS_TICK_US @local = 10;
const ulong WIN_TO_UNIX_EPOCH_US @local = 116444736000000000u64 / WINDOWS_TICK_US;
const ulong WIN_TO_UNIX_EPOCH_US @local = 116444736000000000UL / WINDOWS_TICK_US;
fn Clock native_clock()
{

View File

@@ -5,6 +5,8 @@
### Changes / improvements
- Better default assert messages when no message is specified #2122
- Add `--run-dir`, to specify directory for running executable using `compile-run` and `run` #2121.
- Deprecate uXX and iXX bit suffixes.
- Add experimental LL / ULL suffixes for int128 and uint128 literals.
### Fixes
- Assert triggered when casting from `int[2]` to `uint[2]` #2115

View File

@@ -375,6 +375,7 @@ static bool scan_number_suffix(Lexer *lexer, bool *is_float)
{
case 'l':
c = next(lexer);
if ((c | 32) == 'l') c = next(lexer);
if (*is_float)
{
return add_error_token_at_current(lexer, "Integer suffix '%c' is not valid for a floating point literal.", c);
@@ -389,6 +390,7 @@ static bool scan_number_suffix(Lexer *lexer, bool *is_float)
if ((c | 32) == 'l')
{
c = next(lexer);
if ((c | 32) == 'l') c = next(lexer);
break;
}
while (char_is_digit(c = peek(lexer))) next(lexer);
@@ -399,6 +401,11 @@ static bool scan_number_suffix(Lexer *lexer, bool *is_float)
return add_error_token_at_current(lexer, "Integer suffix '%c' is not valid for a floating point literal.", c);
}
next(lexer);
if (!char_is_digit(peek(lexer)))
{
return add_error_token_at_current(lexer, "Integer suffix 'i' must provide a bit width.");
}
next(lexer);
while (char_is_digit(c = peek(lexer))) next(lexer);
break;
case 'f':

View File

@@ -1367,18 +1367,28 @@ static int read_num_type(const char *string, size_t loc, size_t len)
return i;
}
static int read_int_suffix(const char *string, size_t loc, size_t len, char c)
static int read_int_suffix(const char *string, size_t loc, size_t len, char c, bool *bit_suffix)
{
switch (c | 32)
{
case 'i':
return read_num_type(string, loc, len);
{
int val = read_num_type(string, loc, len);
*bit_suffix = val > 0;
return val;
}
case 'l':
if (loc == len - 2 && (string[loc + 1] | 32) == 'l') return 128;
if (loc != len - 1) return -1;
return 64;
case 'u':
{
if (loc == len - 3 && (string[loc + 1] | 32) == 'l' && (string[loc + 2] | 32) == 'l') return 128;
if (loc == len - 2 && (string[loc + 1] | 32) == 'l') return 64;
return read_num_type(string, loc, len);
int val = read_num_type(string, loc, len);
*bit_suffix = val > 0;
return val;
}
default:
return -1;
}
@@ -1399,6 +1409,7 @@ Expr *parse_integer(ParseContext *c, Expr *left)
int binary_characters = 0;
bool wrapped = false;
uint64_t max;
bool bit_suffix = false;
switch (len > 2 ? (string[1] | 32) : '0')
{
case 'x':
@@ -1410,12 +1421,12 @@ Expr *parse_integer(ParseContext *c, Expr *left)
switch (ch | 32)
{
case 'u':
type_bits = read_int_suffix(string, loc, len, ch);
type_bits = read_int_suffix(string, loc, len, ch, &bit_suffix);
is_unsigned = true;
goto EXIT;
case 'l':
case 'i':
type_bits = read_int_suffix(string, loc, len, ch);
type_bits = read_int_suffix(string, loc, len, ch, &bit_suffix);
is_unsigned = false;
goto EXIT;
case '_' | 32:
@@ -1438,12 +1449,12 @@ Expr *parse_integer(ParseContext *c, Expr *left)
switch (ch | 32)
{
case 'u':
type_bits = read_int_suffix(string, loc, len, ch);
type_bits = read_int_suffix(string, loc, len, ch, &bit_suffix);
is_unsigned = true;
goto EXIT;
case 'l':
case 'i':
type_bits = read_int_suffix(string, loc, len, ch);
type_bits = read_int_suffix(string, loc, len, ch, &bit_suffix);
is_unsigned = false;
goto EXIT;
case '_' | 32:
@@ -1466,12 +1477,12 @@ Expr *parse_integer(ParseContext *c, Expr *left)
switch (ch | 32)
{
case 'u':
type_bits = read_int_suffix(string, loc, len, ch);
type_bits = read_int_suffix(string, loc, len, ch, &bit_suffix);
is_unsigned = true;
goto EXIT;
case 'l':
case 'i':
type_bits = read_int_suffix(string, loc, len, ch);
type_bits = read_int_suffix(string, loc, len, ch, &bit_suffix);
is_unsigned = false;
goto EXIT;
case '_' | 32:
@@ -1492,12 +1503,12 @@ Expr *parse_integer(ParseContext *c, Expr *left)
switch (ch | 32)
{
case 'u':
type_bits = read_int_suffix(string, loc, len, ch);
type_bits = read_int_suffix(string, loc, len, ch, &bit_suffix);
is_unsigned = true;
goto EXIT;
case 'l':
case 'i':
type_bits = read_int_suffix(string, loc, len, ch);
type_bits = read_int_suffix(string, loc, len, ch, &bit_suffix);
is_unsigned = false;
goto EXIT;
case '_' | 32:
@@ -1529,6 +1540,44 @@ EXIT:
PRINT_ERROR_HERE("Integer type suffix should be i8, i16, i32, i64 or i128.");
return poisoned_expr;
}
const char *suffix;
if (bit_suffix)
{
switch (type_bits)
{
case 8:
case 16:
SEMA_DEPRECATED(expr_int, "Bit suffixes are deprecated, use casts instead, eg '(short)123'");
break;
case 32:
if (is_unsigned)
{
SEMA_DEPRECATED(expr_int, "Bit suffixes are deprecated, use the 'u' suffix instead eg '%.*su'.",
(int)len - 3, string);
}
else
{
SEMA_DEPRECATED(expr_int, "Bit suffixes are deprecated, use casts instead, eg '(int)%.*s'",
(int)len - 3, string);
}
break;
case 64:
case 128:
if (type_bits == 64)
{
suffix = is_unsigned ? "U" : "L";
}
else
{
suffix = is_unsigned ? "ULL" : "LL";
}
SEMA_DEPRECATED(expr_int, "Bit suffixes are deprecated, use the '%s' suffix instead eg '%.*s%s'.",
suffix, (int)len - (type_bits == 128 ? 4 : 3), string, suffix);
break;
default:
UNREACHABLE
}
}
}
else
{

View File

@@ -347,7 +347,7 @@ Expr *sema_expr_analyse_ct_arg_index(SemaContext *context, Expr *index_expr, uns
Expr *sema_ct_eval_expr(SemaContext *context, bool is_type_eval, Expr *inner, bool report_missing)
{
Path *path = NULL;
if (!sema_analyse_ct_expr(context, inner)) return false;
if (!sema_analyse_ct_expr(context, inner)) return NULL;
if (!expr_is_const_string(inner))
{
SEMA_ERROR(inner, "'%s' expects a constant string as the argument.", is_type_eval ? "$evaltype" : "$eval");

View File

@@ -145,7 +145,7 @@ extern fn int f_va_callee(int, ...);
fn void f_va_caller() {
float128 fq;
f_va_callee(1, 2, 3i64, 4.0f, 5.0, (Tiny){6, 7, 8, 9},
f_va_callee(1, 2, 3L, 4.0f, 5.0, (Tiny){6, 7, 8, 9},
(Small){10, null}, (Small_aligned){11},
(Large){12, 13, 14, 15});
f_va_callee(1, 2, 3, 4, fq, 6, 7, 8, 9);

View File

@@ -146,7 +146,7 @@ extern fn int f_va_callee(int, ...);
fn void f_va_caller() {
float128 fq;
f_va_callee(1, 2, 3i64, 4.0f, 5.0, (Tiny){6, 7, 8, 9},
f_va_callee(1, 2, 3L, 4.0f, 5.0, (Tiny){6, 7, 8, 9},
(Small){10, null}, (Small_aligned){11},
(Large){12, 13, 14, 15});
f_va_callee(1, 2, 3, 4, fq, 6, 7, 8, 9);

View File

@@ -146,7 +146,7 @@ extern fn int f_va_callee(int, ...);
fn void f_va_caller() {
float128 fq;
f_va_callee(1, 2, 3i64, 4.0f, 5.0, (Tiny){6, 7, 8, 9},
f_va_callee(1, 2, 3L, 4.0f, 5.0, (Tiny){6, 7, 8, 9},
(Small){10, null}, (Small_aligned){11},
(Large){12, 13, 14, 15});
f_va_callee(1, 2, 3, 4, fq, 6, 7, 8, 9);

View File

@@ -8,10 +8,10 @@ fn void main()
$$memcpy(&dst, &src, ushort.sizeof, false, $alignof(dst), $alignof(src));
$$memmove(&dst, &src, ushort.sizeof, false, $alignof(dst), $alignof(src));
$$memset(&dst, 0u8, ushort.sizeof, false, $alignof(dst));
$$memset(&dst, (char)0, ushort.sizeof, false, $alignof(dst));
$$memcpy_inline(&dst, &src, ushort.sizeof, false, $alignof(dst), $alignof(src));
$$memset_inline(&dst, 0u8, ushort.sizeof, false, $alignof(dst));
$$memset_inline(&dst, (char)0, ushort.sizeof, false, $alignof(dst));
}
/* #expect: test.ll

View File

@@ -116,7 +116,7 @@ fn STest2 test7(STest2 x) {
extern fn int printf(char * format, ...);
fn int main2() {
long v = 123455678902i64;
long v = 123455678902L;
printf("%lld\n", v);
return 1;
}

View File

@@ -10,7 +10,7 @@ $foreach $c : $chars:
int $offset = ($c - $from) / BITS;
int $rem = ($c - $from) % BITS;
uint128 $value = $bitmap[$offset]; // #error: is out of range
$value |= 1u128 << $rem;
$value |= 1ULL << $rem;
$bitmap = $bitmap[:$offset] +++ $value +++ $bitmap[$offset+1..]; // #error: End index out of bounds
$endforeach
}

View File

@@ -2,13 +2,13 @@ module foo;
fn void a()
{
$typeof(9146744073709551615i64) ef;
$typeof(9146744073709551615L) ef;
int fffx = ef; // #error: 'long'
}
fn void b()
{
$typeof(9223372036854775809u64) ef;
$typeof(9223372036854775809UL) ef;
int fffx = ef; // #error: 'ulong'
}

View File

@@ -4,7 +4,7 @@ fn void test1()
{
char a = 1;
int b = 2;
char c = b > a ? 1u8 : 0u8;
char c = b > a ? (char)1u : (char)0u;
int d = b ?: 1;
}

View File

@@ -22,7 +22,7 @@ fn Xe foo(Xe a)
{
a.c = 123;
a.a = 39249;
a.b = 12301230123123i64;
a.b = 12301230123123L;
a.z = 1;
return a;
}

View File

@@ -9,8 +9,8 @@ fn void check(uint128 a, uint128 b)
fn void test_big() @test
{
uint128 a = 12345678901234567890012u128;
uint128 b = 1234567890123456789001u128;
uint128 a = 12345678901234567890012ULL;
uint128 b = 1234567890123456789001ULL;
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)

View File

@@ -49,7 +49,7 @@ fn void test_expect()
int a = 2;
int b = 43;
int c = @expect(a, 2, 0.5);
int d = @expect(b, 2u8);
int d = @expect(b, 2);
}

View File

@@ -34,9 +34,9 @@ fn void test_plus()
BigInt b = bigint::from_int(234);
assert(a.add(b).equals(bigint::from_int(234 + 123)));
a = bigint::from_int(12323400012311213314141414i128);
b = bigint::from_int(23400012311213314141414i128);
assert(a.add(b).equals(bigint::from_int(12323400012311213314141414i128 + 23400012311213314141414i128)));
a = bigint::from_int(12323400012311213314141414LL);
b = bigint::from_int(23400012311213314141414LL);
assert(a.add(b).equals(bigint::from_int(12323400012311213314141414LL + 23400012311213314141414LL)));
}
fn void test_mult()
@@ -45,9 +45,9 @@ fn void test_mult()
BigInt b = bigint::from_int(234);
assert(a.mult(b).equals(bigint::from_int(234 * 123)));
a = bigint::from_int(1232311213314141414i128);
b = bigint::from_int(234000123112414i128);
assert(a.mult(b).equals(bigint::from_int(1232311213314141414i128 * 234000123112414i128)));
a = bigint::from_int(1232311213314141414LL);
b = bigint::from_int(234000123112414LL);
assert(a.mult(b).equals(bigint::from_int(1232311213314141414LL * 234000123112414LL)));
}
fn void test_minus()
@@ -56,9 +56,9 @@ fn void test_minus()
BigInt b = bigint::from_int(234);
assert(a.sub(b).equals(bigint::from_int(123 - 234)));
a = bigint::from_int(12323400012311213314141414i128);
b = bigint::from_int(23400012311213314141414i128);
assert(a.sub(b).equals(bigint::from_int(12323400012311213314141414i128 - 23400012311213314141414i128)));
a = bigint::from_int(12323400012311213314141414LL);
b = bigint::from_int(23400012311213314141414LL);
assert(a.sub(b).equals(bigint::from_int(12323400012311213314141414LL - 23400012311213314141414LL)));
}
fn void test_init_string_radix()

View File

@@ -49,7 +49,7 @@ fn void test_abs() @test
test::eq(math::abs(-2), 2);
test::eq(math::abs(2), 2);
test::eq(math::abs((int[<2>]){ -1, 2 }), (int[<2>]) { 1, 2 });
test::eq(math::abs((int128)-1), (int128)1);
test::eq(math::abs(-1LL), 1LL);
test::eq_approx(math::abs((float[<2>]) { 1, -3 }).x, 1.0, 6);
test::eq_approx(math::abs((float[<2>]) { 1, -3 }).y, 3.0, 6);
@@ -623,17 +623,17 @@ fn void test_muldiv()
assert(e.muldiv(40000, 10000) == 4_000_000);
uint f = 3_000_000_000u;
assert(f.muldiv(110, 100) == 3_300_000_000u);
long g = 1_000_000_000_000i64;
assert(g.muldiv(2_000_000_000_000i64, 1_000_000_000i64) == 2_000_000_000_000_000i64);
ulong h = 1_000_000_000_000u64;
assert(h.muldiv(2_000_000_000_000u64, 1_000_000_000u64) == 2_000_000_000_000_000u64);
long g = 1_000_000_000_000;
assert(g.muldiv(2_000_000_000_000L, 1_000_000_000L) == 2_000_000_000_000_000L);
ulong h = 1_000_000_000_000U;
assert(h.muldiv(2_000_000_000_000UL, 1_000_000_000UL) == 2_000_000_000_000_000UL);
char[<4>] i = {20, 30, 40, 50};
assert(i.muldiv(12,10) == (char[<4>]) {24, 36, 48, 60});
assert(i.muldiv((char[<4>]){11, 12, 13, 14}, (char[<4>]){10,10,10,10}) == (char[<4>]){22, 36, 52, 70});
long[<4>] j = {1_000_000_000_000i64, 2_000_000_000_000i64, 3_000_000_000_000i64, 4_000_000_000_000i64};
assert(j.muldiv(2_000_000_000_000i64, 1_000_000_000i64) == (long[<4>]){2_000_000_000_000_000i64, 4_000_000_000_000_000i64, 6_000_000_000_000_000i64, 8_000_000_000_000_000i64});
long[<4>] j = {1_000_000_000_000, 2_000_000_000_000, 3_000_000_000_000, 4_000_000_000_000};
assert(j.muldiv(2_000_000_000_000L, 1_000_000_000L) == (long[<4>]){2_000_000_000_000_000, 4_000_000_000_000_000, 6_000_000_000_000_000, 8_000_000_000_000_000});
ichar[<4>] k = {20, 30, 40, 50};
assert(k.muldiv(20,-10) == (ichar[<4>]){-40,-60,-80,-100});