c bool support and c-integer coercion

This commit is contained in:
2026-06-25 17:53:04 +02:00
parent c08bc6d0cc
commit e0b6f6049c
10 changed files with 80 additions and 13 deletions
+36 -12
View File
@@ -191,6 +191,10 @@ function_result_type :: proc(function: ir.Function, store: ^types.Store) -> stri
c_abi_extension :: proc(value: types.Type, store: ^types.Store) -> string {
resolved := types.runtime_representation(value, store)
if types.is_bool(resolved) {
// clang lowers C `_Bool` as `zeroext i1` across the ABI boundary.
return "zeroext"
}
if !types.is_concrete_integer(resolved) {
return ""
}
@@ -252,7 +256,7 @@ valid_value :: proc(
.Load_Global, .Function_Address, .Address_Of, .Load, .Slice, .Length, .Slice_Ptr,
.Extract, .Select, .Unwrap,
.Optional_Is_Some, .Optional_Value, .Orelse,
.Widen, .C_Vararg_Promote, .Retype, .Weaken_Pointer, .Weaken_Slice, .Decay_Array_Pointer,
.Widen, .C_Coerce, .C_Vararg_Promote, .Retype, .Weaken_Pointer, .Weaken_Slice, .Decay_Array_Pointer,
.Neg_Checked, .Add_Checked, .Sub_Checked, .Mul_Checked, .Div_Checked, .Pointer_Add, .Not, .Compare, .Call:
return true
case .Address_Global, .Alloca, .Index_Address, .Field_Address, .Orelse_Begin,
@@ -297,19 +301,15 @@ write_constant :: proc(builder: ^strings.Builder, value: i64, value_type: types.
}
selected := store.selected if store != nil else target.DEFAULT
if types.is_float(resolved, selected) {
text := ""
// LLVM rejects decimal float literals that don't round-trip exactly, so
// emit the IEEE-754 double bit pattern as a hex literal (`0x...`), which
// always parses. For `float` we widen the f32 to f64 first — exact, and
// LLVM requires the value be representable as float, which it is.
number := transmute(f64)value
if types.bits(resolved, selected) == 32 {
bits := u32(value)
number := transmute(f32)bits
text = fmt.tprintf("%.9g", number)
} else {
number := transmute(f64)value
text = fmt.tprintf("%.17g", number)
}
strings.write_string(builder, text)
if !strings.contains(text, ".") && !strings.contains(text, "e") && !strings.contains(text, "E") {
strings.write_string(builder, ".0")
number = f64(transmute(f32)u32(value))
}
fmt.sbprintf(builder, "0x%016X", transmute(u64)number)
return
}
fmt.sbprintf(builder, "%d", value)
@@ -1198,6 +1198,30 @@ emit_instruction_stream :: proc(
fmt.sbprintf(&emitter.builder, " %%v%d = %s %s ", instruction_index, operation, llvm_type(from_type, &emitter.module.types))
write_operand(&emitter.builder, instructions, instruction.a, from_type, &emitter.module.types)
fmt.sbprintf(&emitter.builder, " to %s\n", llvm_type(instruction.type, &emitter.module.types))
case .C_Coerce:
if !valid_instruction(instructions, instruction.a) ||
!types.can_coerce_c_integer(instructions[instruction.a].type, instruction.type) {
emit_recovery_value(emitter, instruction_index, instruction, "invalid C integer coercion operand")
continue
}
from_type := instructions[instruction.a].type
from_bits := types.bits(from_type, emitter.module.target)
to_bits := types.bits(instruction.type, emitter.module.target)
if from_bits == to_bits {
// Same-width signedness change: c_uint and c_int both lower to the
// identical `iN`, so this is a pure reinterpret (no-op `select`).
type_name := llvm_type(instruction.type, &emitter.module.types)
fmt.sbprintf(&emitter.builder, " %%v%d = select i1 true, %s ", instruction_index, type_name)
write_operand(&emitter.builder, instructions, instruction.a, from_type, &emitter.module.types)
fmt.sbprintf(&emitter.builder, ", %s ", type_name)
write_operand(&emitter.builder, instructions, instruction.a, from_type, &emitter.module.types)
strings.write_string(&emitter.builder, "\n")
continue
}
operation := "sext" if types.is_signed(from_type, emitter.module.target) else "zext"
fmt.sbprintf(&emitter.builder, " %%v%d = %s %s ", instruction_index, operation, llvm_type(from_type, &emitter.module.types))
write_operand(&emitter.builder, instructions, instruction.a, from_type, &emitter.module.types)
fmt.sbprintf(&emitter.builder, " to %s\n", llvm_type(instruction.type, &emitter.module.types))
case .C_Vararg_Promote:
if !valid_instruction(instructions, instruction.a) {
emit_recovery_value(emitter, instruction_index, instruction, "invalid C variadic promotion operand")