205 lines
4.4 KiB
Odin
205 lines
4.4 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,
|
|
Load,
|
|
Store,
|
|
Slice,
|
|
Length,
|
|
Slice_Ptr,
|
|
Unwrap,
|
|
Optional_Is_Some,
|
|
Optional_Value,
|
|
Orelse_Begin,
|
|
Orelse,
|
|
Widen,
|
|
C_Vararg_Promote,
|
|
Weaken_Pointer,
|
|
Weaken_Slice,
|
|
Decay_Array_Pointer,
|
|
Neg_Checked,
|
|
Add_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)
|
|
}
|