error handling kickoff
This commit is contained in:
+117
-4
@@ -163,7 +163,7 @@ llvm_type :: proc(value: types.Type, store: ^types.Store = nil) -> string {
|
||||
return "ptr"
|
||||
}
|
||||
return fmt.tprintf("{{ i1, %s }}", llvm_type(item.child, store))
|
||||
case .Struct, .Union:
|
||||
case .Struct, .Union, .Fallible:
|
||||
return fmt.tprintf("%%bro.type.%d", resolved)
|
||||
}
|
||||
selected := store.selected if store != nil else target.DEFAULT
|
||||
@@ -256,7 +256,7 @@ valid_value :: proc(
|
||||
.Load_Global, .Function_Address, .Address_Of, .Load, .Union_Tag, .Slice, .Length, .Slice_Ptr,
|
||||
.Extract, .Select, .Unwrap,
|
||||
.Optional_Is_Some, .Optional_Value, .Orelse,
|
||||
.Widen, .C_Coerce, .C_Vararg_Promote, .Retype, .Weaken_Pointer, .Weaken_Slice, .Decay_Array_Pointer,
|
||||
.Widen, .Sum_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,
|
||||
@@ -690,6 +690,8 @@ emit_instruction_stream :: proc(
|
||||
expected_count = int(item.field_count)
|
||||
} else if ok && item.kind == .Union {
|
||||
expected_count = 1
|
||||
} else if ok && item.kind == .Fallible {
|
||||
expected_count = 1
|
||||
} else if ok && item.kind == .Range {
|
||||
expected_count = 3
|
||||
} else {
|
||||
@@ -701,6 +703,56 @@ emit_instruction_stream :: proc(
|
||||
continue
|
||||
}
|
||||
type_name := llvm_type(instruction.type, &emitter.module.types)
|
||||
if item.kind == .Fallible {
|
||||
success := item.child
|
||||
error_type := item.extra
|
||||
error_path := instruction.integer != 0
|
||||
payload_offset := types.fallible_payload_offset(instruction.type, &emitter.module.types, emitter.module.target)
|
||||
fmt.sbprintf(&emitter.builder, " %%fallible_slot%d = alloca %s, align %d\n", instruction_index, type_name, types.alignment_of(instruction.type, &emitter.module.types, emitter.module.target))
|
||||
fmt.sbprintf(&emitter.builder, " store %s zeroinitializer, ptr %%fallible_slot%d\n", type_name, instruction_index)
|
||||
if !error_path {
|
||||
fmt.sbprintf(&emitter.builder, " store i16 0, ptr %%fallible_slot%d\n", instruction_index)
|
||||
if !types.is_void(success) {
|
||||
if !valid_value(instructions, instruction.args[0], success, &emitter.module.types) {
|
||||
emit_recovery_value(emitter, instruction_index, instruction, "invalid fallible success operand")
|
||||
continue
|
||||
}
|
||||
fmt.sbprintf(&emitter.builder, " %%fallible_payload%d = getelementptr i8, ptr %%fallible_slot%d, i64 %d\n", instruction_index, instruction_index, payload_offset)
|
||||
fmt.sbprintf(&emitter.builder, " store %s ", llvm_type(success, &emitter.module.types))
|
||||
write_operand(&emitter.builder, instructions, instruction.args[0], success, &emitter.module.types)
|
||||
fmt.sbprintf(&emitter.builder, ", ptr %%fallible_payload%d\n", instruction_index)
|
||||
}
|
||||
} else if types.is_enum(error_type, &emitter.module.types) {
|
||||
if !valid_value(instructions, instruction.args[0], error_type, &emitter.module.types) {
|
||||
emit_recovery_value(emitter, instruction_index, instruction, "invalid fallible enum error operand")
|
||||
continue
|
||||
}
|
||||
fmt.sbprintf(&emitter.builder, " store i16 ")
|
||||
write_operand(&emitter.builder, instructions, instruction.args[0], error_type, &emitter.module.types)
|
||||
fmt.sbprintf(&emitter.builder, ", ptr %%fallible_slot%d\n", instruction_index)
|
||||
} else if types.is_tagged_union(error_type, &emitter.module.types) {
|
||||
if !valid_value(instructions, instruction.args[0], error_type, &emitter.module.types) {
|
||||
emit_recovery_value(emitter, instruction_index, instruction, "invalid fallible union error operand")
|
||||
continue
|
||||
}
|
||||
error_slot_align := types.alignment_of(error_type, &emitter.module.types, emitter.module.target)
|
||||
fmt.sbprintf(&emitter.builder, " %%fallible_error_slot%d = alloca %s, align %d\n", instruction_index, llvm_type(error_type, &emitter.module.types), error_slot_align)
|
||||
fmt.sbprintf(&emitter.builder, " store %s ", llvm_type(error_type, &emitter.module.types))
|
||||
write_operand(&emitter.builder, instructions, instruction.args[0], error_type, &emitter.module.types)
|
||||
fmt.sbprintf(&emitter.builder, ", ptr %%fallible_error_slot%d\n", instruction_index)
|
||||
fmt.sbprintf(&emitter.builder, " %%fallible_error_code%d = load i16, ptr %%fallible_error_slot%d\n", instruction_index, instruction_index)
|
||||
fmt.sbprintf(&emitter.builder, " store i16 %%fallible_error_code%d, ptr %%fallible_slot%d\n", instruction_index, instruction_index)
|
||||
error_payload_offset := types.union_payload_offset(error_type, &emitter.module.types, emitter.module.target)
|
||||
error_payload_size := types.sum_payload_size(error_type, &emitter.module.types, emitter.module.target)
|
||||
if error_payload_size > 0 {
|
||||
fmt.sbprintf(&emitter.builder, " %%fallible_error_payload%d = getelementptr i8, ptr %%fallible_error_slot%d, i64 %d\n", instruction_index, instruction_index, error_payload_offset)
|
||||
fmt.sbprintf(&emitter.builder, " %%fallible_payload%d = getelementptr i8, ptr %%fallible_slot%d, i64 %d\n", instruction_index, instruction_index, payload_offset)
|
||||
fmt.sbprintf(&emitter.builder, " call void @llvm.memcpy.p0.p0.i64(ptr %%fallible_payload%d, ptr %%fallible_error_payload%d, i64 %d, i1 false)\n", instruction_index, instruction_index, error_payload_size)
|
||||
}
|
||||
}
|
||||
fmt.sbprintf(&emitter.builder, " %%v%d = load %s, ptr %%fallible_slot%d\n", instruction_index, type_name, instruction_index)
|
||||
continue
|
||||
}
|
||||
if item.kind == .Union {
|
||||
fields := types.fields_for(&emitter.module.types, instruction.type)
|
||||
field_index := int(instruction.integer)
|
||||
@@ -958,6 +1010,10 @@ emit_instruction_stream :: proc(
|
||||
if types.is_pointer(base_type, &emitter.module.types) {
|
||||
base_type = types.child_type(base_type, &emitter.module.types)
|
||||
}
|
||||
if types.kind(base_type, &emitter.module.types) == .Fallible {
|
||||
fmt.sbprintf(&emitter.builder, " %%v%d = getelementptr i8, ptr %%v%d, i64 %d\n", instruction_index, instruction.a, types.fallible_payload_offset(base_type, &emitter.module.types, emitter.module.target))
|
||||
continue
|
||||
}
|
||||
fields := types.fields_for(&emitter.module.types, base_type)
|
||||
field_index := int(instruction.integer)
|
||||
if field_index < 0 || field_index >= len(fields) ||
|
||||
@@ -1254,6 +1310,45 @@ 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 .Sum_Widen:
|
||||
if !valid_instruction(instructions, instruction.a) ||
|
||||
!types.can_sum_widen(instructions[instruction.a].type, instruction.type, &emitter.module.types) {
|
||||
emit_recovery_value(emitter, instruction_index, instruction, "invalid sum widening operand")
|
||||
continue
|
||||
}
|
||||
from_type := instructions[instruction.a].type
|
||||
if types.is_enum(from_type, &emitter.module.types) && types.is_enum(instruction.type, &emitter.module.types) {
|
||||
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 zeroinitializer\n", type_name)
|
||||
continue
|
||||
}
|
||||
if types.is_tagged_union(from_type, &emitter.module.types) && types.is_tagged_union(instruction.type, &emitter.module.types) {
|
||||
from_name := llvm_type(from_type, &emitter.module.types)
|
||||
to_name := llvm_type(instruction.type, &emitter.module.types)
|
||||
from_align := types.alignment_of(from_type, &emitter.module.types, emitter.module.target)
|
||||
to_align := types.alignment_of(instruction.type, &emitter.module.types, emitter.module.target)
|
||||
fmt.sbprintf(&emitter.builder, " %%sum_from_slot%d = alloca %s, align %d\n", instruction_index, from_name, from_align)
|
||||
fmt.sbprintf(&emitter.builder, " store %s ", from_name)
|
||||
write_operand(&emitter.builder, instructions, instruction.a, from_type, &emitter.module.types)
|
||||
fmt.sbprintf(&emitter.builder, ", ptr %%sum_from_slot%d\n", instruction_index)
|
||||
fmt.sbprintf(&emitter.builder, " %%sum_to_slot%d = alloca %s, align %d\n", instruction_index, to_name, to_align)
|
||||
fmt.sbprintf(&emitter.builder, " store %s zeroinitializer, ptr %%sum_to_slot%d\n", to_name, instruction_index)
|
||||
fmt.sbprintf(&emitter.builder, " %%sum_tag%d = load i16, ptr %%sum_from_slot%d\n", instruction_index, instruction_index)
|
||||
fmt.sbprintf(&emitter.builder, " store i16 %%sum_tag%d, ptr %%sum_to_slot%d\n", instruction_index, instruction_index)
|
||||
from_payload_offset := types.union_payload_offset(from_type, &emitter.module.types, emitter.module.target)
|
||||
to_payload_offset := types.union_payload_offset(instruction.type, &emitter.module.types, emitter.module.target)
|
||||
payload_size := types.sum_payload_size(from_type, &emitter.module.types, emitter.module.target)
|
||||
if payload_size > 0 {
|
||||
fmt.sbprintf(&emitter.builder, " %%sum_from_payload%d = getelementptr i8, ptr %%sum_from_slot%d, i64 %d\n", instruction_index, instruction_index, from_payload_offset)
|
||||
fmt.sbprintf(&emitter.builder, " %%sum_to_payload%d = getelementptr i8, ptr %%sum_to_slot%d, i64 %d\n", instruction_index, instruction_index, to_payload_offset)
|
||||
fmt.sbprintf(&emitter.builder, " call void @llvm.memcpy.p0.p0.i64(ptr %%sum_to_payload%d, ptr %%sum_from_payload%d, i64 %d, i1 false)\n", instruction_index, instruction_index, payload_size)
|
||||
}
|
||||
fmt.sbprintf(&emitter.builder, " %%v%d = load %s, ptr %%sum_to_slot%d\n", instruction_index, to_name, instruction_index)
|
||||
continue
|
||||
}
|
||||
emit_recovery_value(emitter, instruction_index, instruction, "unsupported sum widening operand")
|
||||
case .C_Coerce:
|
||||
if !valid_instruction(instructions, instruction.a) ||
|
||||
!types.can_coerce_c_integer(instructions[instruction.a].type, instruction.type) {
|
||||
@@ -1814,7 +1909,7 @@ emit_globals :: proc(emitter: ^Emitter) {
|
||||
|
||||
emit_types :: proc(emitter: ^Emitter) {
|
||||
for item, index in emitter.module.types.nodes {
|
||||
if item.kind != .Struct && item.kind != .Union {
|
||||
if item.kind != .Struct && item.kind != .Union && item.kind != .Fallible {
|
||||
continue
|
||||
}
|
||||
id := types.DYNAMIC_START+types.Type(index)
|
||||
@@ -1823,6 +1918,24 @@ emit_types :: proc(emitter: ^Emitter) {
|
||||
strings.write_string(&emitter.builder, "opaque\n")
|
||||
continue
|
||||
}
|
||||
if item.kind == .Fallible {
|
||||
payload_offset := types.fallible_payload_offset(id, &emitter.module.types, emitter.module.target)
|
||||
payload_size := types.fallible_payload_size(id, &emitter.module.types, emitter.module.target)
|
||||
total_size := types.size(id, &emitter.module.types, emitter.module.target)
|
||||
strings.write_string(&emitter.builder, "{ i16")
|
||||
if payload_offset > 2 {
|
||||
fmt.sbprintf(&emitter.builder, ", [%d x i8]", payload_offset-2)
|
||||
}
|
||||
if payload_size > 0 {
|
||||
fmt.sbprintf(&emitter.builder, ", [%d x i8]", payload_size)
|
||||
}
|
||||
used := payload_offset + payload_size
|
||||
if used < total_size {
|
||||
fmt.sbprintf(&emitter.builder, ", [%d x i8]", total_size-used)
|
||||
}
|
||||
strings.write_string(&emitter.builder, " }\n")
|
||||
continue
|
||||
}
|
||||
if item.kind == .Union {
|
||||
fields := types.fields_for(&emitter.module.types, id)
|
||||
carrier := types.INVALID
|
||||
@@ -1839,7 +1952,7 @@ emit_types :: proc(emitter: ^Emitter) {
|
||||
}
|
||||
}
|
||||
total_size := types.size(id, &emitter.module.types, emitter.module.target)
|
||||
if !types.is_valid(carrier) {
|
||||
if !types.is_valid(carrier) || types.is_void(carrier) {
|
||||
fmt.sbprintf(&emitter.builder, "[%d x i8]\n", total_size)
|
||||
continue
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user