c interop type foundation
This commit is contained in:
+249
-37
@@ -3,6 +3,7 @@ package lower
|
||||
import "../hir"
|
||||
import "../ir"
|
||||
import "../source"
|
||||
import "../target"
|
||||
import "../types"
|
||||
import "core:fmt"
|
||||
import "core:mem"
|
||||
@@ -28,8 +29,11 @@ clone_args :: proc(values: []ir.Instruction_Id, allocator: mem.Allocator) -> []i
|
||||
return result
|
||||
}
|
||||
|
||||
sentinel :: proc(value_type: types.Type) -> i64 {
|
||||
switch value_type.bits {
|
||||
sentinel :: proc(value_type: types.Type, selected := target.DEFAULT) -> i64 {
|
||||
if types.is_float(value_type, selected) {
|
||||
return i64(0x7fc0_0000) if types.bits(value_type, selected) == 32 else transmute(i64)u64(0x7ff8_0000_0000_0000)
|
||||
}
|
||||
switch types.bits(value_type, selected) {
|
||||
case 8: return -86
|
||||
case 16: return -21846
|
||||
case 32: return -1431655766
|
||||
@@ -53,14 +57,14 @@ append_recovery_value :: proc(
|
||||
diagnostic=diagnostic,
|
||||
})
|
||||
fallback := value_type
|
||||
if !types.is_concrete_integer(fallback) {
|
||||
if !types.is_valid(fallback) {
|
||||
fallback = types.I64
|
||||
}
|
||||
return append_instruction(state, ir.Instruction{
|
||||
op=.Const,
|
||||
span=span,
|
||||
type=fallback,
|
||||
integer=sentinel(fallback),
|
||||
integer=sentinel(fallback, state.hir_module.target),
|
||||
target=ir.INVALID_REF,
|
||||
a=ir.INVALID_INSTRUCTION,
|
||||
b=ir.INVALID_INSTRUCTION,
|
||||
@@ -76,6 +80,187 @@ Lower_Expr_Frame :: struct {
|
||||
args: []ir.Instruction_Id,
|
||||
}
|
||||
|
||||
lower_nested_expr :: proc(state: ^State, expr_id: hir.Expr_Id) -> ir.Instruction_Id {
|
||||
outer := state.expr_stack
|
||||
state.expr_stack = nil
|
||||
state.expr_stack.allocator = state.allocator
|
||||
result := lower_expr(state, expr_id)
|
||||
delete(state.expr_stack)
|
||||
state.expr_stack = outer
|
||||
return result
|
||||
}
|
||||
|
||||
lower_location :: proc(state: ^State, expr_id: hir.Expr_Id, for_write := false) -> ir.Instruction_Id {
|
||||
if expr_id == hir.INVALID_EXPR || int(expr_id) >= len(state.hir_module.exprs) {
|
||||
return ir.INVALID_INSTRUCTION
|
||||
}
|
||||
expr := state.hir_module.exprs[expr_id]
|
||||
#partial switch expr.kind {
|
||||
case .Local:
|
||||
local := hir.as_local(expr.target)
|
||||
if local != hir.INVALID_LOCAL && int(local) < len(state.local_slots) {
|
||||
return state.local_slots[local]
|
||||
}
|
||||
case .Global:
|
||||
global := hir.as_global(expr.target)
|
||||
if global != hir.INVALID_GLOBAL && int(global) < len(state.hir_module.globals) {
|
||||
return append_instruction(state, ir.Instruction{
|
||||
op=.Address_Global, span=expr.span, type=expr.type,
|
||||
target=ir.global_ref(ir.Global_Id(global)),
|
||||
a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
}
|
||||
case .Deref:
|
||||
return lower_nested_expr(state, expr.left)
|
||||
case .Index:
|
||||
container_type := state.hir_module.exprs[expr.left].type
|
||||
container := lower_nested_expr(state, expr.left)
|
||||
if types.is_array(container_type, &state.hir_module.types) {
|
||||
container = lower_location(state, expr.left, for_write)
|
||||
}
|
||||
index := lower_nested_expr(state, expr.right)
|
||||
return append_instruction(state, ir.Instruction{
|
||||
op=.Index_Address, span=expr.span, type=expr.type,
|
||||
integer=0 if for_write else 1,
|
||||
target=ir.INVALID_REF, a=container, b=index,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
case .Field:
|
||||
base_type := state.hir_module.exprs[expr.left].type
|
||||
base := lower_nested_expr(state, expr.left)
|
||||
if !types.is_pointer(base_type, &state.hir_module.types) {
|
||||
base = lower_location(state, expr.left, for_write)
|
||||
}
|
||||
return append_instruction(state, ir.Instruction{
|
||||
op=.Field_Address, span=expr.span, type=expr.type, integer=expr.integer,
|
||||
target=ir.INVALID_REF, a=base, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
}
|
||||
return ir.INVALID_INSTRUCTION
|
||||
}
|
||||
|
||||
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 {
|
||||
case .String:
|
||||
return append_instruction(state, ir.Instruction{
|
||||
op=.String, span=expr.span, type=expr.type, integer=expr.integer,
|
||||
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
case .Array, .Struct:
|
||||
args := make([]ir.Instruction_Id, len(expr.args), state.allocator)
|
||||
for arg, index in expr.args {
|
||||
args[index] = lower_nested_expr(state, arg)
|
||||
}
|
||||
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,
|
||||
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
case .Optional_Some:
|
||||
value := lower_nested_expr(state, expr.left)
|
||||
return append_instruction(state, ir.Instruction{
|
||||
op=.Optional_Some, span=expr.span, type=expr.type,
|
||||
target=ir.INVALID_REF, a=value, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
case .Address:
|
||||
location := lower_location(state, expr.left, types.is_mutable(expr.type, &state.hir_module.types))
|
||||
if location != ir.INVALID_INSTRUCTION {
|
||||
return append_instruction(state, ir.Instruction{
|
||||
op=.Address_Of, span=expr.span, type=expr.type,
|
||||
target=ir.INVALID_REF, a=location, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
}
|
||||
return append_recovery_value(state, expr.span, expr.type, expr.diagnostic)
|
||||
case .Deref, .Index, .Field:
|
||||
location := lower_location(state, expr_id)
|
||||
if location == ir.INVALID_INSTRUCTION {
|
||||
return append_recovery_value(state, expr.span, expr.type, expr.diagnostic)
|
||||
}
|
||||
return append_instruction(state, ir.Instruction{
|
||||
op=.Load, span=expr.span, type=expr.type,
|
||||
target=ir.INVALID_REF, a=location, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
case .Slice:
|
||||
container := lower_nested_expr(state, expr.left)
|
||||
if types.is_array(state.hir_module.exprs[expr.left].type, &state.hir_module.types) {
|
||||
container = lower_location(state, expr.left)
|
||||
}
|
||||
args := make([]ir.Instruction_Id, len(expr.args), state.allocator)
|
||||
for arg, index in expr.args {
|
||||
args[index] = ir.INVALID_INSTRUCTION
|
||||
if arg != hir.INVALID_EXPR {
|
||||
args[index] = lower_nested_expr(state, arg)
|
||||
}
|
||||
}
|
||||
return append_instruction(state, ir.Instruction{
|
||||
op=.Slice, span=expr.span, type=expr.type, args=args,
|
||||
target=ir.INVALID_REF, a=container, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
case .Unwrap:
|
||||
value := lower_nested_expr(state, expr.left)
|
||||
return append_instruction(state, ir.Instruction{
|
||||
op=.Unwrap, span=expr.span, type=expr.type,
|
||||
target=ir.INVALID_REF, a=value, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
case .Length:
|
||||
container_type := state.hir_module.exprs[expr.left].type
|
||||
item, ok := types.node(&state.hir_module.types, container_type)
|
||||
if ok && item.kind == .Array {
|
||||
return append_instruction(state, ir.Instruction{
|
||||
op=.Const, span=expr.span, type=types.USIZE, integer=i64(item.count),
|
||||
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
}
|
||||
value := lower_nested_expr(state, expr.left)
|
||||
return append_instruction(state, ir.Instruction{
|
||||
op=.Length, span=expr.span, type=types.USIZE,
|
||||
target=ir.INVALID_REF, a=value, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
case .Slice_Ptr:
|
||||
container_type := state.hir_module.exprs[expr.left].type
|
||||
value := lower_nested_expr(state, expr.left)
|
||||
if types.is_array(container_type, &state.hir_module.types) {
|
||||
value = lower_location(state, expr.left)
|
||||
}
|
||||
return append_instruction(state, ir.Instruction{
|
||||
op=.Slice_Ptr, span=expr.span, type=expr.type,
|
||||
target=ir.INVALID_REF, a=value, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
case .Orelse:
|
||||
value := lower_nested_expr(state, expr.left)
|
||||
begin := append_instruction(state, ir.Instruction{
|
||||
op=.Orelse_Begin, span=expr.span, type=expr.type,
|
||||
target=ir.INVALID_REF, a=value, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
fallback := lower_nested_expr(state, expr.right)
|
||||
return append_instruction(state, ir.Instruction{
|
||||
op=.Orelse, span=expr.span, type=expr.type,
|
||||
target=ir.INVALID_REF, a=begin, b=fallback,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
}
|
||||
return append_recovery_value(state, expr.span, expr.type, expr.diagnostic)
|
||||
}
|
||||
|
||||
lower_expr :: proc(state: ^State, expr_id: hir.Expr_Id) -> ir.Instruction_Id {
|
||||
stack := state.expr_stack
|
||||
clear_dynamic_array(&stack)
|
||||
@@ -98,16 +283,20 @@ lower_expr :: proc(state: ^State, expr_id: hir.Expr_Id) -> ir.Instruction_Id {
|
||||
}
|
||||
expr := state.hir_module.exprs[frame.expr]
|
||||
if frame.stage == 0 {
|
||||
switch expr.kind {
|
||||
#partial switch expr.kind {
|
||||
case .Invalid:
|
||||
last = append_recovery_value(state, expr.span, expr.type, expr.diagnostic)
|
||||
_ = pop(&stack)
|
||||
case .Integer:
|
||||
case .Integer, .Float:
|
||||
last = append_instruction(state, ir.Instruction{
|
||||
op=.Const, span=expr.span, type=expr.type, integer=expr.integer,
|
||||
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,
|
||||
.Index, .Slice, .Field, .Length, .Slice_Ptr, .Unwrap, .Orelse:
|
||||
last = lower_compound_expr(state, frame.expr)
|
||||
_ = pop(&stack)
|
||||
case .Local:
|
||||
last = ir.INVALID_INSTRUCTION
|
||||
local := hir.as_local(expr.target)
|
||||
@@ -141,7 +330,7 @@ lower_expr :: proc(state: ^State, expr_id: hir.Expr_Id) -> ir.Instruction_Id {
|
||||
case .Negate:
|
||||
stack[frame_index].stage = 5
|
||||
append(&stack, Lower_Expr_Frame{expr=expr.left})
|
||||
case .Add:
|
||||
case .Add, .Pointer_Add:
|
||||
stack[frame_index].stage = 2
|
||||
append(&stack, Lower_Expr_Frame{expr=expr.left})
|
||||
case .Call:
|
||||
@@ -183,7 +372,8 @@ lower_expr :: proc(state: ^State, expr_id: hir.Expr_Id) -> ir.Instruction_Id {
|
||||
}
|
||||
if frame.stage == 3 {
|
||||
last = append_instruction(state, ir.Instruction{
|
||||
op=.Add_Checked, span=expr.span, type=expr.type, target=ir.INVALID_REF,
|
||||
op=.Pointer_Add if expr.kind == .Pointer_Add else .Add_Checked,
|
||||
span=expr.span, type=expr.type, target=ir.INVALID_REF,
|
||||
a=frame.left, b=last, diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
_ = pop(&stack)
|
||||
@@ -238,6 +428,20 @@ lower_body :: proc(hir_module: ^hir.Module, function: hir.Function, allocator: m
|
||||
})
|
||||
state.local_values[local_id] = param
|
||||
}
|
||||
for local_id in function.params {
|
||||
slot := append_instruction(&state, ir.Instruction{
|
||||
op=.Alloca, type=function.locals[local_id].type,
|
||||
target=ir.local_ref(ir.Local_Id(local_id)),
|
||||
a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
append_instruction(&state, ir.Instruction{
|
||||
op=.Store, type=function.locals[local_id].type,
|
||||
target=ir.INVALID_REF, a=slot, b=state.local_values[local_id],
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
state.local_slots[local_id] = slot
|
||||
}
|
||||
|
||||
for statement_id in function.body {
|
||||
statement := hir_module.statements[statement_id]
|
||||
@@ -252,36 +456,39 @@ lower_body :: proc(hir_module: ^hir.Module, function: hir.Function, allocator: m
|
||||
continue
|
||||
}
|
||||
local := function.locals[statement.local]
|
||||
if local.mutable {
|
||||
slot := append_instruction(&state, ir.Instruction{
|
||||
op=.Alloca,
|
||||
span=statement.span,
|
||||
type=local.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] = slot
|
||||
append_instruction(&state, ir.Instruction{
|
||||
op=.Store,
|
||||
span=statement.span,
|
||||
type=local.type,
|
||||
target=ir.INVALID_REF,
|
||||
a=slot,
|
||||
b=value,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
} else {
|
||||
state.local_values[statement.local] = value
|
||||
}
|
||||
slot := append_instruction(&state, ir.Instruction{
|
||||
op=.Alloca,
|
||||
span=statement.span,
|
||||
type=local.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] = slot
|
||||
append_instruction(&state, ir.Instruction{
|
||||
op=.Store,
|
||||
span=statement.span,
|
||||
type=local.type,
|
||||
target=ir.INVALID_REF,
|
||||
a=slot,
|
||||
b=value,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
case .Assignment:
|
||||
value := lower_expr(&state, statement.expr)
|
||||
slot := ir.INVALID_INSTRUCTION
|
||||
if statement.local != hir.INVALID_LOCAL && int(statement.local) < len(state.local_slots) {
|
||||
value_type := types.INVALID
|
||||
if statement.target != hir.INVALID_EXPR {
|
||||
slot = lower_location(&state, statement.target, true)
|
||||
if int(statement.target) < len(hir_module.exprs) {
|
||||
value_type = hir_module.exprs[statement.target].type
|
||||
}
|
||||
} else if statement.local != hir.INVALID_LOCAL && int(statement.local) < len(state.local_slots) {
|
||||
slot = state.local_slots[statement.local]
|
||||
value_type = function.locals[statement.local].type
|
||||
}
|
||||
if slot == ir.INVALID_INSTRUCTION || statement.local == hir.INVALID_LOCAL || int(statement.local) >= len(function.locals) {
|
||||
if slot == ir.INVALID_INSTRUCTION || !types.is_valid(value_type) {
|
||||
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,
|
||||
@@ -291,7 +498,7 @@ lower_body :: proc(hir_module: ^hir.Module, function: hir.Function, allocator: m
|
||||
append_instruction(&state, ir.Instruction{
|
||||
op=.Store,
|
||||
span=statement.span,
|
||||
type=function.locals[statement.local].type,
|
||||
type=value_type,
|
||||
target=ir.INVALID_REF,
|
||||
a=slot,
|
||||
b=value,
|
||||
@@ -337,13 +544,13 @@ lower_body :: proc(hir_module: ^hir.Module, function: hir.Function, allocator: m
|
||||
if len(state.instructions) == 0 ||
|
||||
(state.instructions[len(state.instructions)-1].op != .Return &&
|
||||
state.instructions[len(state.instructions)-1].op != .Return_Void) {
|
||||
if function.result.kind == .Void {
|
||||
if types.is_void(function.result) {
|
||||
append_instruction(&state, ir.Instruction{op=.Return_Void, type=types.VOID, target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION, diagnostic=source.INVALID_DIAGNOSTIC})
|
||||
} else {
|
||||
value := append_instruction(&state, ir.Instruction{
|
||||
op=.Const,
|
||||
type=function.result,
|
||||
integer=sentinel(function.result),
|
||||
integer=sentinel(function.result, hir_module.target),
|
||||
target=ir.INVALID_REF,
|
||||
a=ir.INVALID_INSTRUCTION,
|
||||
b=ir.INVALID_INSTRUCTION,
|
||||
@@ -373,7 +580,12 @@ lower_global_initializer :: proc(hir_module: ^hir.Module, global: hir.Global, al
|
||||
}
|
||||
|
||||
lower :: proc(hir_module: ^hir.Module, allocator := context.allocator) -> ir.Module {
|
||||
module := ir.init_module(allocator)
|
||||
module := ir.init_module(hir_module.target, allocator)
|
||||
types.destroy_store(&module.types)
|
||||
module.types = types.clone_store(&hir_module.types, allocator)
|
||||
for value in hir_module.strings {
|
||||
append(&module.strings, fmt.aprintf("%s", value, allocator=allocator))
|
||||
}
|
||||
for global in hir_module.globals {
|
||||
_ = ir.global_id(len(module.globals))
|
||||
append(&module.globals, ir.Global{
|
||||
|
||||
Reference in New Issue
Block a user