for loops

This commit is contained in:
2026-06-22 20:11:18 +02:00
parent 380b5943b3
commit 27f42dd253
15 changed files with 1369 additions and 22 deletions
+59 -5
View File
@@ -146,6 +146,10 @@ llvm_type :: proc(value: types.Type, store: ^types.Store = nil) -> string {
return "ptr"
case .Slice:
return "{ ptr, i64 }"
case .Range:
item, _ := types.node(store, value)
child := llvm_type(item.child, store)
return fmt.tprintf("{{ %s, %s, i1 }}", child, child)
case .Array:
item, _ := types.node(store, value)
return fmt.tprintf("[%d x %s]", types.physical_count(value, store), llvm_type(item.child, store))
@@ -232,7 +236,8 @@ valid_value :: proc(
}
switch instructions[value_id].op {
case .Param, .Const, .String, .Aggregate, .None, .Optional_Some,
.Load_Global, .Function_Address, .Address_Of, .Load, .Slice, .Length, .Slice_Ptr, .Unwrap,
.Load_Global, .Function_Address, .Address_Of, .Load, .Slice, .Length, .Slice_Ptr,
.Extract, .Select, .Unwrap,
.Optional_Is_Some, .Optional_Value, .Orelse,
.Widen, .C_Vararg_Promote, .Weaken_Pointer, .Weaken_Slice, .Decay_Array_Pointer,
.Neg_Checked, .Add_Checked, .Pointer_Add, .Not, .Compare, .Call:
@@ -551,6 +556,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 == .Range {
expected_count = 3
} else {
emit_recovery_value(emitter, instruction_index, instruction, "invalid aggregate type")
continue
@@ -585,6 +592,8 @@ emit_instruction_stream :: proc(
element_type := item.child
if item.kind == .Struct {
element_type = types.fields_for(&emitter.module.types, instruction.type)[arg_index].type
} else if item.kind == .Range && arg_index == 2 {
element_type = types.BOOL
}
final := arg_index == total-1
if final {
@@ -924,6 +933,46 @@ emit_instruction_stream :: proc(
} else {
emit_recovery_value(emitter, instruction_index, instruction, "invalid container pointer")
}
case .Extract:
if !valid_instruction(instructions, instruction.a) {
emit_recovery_value(emitter, instruction_index, instruction, "invalid aggregate extraction")
continue
}
aggregate_type := instructions[instruction.a].type
item, ok := types.node(&emitter.module.types, aggregate_type)
field_index := int(instruction.integer)
expected_type := types.INVALID
if ok && item.kind == .Range && field_index >= 0 && field_index < 3 {
expected_type = types.BOOL if field_index == 2 else item.child
}
if !types.equal(expected_type, instruction.type) ||
!valid_value(instructions, instruction.a, aggregate_type, &emitter.module.types) {
emit_recovery_value(emitter, instruction_index, instruction, "invalid aggregate extraction")
continue
}
fmt.sbprintf(
&emitter.builder,
" %%v%d = extractvalue %s %%v%d, %d\n",
instruction_index,
llvm_type(aggregate_type, &emitter.module.types),
instruction.a,
field_index,
)
case .Select:
if len(instruction.args) != 2 ||
!valid_value(instructions, instruction.a, types.BOOL, &emitter.module.types) ||
!valid_value(instructions, instruction.args[0], instruction.type, &emitter.module.types) ||
!valid_value(instructions, instruction.args[1], instruction.type, &emitter.module.types) {
emit_recovery_value(emitter, instruction_index, instruction, "invalid selection")
continue
}
fmt.sbprintf(&emitter.builder, " %%v%d = select i1 ", instruction_index)
write_operand(&emitter.builder, instructions, instruction.a, types.BOOL, &emitter.module.types)
fmt.sbprintf(&emitter.builder, ", %s ", llvm_type(instruction.type, &emitter.module.types))
write_operand(&emitter.builder, instructions, instruction.args[0], instruction.type, &emitter.module.types)
fmt.sbprintf(&emitter.builder, ", %s ", llvm_type(instruction.type, &emitter.module.types))
write_operand(&emitter.builder, instructions, instruction.args[1], instruction.type, &emitter.module.types)
strings.write_string(&emitter.builder, "\n")
case .Unwrap:
optional_type := instructions[instruction.a].type if valid_instruction(instructions, instruction.a) else types.INVALID
item, ok := types.node(&emitter.module.types, optional_type)
@@ -1152,14 +1201,19 @@ emit_instruction_stream :: proc(
emit_trap_call(emitter, message)
fmt.sbprintf(&emitter.builder, " unreachable\noverflow_continue%d:\n", instruction_index)
case .Pointer_Add:
item, ok := types.node(&emitter.module.types, instruction.type)
if !ok || item.kind != .Pointer || !item.many ||
!valid_value(instructions, instruction.a, instruction.type, &emitter.module.types) ||
result_item, result_ok := types.node(&emitter.module.types, instruction.type)
base_type := instructions[instruction.a].type if valid_instruction(instructions, instruction.a) else types.INVALID
base_item, base_ok := types.node(&emitter.module.types, base_type)
if !result_ok || result_item.kind != .Pointer ||
!base_ok || base_item.kind != .Pointer || !base_item.many ||
result_item.child != base_item.child ||
result_item.mutable != base_item.mutable ||
!valid_value(instructions, instruction.a, base_type, &emitter.module.types) ||
!valid_value(instructions, instruction.b, types.USIZE, &emitter.module.types) {
emit_recovery_value(emitter, instruction_index, instruction, "invalid pointer offset")
continue
}
fmt.sbprintf(&emitter.builder, " %%v%d = getelementptr %s, ptr %%v%d, i64 ", instruction_index, llvm_type(item.child, &emitter.module.types), instruction.a)
fmt.sbprintf(&emitter.builder, " %%v%d = getelementptr %s, ptr %%v%d, i64 ", instruction_index, llvm_type(result_item.child, &emitter.module.types), instruction.a)
write_operand(&emitter.builder, instructions, instruction.b, types.USIZE, &emitter.module.types)
strings.write_string(&emitter.builder, "\n")
case .Call: