This commit is contained in:
kbkpbot 2025-09-10 12:50:52 +08:00
parent aa48c61196
commit 50b184a0d1

View file

@ -3807,13 +3807,11 @@ fn (mut g Gen) expr(node_ ast.Expr) {
g.write2('-0', node.val[3..])
} else {
g.write(node.val)
val_u64 := node.val.u64()
if val_u64 & 0x80000000_00000000 != 0 && !node.val.starts_with('-') {
// a large integer with sign bit set, but without `-`, it should be a unsigned integer
val_type := determine_integer_literal_type(node)
if val_type in [ast.u32_type, ast.u64_type] {
g.write('U')
}
if val_u64 & 0xFFFFFFFF_00000000 != 0 {
// not in [min_i32, max_i32]
if val_type in [ast.i64_type, ast.u64_type] {
g.write('LL')
}
}
@ -8514,3 +8512,43 @@ fn (mut g Gen) check_noscan(elem_typ ast.Type) string {
}
return ''
}
const hi_32_mask = u64(0xFFFFFFFF00000000)
const lo_32_mask = u64(0x00000000FFFFFFFF)
const sign_bit_32 = u32(0x80000000)
const sign_bit_64 = u64(0x8000000000000000)
fn determine_integer_literal_type(node ast.IntegerLiteral) ast.Type {
is_negative := node.val.starts_with('-')
if is_negative {
uval := node.val.i64()
high32 := u32(uval >> 32)
low32 := u32(uval)
// Check if high 32 bits are all ones (0xFFFFFFFF)
// This indicates a 32-bit negative number in two's complement
high32_all_ones := high32 == u32(0xFFFFFFFF)
// Check if the sign bit (bit 31) is set in low 32 bits
// This confirms the number is negative in 32-bit context
low32_sign_bit_set := (low32 & sign_bit_32) != 0
// If both conditions are true, it's a 32-bit signed integer (i32)
// Otherwise, it requires 64-bit representation (i64)
return if high32_all_ones && low32_sign_bit_set { ast.i32_type } else { ast.i64_type }
} else {
uval := node.val.u64()
high32_all_zero := (uval & hi_32_mask) == 0
if high32_all_zero {
low32 := u32(uval)
// Check if sign bit (bit 31) is clear (0)
// This indicates the number fits in 31 bits (signed 32-bit positive)
low32_sign_bit_clear := (low32 & sign_bit_32) == 0
// If sign bit is clear, it's a signed 32-bit integer (i32)
// Otherwise, it's an unsigned 32-bit integer (u32)
return if low32_sign_bit_clear { ast.i32_type } else { ast.u32_type }
} else {
sign_bit_clear := (uval & sign_bit_64) == 0
// If sign bit is clear, it's a signed 64-bit integer (i64)
// Otherwise, it's an unsigned 64-bit integer (u64)
return if sign_bit_clear { ast.i64_type } else { ast.u64_type }
}
}
}