booleans, comparisons, and if/else

This commit is contained in:
2026-06-21 20:20:55 +02:00
parent 19e9fbdd4b
commit c90ada608e
13 changed files with 1064 additions and 518 deletions
+74 -2
View File
@@ -138,6 +138,9 @@ llvm_type :: proc(value: types.Type, store: ^types.Store = nil) -> string {
if types.is_void(value) {
return "void"
}
if types.is_bool(value) {
return "i1"
}
#partial switch types.kind(value, store) {
case .Pointer:
return "ptr"
@@ -201,6 +204,9 @@ emit_function_result :: proc(builder: ^strings.Builder, function: ir.Function, s
}
sentinel :: proc(value_type: types.Type, selected := target.DEFAULT) -> i64 {
if types.is_bool(value_type) {
return 0
}
switch types.bits(value_type, selected) {
case 8: return -86
case 16: return -21846
@@ -228,10 +234,10 @@ valid_value :: proc(
case .Param, .Const, .String, .Aggregate, .None, .Optional_Some,
.Load_Global, .Function_Address, .Address_Of, .Load, .Slice, .Length, .Slice_Ptr, .Unwrap, .Orelse,
.Widen, .C_Vararg_Promote, .Weaken_Pointer, .Weaken_Slice, .Decay_Array_Pointer,
.Neg_Checked, .Add_Checked, .Pointer_Add, .Call:
.Neg_Checked, .Add_Checked, .Pointer_Add, .Not, .Compare, .Call:
return true
case .Address_Global, .Alloca, .Index_Address, .Field_Address, .Orelse_Begin,
.Store, .Trap, .Return, .Return_Void:
.Store, .Trap, .Label, .Br, .Cond_Br, .Return, .Return_Void:
return false
}
return false
@@ -262,6 +268,10 @@ write_constant :: proc(builder: ^strings.Builder, value: i64, value_type: types.
strings.write_string(builder, "zeroinitializer")
return
}
if types.is_bool(value_type) {
strings.write_string(builder, "true" if value != 0 else "false")
return
}
selected := store.selected if store != nil else target.DEFAULT
if types.is_float(value_type, selected) {
text := ""
@@ -462,6 +472,30 @@ emit_unpack_c_record :: proc(
fmt.sbprintf(&emitter.builder, " %s = load %s, ptr %%abi_unpack_slot%d\n", result_name, llvm_type(value_type, &emitter.module.types), tag)
}
integer_predicate :: proc(predicate: ir.Compare_Predicate, signed: bool) -> string {
switch predicate {
case .Eq: return "eq"
case .Ne: return "ne"
case .Lt: return "slt" if signed else "ult"
case .Le: return "sle" if signed else "ule"
case .Gt: return "sgt" if signed else "ugt"
case .Ge: return "sge" if signed else "uge"
}
return "eq"
}
float_predicate :: proc(predicate: ir.Compare_Predicate) -> string {
switch predicate {
case .Eq: return "oeq"
case .Ne: return "une"
case .Lt: return "olt"
case .Le: return "ole"
case .Gt: return "ogt"
case .Ge: return "oge"
}
return "oeq"
}
emit_instruction_stream :: proc(
emitter: ^Emitter,
instructions: []ir.Instruction,
@@ -1335,6 +1369,44 @@ emit_instruction_stream :: proc(
100000+instruction_index,
)
}
case .Not:
if !valid_value(instructions, instruction.a, types.BOOL, &emitter.module.types) {
emit_recovery_value(emitter, instruction_index, instruction, "invalid '!' operand")
continue
}
fmt.sbprintf(&emitter.builder, " %%v%d = xor i1 ", instruction_index)
write_operand(&emitter.builder, instructions, instruction.a, types.BOOL, &emitter.module.types)
strings.write_string(&emitter.builder, ", true\n")
case .Compare:
operand_type := instructions[instruction.a].type if valid_instruction(instructions, instruction.a) else types.INVALID
if !valid_value(instructions, instruction.a, operand_type, &emitter.module.types) ||
!valid_value(instructions, instruction.b, operand_type, &emitter.module.types) {
emit_recovery_value(emitter, instruction_index, instruction, "invalid comparison operand")
continue
}
predicate := ir.Compare_Predicate(instruction.integer)
type_name := llvm_type(operand_type, &emitter.module.types)
if types.is_float(operand_type, emitter.module.target) {
fmt.sbprintf(&emitter.builder, " %%v%d = fcmp %s %s ", instruction_index, float_predicate(predicate), type_name)
} else {
fmt.sbprintf(&emitter.builder, " %%v%d = icmp %s %s ", instruction_index, integer_predicate(predicate, types.is_signed(operand_type, emitter.module.target)), type_name)
}
write_operand(&emitter.builder, instructions, instruction.a, operand_type, &emitter.module.types)
strings.write_string(&emitter.builder, ", ")
write_operand(&emitter.builder, instructions, instruction.b, operand_type, &emitter.module.types)
strings.write_string(&emitter.builder, "\n")
case .Label:
fmt.sbprintf(&emitter.builder, "bro_block_%d:\n", instruction.integer)
case .Br:
fmt.sbprintf(&emitter.builder, " br label %%bro_block_%d\n", instruction.integer)
case .Cond_Br:
if !valid_value(instructions, instruction.a, types.BOOL, &emitter.module.types) {
fmt.sbprintf(&emitter.builder, " br label %%bro_block_%d\n", u32(instruction.target))
continue
}
strings.write_string(&emitter.builder, " br i1 ")
write_operand(&emitter.builder, instructions, instruction.a, types.BOOL, &emitter.module.types)
fmt.sbprintf(&emitter.builder, ", label %%bro_block_%d, label %%bro_block_%d\n", instruction.integer, u32(instruction.target))
case .Trap:
message := diagnostic_message(emitter, instruction.diagnostic, instruction.span, "invalid recovered source")
emit_trap_call(emitter, message)