Files
brolang/compiler/ir/ir.odin
T
2026-06-30 20:40:40 +02:00

216 lines
4.5 KiB
Odin

package ir
import "../source"
import "../symbol"
import "../target"
import "../types"
import "core:mem"
Instruction_Id :: distinct u32
Local_Id :: distinct u32
Function_Id :: distinct u32
Global_Id :: distinct u32
Ref :: distinct u32
INVALID_INSTRUCTION :: Instruction_Id(0xffff_ffff)
INVALID_LOCAL :: Local_Id(0xffff_ffff)
INVALID_FUNCTION :: Function_Id(0xffff_ffff)
INVALID_GLOBAL :: Global_Id(0xffff_ffff)
INVALID_REF :: Ref(0xffff_ffff)
instruction_id :: proc(index: int) -> Instruction_Id {
assert(index >= 0 && u64(index) < u64(INVALID_INSTRUCTION))
return Instruction_Id(index)
}
local_id :: proc(index: int) -> Local_Id {
assert(index >= 0 && u64(index) < u64(INVALID_LOCAL))
return Local_Id(index)
}
function_id :: proc(index: int) -> Function_Id {
assert(index >= 0 && u64(index) < u64(INVALID_FUNCTION))
return Function_Id(index)
}
global_id :: proc(index: int) -> Global_Id {
assert(index >= 0 && u64(index) < u64(INVALID_GLOBAL))
return Global_Id(index)
}
index :: proc(id: $T, invalid: T, count: int) -> (int, bool) {
value := int(id)
return value, id != invalid && value < count
}
local_ref :: proc(id: Local_Id) -> Ref {return Ref(id)}
function_ref :: proc(id: Function_Id) -> Ref {return Ref(id)}
global_ref :: proc(id: Global_Id) -> Ref {return Ref(id)}
as_local :: proc(ref: Ref) -> Local_Id {return Local_Id(ref)}
as_function :: proc(ref: Ref) -> Function_Id {return Function_Id(ref)}
as_global :: proc(ref: Ref) -> Global_Id {return Global_Id(ref)}
Calling_Convention :: enum u8 {
Brolang,
C,
}
Implementation :: enum u8 {
Definition,
Declaration,
}
Linkage :: enum u8 {
Internal,
External,
}
Opcode :: enum u8 {
Param,
Const,
String,
Aggregate,
None,
Optional_Some,
Load_Global,
Function_Address,
Address_Global,
Address_Of,
Alloca,
Index_Address,
Field_Address,
Union_Tag,
Fallible_Error,
Load,
Store,
Fill,
Slice,
Length,
Slice_Ptr,
Extract,
Select,
Unwrap,
Optional_Is_Some,
Optional_Value,
Orelse_Begin,
Orelse,
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,
Label,
Br,
Cond_Br,
Call,
Trap,
Return,
Return_Void,
}
// Compare_Predicate is stored in Instruction.integer for the Compare opcode.
Compare_Predicate :: enum u8 {
Eq,
Ne,
Lt,
Le,
Gt,
Ge,
}
Instruction :: struct {
span: source.Span,
type: types.Type,
integer: i64,
args: []Instruction_Id,
target: Ref,
a: Instruction_Id,
b: Instruction_Id,
diagnostic: source.Diagnostic_Id,
op: Opcode,
}
Function :: struct {
link_name: string,
calling_convention: Calling_Convention,
implementation: Implementation,
linkage: Linkage,
is_main: bool,
variadic: bool,
param_types: []types.Type,
result: types.Type,
instructions: []Instruction,
problematic: bool,
}
Global :: struct {
name: symbol.Id,
link_name: string,
type: types.Type,
is_static: bool,
external: bool,
writable: bool,
static_value: i64,
initializer: []Instruction,
problematic: bool,
diagnostic: source.Diagnostic_Id,
}
Module :: struct {
functions: [dynamic]Function,
globals: [dynamic]Global,
strings: [dynamic]string,
types: types.Store,
target: target.Target,
allocator: mem.Allocator,
}
init_module :: proc(selected := target.DEFAULT, allocator := context.allocator) -> Module {
module: Module
module.target = selected
module.types = types.init_store(allocator)
module.types.selected = selected
module.functions.allocator = allocator
module.globals.allocator = allocator
module.strings.allocator = allocator
module.allocator = allocator
return module
}
destroy_instructions :: proc(instructions: []Instruction, allocator: mem.Allocator) {
for instruction in instructions {
delete(instruction.args, allocator)
}
delete(instructions, allocator)
}
destroy_module :: proc(module: ^Module) {
for function in module.functions {
delete(function.link_name, module.allocator)
delete(function.param_types, module.allocator)
destroy_instructions(function.instructions, module.allocator)
}
for global in module.globals {
delete(global.link_name, module.allocator)
destroy_instructions(global.initializer, module.allocator)
}
for value in module.strings {
delete(value, module.allocator)
}
delete(module.functions)
delete(module.globals)
delete(module.strings)
types.destroy_store(&module.types)
}