for loops
This commit is contained in:
+357
-1
@@ -150,6 +150,18 @@ lower_location :: proc(state: ^State, expr_id: hir.Expr_Id, for_write := false)
|
||||
return ir.INVALID_INSTRUCTION
|
||||
}
|
||||
|
||||
hir_expr_is_location :: proc(state: ^State, expr_id: hir.Expr_Id) -> bool {
|
||||
if expr_id == hir.INVALID_EXPR || int(expr_id) >= len(state.hir_module.exprs) {
|
||||
return false
|
||||
}
|
||||
#partial switch state.hir_module.exprs[expr_id].kind {
|
||||
case .Local, .Global, .Deref, .Index, .Field:
|
||||
return true
|
||||
case:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
lower_compound_expr :: proc(state: ^State, expr_id: hir.Expr_Id) -> ir.Instruction_Id {
|
||||
expr := state.hir_module.exprs[expr_id]
|
||||
#partial switch expr.kind {
|
||||
@@ -169,6 +181,30 @@ lower_compound_expr :: proc(state: ^State, expr_id: hir.Expr_Id) -> ir.Instructi
|
||||
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
case .Range:
|
||||
args := make([]ir.Instruction_Id, 3, state.allocator)
|
||||
args[0] = lower_nested_expr(state, expr.args[0])
|
||||
args[1] = lower_nested_expr(state, expr.args[1])
|
||||
args[2] = append_instruction(state, ir.Instruction{
|
||||
op=.Const,
|
||||
span=expr.span,
|
||||
type=types.BOOL,
|
||||
integer=expr.integer,
|
||||
target=ir.INVALID_REF,
|
||||
a=ir.INVALID_INSTRUCTION,
|
||||
b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
return append_instruction(state, ir.Instruction{
|
||||
op=.Aggregate,
|
||||
span=expr.span,
|
||||
type=expr.type,
|
||||
args=args,
|
||||
target=ir.INVALID_REF,
|
||||
a=ir.INVALID_INSTRUCTION,
|
||||
b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
case .None:
|
||||
return append_instruction(state, ir.Instruction{
|
||||
op=.None, span=expr.span, type=expr.type,
|
||||
@@ -381,7 +417,7 @@ lower_expr :: proc(state: ^State, expr_id: hir.Expr_Id) -> ir.Instruction_Id {
|
||||
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION, diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
_ = pop(&stack)
|
||||
case .String, .Array, .Struct, .None, .Optional_Some, .Address, .Deref,
|
||||
case .String, .Array, .Struct, .Range, .None, .Optional_Some, .Address, .Deref,
|
||||
.Index, .Slice, .Field, .Length, .Slice_Ptr, .Unwrap, .Orelse,
|
||||
.Not, .Eq, .Ne, .Lt, .Le, .Gt, .Ge, .And, .Or:
|
||||
last = lower_compound_expr(state, frame.expr)
|
||||
@@ -762,6 +798,326 @@ lower_statements :: proc(state: ^State, statements: []hir.Stmt_Id) {
|
||||
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
case .For:
|
||||
iterable_type := hir_module.exprs[statement.expr].type
|
||||
if types.is_range(iterable_type, &hir_module.types) {
|
||||
child := types.child_type(iterable_type, &hir_module.types)
|
||||
range_value := lower_expr(state, statement.expr)
|
||||
start := append_instruction(state, ir.Instruction{
|
||||
op=.Extract, span=statement.span, type=child, integer=0,
|
||||
target=ir.INVALID_REF, a=range_value, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
end := append_instruction(state, ir.Instruction{
|
||||
op=.Extract, span=statement.span, type=child, integer=1,
|
||||
target=ir.INVALID_REF, a=range_value, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
inclusive := append_instruction(state, ir.Instruction{
|
||||
op=.Extract, span=statement.span, type=types.BOOL, integer=2,
|
||||
target=ir.INVALID_REF, a=range_value, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
current_slot := append_instruction(state, ir.Instruction{
|
||||
op=.Alloca, span=statement.span, type=child,
|
||||
target=ir.local_ref(ir.Local_Id(statement.local)),
|
||||
a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
state.local_slots[statement.local] = current_slot
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Store, span=statement.span, type=child,
|
||||
target=ir.INVALID_REF, a=current_slot, b=start,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
condition_lbl := fresh_label(state)
|
||||
body_lbl := fresh_label(state)
|
||||
update_lbl := fresh_label(state)
|
||||
exit_lbl := fresh_label(state)
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Br, span=statement.span, type=types.VOID, integer=condition_lbl,
|
||||
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Label, span=statement.span, type=types.VOID, integer=condition_lbl,
|
||||
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
current := append_instruction(state, ir.Instruction{
|
||||
op=.Load, span=statement.span, type=child,
|
||||
target=ir.INVALID_REF, a=current_slot, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
less := append_instruction(state, ir.Instruction{
|
||||
op=.Compare, span=statement.span, type=types.BOOL,
|
||||
integer=i64(ir.Compare_Predicate.Lt),
|
||||
target=ir.INVALID_REF, a=current, b=end,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
equal := append_instruction(state, ir.Instruction{
|
||||
op=.Compare, span=statement.span, type=types.BOOL,
|
||||
integer=i64(ir.Compare_Predicate.Eq),
|
||||
target=ir.INVALID_REF, a=current, b=end,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
false_value := append_instruction(state, ir.Instruction{
|
||||
op=.Const, span=statement.span, type=types.BOOL, integer=0,
|
||||
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
true_value := append_instruction(state, ir.Instruction{
|
||||
op=.Const, span=statement.span, type=types.BOOL, integer=1,
|
||||
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
inclusive_args := make([]ir.Instruction_Id, 2, state.allocator)
|
||||
inclusive_args[0] = equal
|
||||
inclusive_args[1] = false_value
|
||||
inclusive_equal := append_instruction(state, ir.Instruction{
|
||||
op=.Select, span=statement.span, type=types.BOOL,
|
||||
target=ir.INVALID_REF, a=inclusive, b=ir.INVALID_INSTRUCTION,
|
||||
args=inclusive_args, diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
condition_args := make([]ir.Instruction_Id, 2, state.allocator)
|
||||
condition_args[0] = true_value
|
||||
condition_args[1] = inclusive_equal
|
||||
condition := append_instruction(state, ir.Instruction{
|
||||
op=.Select, span=statement.span, type=types.BOOL,
|
||||
target=ir.INVALID_REF, a=less, b=ir.INVALID_INSTRUCTION,
|
||||
args=condition_args, diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Cond_Br, span=statement.span, type=types.VOID,
|
||||
a=condition, integer=body_lbl, target=ir.Ref(u32(exit_lbl)),
|
||||
b=ir.INVALID_INSTRUCTION, diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Label, span=statement.span, type=types.VOID, integer=body_lbl,
|
||||
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
lower_statements(state, statement.then_body)
|
||||
after_body := append_instruction(state, ir.Instruction{
|
||||
op=.Load, span=statement.span, type=child,
|
||||
target=ir.INVALID_REF, a=current_slot, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
at_end := append_instruction(state, ir.Instruction{
|
||||
op=.Compare, span=statement.span, type=types.BOOL,
|
||||
integer=i64(ir.Compare_Predicate.Eq),
|
||||
target=ir.INVALID_REF, a=after_body, b=end,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Cond_Br, span=statement.span, type=types.VOID,
|
||||
a=at_end, integer=exit_lbl, target=ir.Ref(u32(update_lbl)),
|
||||
b=ir.INVALID_INSTRUCTION, diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Label, span=statement.span, type=types.VOID, integer=update_lbl,
|
||||
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
one := append_instruction(state, ir.Instruction{
|
||||
op=.Const, span=statement.span, type=child, integer=1,
|
||||
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
next := append_instruction(state, ir.Instruction{
|
||||
op=.Add_Checked, span=statement.span, type=child,
|
||||
target=ir.INVALID_REF, a=after_body, b=one,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Store, span=statement.span, type=child,
|
||||
target=ir.INVALID_REF, a=current_slot, b=next,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Br, span=statement.span, type=types.VOID, integer=condition_lbl,
|
||||
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Label, span=statement.span, type=types.VOID, integer=exit_lbl,
|
||||
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
item, item_ok := types.container(iterable_type, &hir_module.types)
|
||||
if !item_ok {
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Trap, span=statement.span, type=types.VOID,
|
||||
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=statement.diagnostic,
|
||||
})
|
||||
continue
|
||||
}
|
||||
iterable_value := ir.INVALID_INSTRUCTION
|
||||
if types.is_array(iterable_type, &hir_module.types) {
|
||||
if hir_expr_is_location(state, statement.expr) {
|
||||
iterable_value = lower_location(state, statement.expr)
|
||||
} else {
|
||||
value := lower_expr(state, statement.expr)
|
||||
iterable_value = append_instruction(state, ir.Instruction{
|
||||
op=.Alloca, span=statement.span, type=iterable_type,
|
||||
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Store, span=statement.span, type=iterable_type,
|
||||
target=ir.INVALID_REF, a=iterable_value, b=value,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
iterable_value = lower_expr(state, statement.expr)
|
||||
}
|
||||
base := append_instruction(state, ir.Instruction{
|
||||
op=.Slice_Ptr, span=statement.span, type=statement.iterator_type,
|
||||
target=ir.INVALID_REF, a=iterable_value, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
length := ir.INVALID_INSTRUCTION
|
||||
if item.kind == .Array {
|
||||
length = append_instruction(state, ir.Instruction{
|
||||
op=.Const, span=statement.span, type=types.USIZE, integer=i64(item.count),
|
||||
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
} else {
|
||||
length = append_instruction(state, ir.Instruction{
|
||||
op=.Length, span=statement.span, type=types.USIZE,
|
||||
target=ir.INVALID_REF, a=iterable_value, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
}
|
||||
counter_target := ir.INVALID_REF
|
||||
if statement.index_local != hir.INVALID_LOCAL {
|
||||
counter_target = ir.local_ref(ir.Local_Id(statement.index_local))
|
||||
}
|
||||
counter_slot := append_instruction(state, ir.Instruction{
|
||||
op=.Alloca, span=statement.span, type=types.USIZE,
|
||||
target=counter_target, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
if statement.index_local != hir.INVALID_LOCAL {
|
||||
state.local_slots[statement.index_local] = counter_slot
|
||||
}
|
||||
zero := append_instruction(state, ir.Instruction{
|
||||
op=.Const, span=statement.span, type=types.USIZE, integer=0,
|
||||
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Store, span=statement.span, type=types.USIZE,
|
||||
target=ir.INVALID_REF, a=counter_slot, b=zero,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
capture_type := state.func_locals[statement.local].type
|
||||
capture_slot := append_instruction(state, ir.Instruction{
|
||||
op=.Alloca, span=statement.span, type=capture_type,
|
||||
target=ir.local_ref(ir.Local_Id(statement.local)),
|
||||
a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
state.local_slots[statement.local] = capture_slot
|
||||
condition_lbl := fresh_label(state)
|
||||
body_lbl := fresh_label(state)
|
||||
update_lbl := fresh_label(state)
|
||||
exit_lbl := fresh_label(state)
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Br, span=statement.span, type=types.VOID, integer=condition_lbl,
|
||||
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Label, span=statement.span, type=types.VOID, integer=condition_lbl,
|
||||
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
index := append_instruction(state, ir.Instruction{
|
||||
op=.Load, span=statement.span, type=types.USIZE,
|
||||
target=ir.INVALID_REF, a=counter_slot, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
condition := append_instruction(state, ir.Instruction{
|
||||
op=.Compare, span=statement.span, type=types.BOOL,
|
||||
integer=i64(ir.Compare_Predicate.Lt),
|
||||
target=ir.INVALID_REF, a=index, b=length,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Cond_Br, span=statement.span, type=types.VOID,
|
||||
a=condition, integer=body_lbl, target=ir.Ref(u32(exit_lbl)),
|
||||
b=ir.INVALID_INSTRUCTION, diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Label, span=statement.span, type=types.VOID, integer=body_lbl,
|
||||
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
pointer_type := statement.iterator_type
|
||||
if statement.pointer_capture {
|
||||
pointer_type = capture_type
|
||||
}
|
||||
element_pointer := append_instruction(state, ir.Instruction{
|
||||
op=.Pointer_Add, span=statement.span, type=pointer_type,
|
||||
target=ir.INVALID_REF, a=base, b=index,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
captured := element_pointer
|
||||
if !statement.pointer_capture {
|
||||
captured = append_instruction(state, ir.Instruction{
|
||||
op=.Load, span=statement.span, type=item.child,
|
||||
target=ir.INVALID_REF, a=element_pointer, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
}
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Store, span=statement.span, type=capture_type,
|
||||
target=ir.INVALID_REF, a=capture_slot, b=captured,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
lower_statements(state, statement.then_body)
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Br, span=statement.span, type=types.VOID, integer=update_lbl,
|
||||
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Label, span=statement.span, type=types.VOID, integer=update_lbl,
|
||||
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
one := append_instruction(state, ir.Instruction{
|
||||
op=.Const, span=statement.span, type=types.USIZE, integer=1,
|
||||
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
next := append_instruction(state, ir.Instruction{
|
||||
op=.Add_Checked, span=statement.span, type=types.USIZE,
|
||||
target=ir.INVALID_REF, a=index, b=one,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Store, span=statement.span, type=types.USIZE,
|
||||
target=ir.INVALID_REF, a=counter_slot, b=next,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Br, span=statement.span, type=types.VOID, integer=condition_lbl,
|
||||
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
append_instruction(state, ir.Instruction{
|
||||
op=.Label, span=statement.span, type=types.VOID, integer=exit_lbl,
|
||||
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user