booleans, comparisons, and if/else
This commit is contained in:
+74
-2
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user