import "!hashmap.pry"; import "llvm.pry"; let Variable = struct { value: LLVMValueRef, type: LLVMTypeRef, node: *Node, node_type: *Node, stack_level: *i64, }; let Scope = struct { variables: *HashMap, }; let Environment = struct { scope_stack: **Scope, scope_stack_len: i64, arena: *arena, }; let environment_create_scope = (e: *Environment) => void { let scope = cast(*Scope, arena_alloc((*e).arena, sizeof(Scope))); (*scope).variables = hashmap_init(16, (*e).arena); (*((*e).scope_stack + cast(**Scope, (*e).scope_stack_len))) = scope; (*e).scope_stack_len = (*e).scope_stack_len + 1; return; }; let environment_drop_scope = (e: *Environment) => void { (*e).scope_stack_len = (*e).scope_stack_len - 1; return; }; let environment_get_variable = (e: *Environment, name: *i8) => *Variable { let i = (*e).scope_stack_len; let variable = cast(*Variable, null); while i > 0 { i = i - 1; let scope = *(((*e).scope_stack + cast(**Scope, i))); assert(scope != cast(*Scope, null)); let v = cast(*Variable, hashmap_get((*scope).variables, name)); if v != cast(*Variable, null) { if variable == cast(*Variable, null) { variable = v; }; let stack_level = cast(*i64, arena_alloc((*e).arena, sizeof(i64))); (*stack_level) = i; (*variable).stack_level = stack_level; }; }; return variable; }; let environment_add_variable = (e: *Environment, name: *i8, variable: *Variable) => void { let top_scope = *(((*e).scope_stack + cast(**Scope, (*e).scope_stack_len - 1))); hashmap_put((*top_scope).variables, name, cast(*void, variable)); return; }; let environment_set_variable = (e: *Environment, name: *i8, variable: *Variable) => void { let existing = environment_get_variable(e, name); (*existing) = (*variable); return; }; let environment_init = (alloc: *arena) => *Environment { let e = cast(*Environment, arena_alloc(alloc, sizeof(Environment))); (*e).scope_stack = cast(**Scope, arena_alloc(alloc, sizeof(*Scope) * 40)); (*e).scope_stack_len = 0; (*e).arena = alloc; environment_create_scope(e); return e; }; let codegen = struct { llvm_module: LLVMModuleRef, llvm_context: LLVMContextRef, builder: LLVMBuilderRef, arena: *arena, environment: *Environment, whil_loop_exit: LLVMBasicBlockRef, whil_block: LLVMBasicBlockRef, current_function: LLVMValueRef, current_function_retur_type: *Node, llvm_target_data: LLVMTargetDataRef, }; let codegen_init = (alloc: *arena) => *codegen { LLVMInitializeAllTargetInfos(); LLVMInitializeAllTargetMCs(); LLVMInitializeAllTargets(); LLVMInitializeAllAsmPrinters(); LLVMInitializeAllAsmParsers(); let module = LLVMModuleCreateWithName("module"); let context = LLVMGetGlobalContext(); let builder = LLVMCreateBuilder(); let c = cast(*codegen, arena_alloc(alloc, sizeof(codegen))); (*c).llvm_module = module; (*c).llvm_target_data = LLVMGetModuleDataLayout(module); (*c).llvm_context = context; (*c).builder = builder; (*c).arena = alloc; (*c).environment = environment_init(alloc); return c; }; let create_node = (c: *codegen, n: Node) => *Node { let res = cast(*Node, arena_alloc((*c).arena, sizeof(Node))); *res = n; return res; }; let codegen_create_variable = (c: *codegen, variable: Variable) => *Variable { let v = cast(*Variable, arena_alloc((*c).arena, sizeof(Variable))); *v = variable; return v; }; let codegen_get_llvm_type = (c: *codegen, node: *Node) => *LLVMTypeRef { assert((*node).type >= NODE_TYPE_SIMPLE_TYPE); assert((*node).type <= NODE_TYPE_STRUCT_TYPE); if (*node).type == NODE_TYPE_SIMPLE_TYPE { let simple_type = *cast(*NODE_TYPE_SIMPLE_TYPE_DATA, (*node).data); if strcmp(simple_type.name, "i8") { let r = cast(*LLVMTypeRef, arena_alloc((*c).arena, sizeof(LLVMTypeRef))); *r = LLVMInt8Type(); return r; }; if strcmp(simple_type.name, "i64") { let r = cast(*LLVMTypeRef, arena_alloc((*c).arena, sizeof(LLVMTypeRef))); *r = LLVMInt64Type(); return r; }; if strcmp(simple_type.name, "bool") { let r = cast(*LLVMTypeRef, arena_alloc((*c).arena, sizeof(LLVMTypeRef))); *r = LLVMInt1Type(); return r; }; if strcmp(simple_type.name, "void") { let r = cast(*LLVMTypeRef, arena_alloc((*c).arena, sizeof(LLVMTypeRef))); *r = LLVMVoidType(); return r; }; if strcmp(simple_type.name, "varargs") { /* Hack for varargs (only used for printf) */ let r = cast(*LLVMTypeRef, arena_alloc((*c).arena, sizeof(LLVMTypeRef))); *r = LLVMPointerType(LLVMInt64Type(), 0); return r; }; let v = environment_get_variable((*c).environment, simple_type.name); if (v != cast(*Variable, null)) { assert((*v).type != cast(LLVMTypeRef, null)); let r = cast(*LLVMTypeRef, arena_alloc((*c).arena, sizeof(LLVMTypeRef))); *r = (*v).type; return r; }; printf("NO SIMPLE TYPE %s!\n", simple_type.name); assert(false); }; if (*node).type == NODE_TYPE_FUNCTION_TYPE { let function_type = *cast(*NODE_TYPE_FUNCTION_TYPE_DATA, (*node).data); let f_retur = function_type.retur_type; let retur_type = codegen_get_llvm_type(c, f_retur); assert(retur_type != cast(*LLVMTypeRef, null)); if (*f_retur).type == NODE_TYPE_FUNCTION_TYPE { (*retur_type) = LLVMPointerType(*retur_type, 0); }; let paramtypes = cast(*LLVMTypeRef, arena_alloc((*c).arena, sizeof(LLVMTypeRef) * 20)); let paramtypes_len = 0; let is_varargs = 0; let i = 0; while i < function_type.parameters_len { let param = *(function_type.parameters + cast(**Node, i)); if (*param).type == NODE_TYPE_SIMPLE_TYPE { let simple_type = *cast(*NODE_TYPE_SIMPLE_TYPE_DATA, (*param).data); if strcmp(simple_type.name, "varargs") { is_varargs = 1; i = i + 1; continue; }; }; let typ = codegen_get_llvm_type(c, param); assert(typ != cast(*LLVMTypeRef, null)); if (*param).type == NODE_TYPE_FUNCTION_TYPE { *typ = LLVMPointerType(*typ, 0); }; (*(paramtypes + cast(*LLVMTypeRef, paramtypes_len))) = *typ; paramtypes_len = paramtypes_len + 1; i = i + 1; }; let function_type = LLVMFunctionType(*retur_type, paramtypes, paramtypes_len, is_varargs); let r = cast(*LLVMTypeRef, arena_alloc((*c).arena, sizeof(LLVMTypeRef))); *r = function_type; return r; }; if (*node).type == NODE_TYPE_POINTER_TYPE { let pointer_type = *cast(*NODE_TYPE_POINTER_TYPE_DATA, (*node).data); let inner_type = codegen_get_llvm_type(c, pointer_type.type); assert(inner_type != cast(*LLVMTypeRef, null)); let r = cast(*LLVMTypeRef, arena_alloc((*c).arena, sizeof(LLVMTypeRef))); *r = LLVMPointerType(*inner_type, 0); return r; }; printf("NO TYPEEE BOI %d\n", (*node).type); assert(false); return cast(*LLVMTypeRef, null); }; let codegen_generate_literal = (c: *codegen, literal_val: LLVMValueRef, name: *i8, node: *Node, node_type: *Node) => *Variable { if name != cast(*i8, null) { let e = (*c).environment; if (*e).scope_stack_len == 1 { let lt = codegen_get_llvm_type(c, node_type); assert(lt != cast(*LLVMTypeRef, null)); let v = Variable{}; v.value = LLVMAddGlobal((*c).llvm_module, *lt, name); v.type = cast(LLVMTypeRef, null); v.stack_level = cast(*i64, null); v.node = node; v.node_type = node_type; LLVMSetInitializer(v.value, literal_val); return codegen_create_variable(c, v); }; }; let v = Variable{}; v.value = literal_val; v.type = cast(LLVMTypeRef, null); v.stack_level = cast(*i64, null); v.node = node; v.node_type = node_type; return codegen_create_variable(c, v); }; extern codegen_generate_statement = (*codegen, *Node) => i64; extern codegen_generate_function_call_statement = (*codegen, *Node) => *Variable; extern codegen_generate_expression_value = (*codegen, *Node, *i8) => *Variable; let StructField = struct { value: LLVMValueRef, type: *Node, }; let codegen_get_struct_field = (c: *codegen, node: *Node, name: *i8) => *StructField { let ptr = cast(*Variable, null); if (*node).type == NODE_PRIMARY_EXPRESSION_IDENTIFIER { let identifier = *cast(*NODE_PRIMARY_EXPRESSION_IDENTIFIER_DATA, (*node).data); ptr = environment_get_variable((*c).environment, identifier.name); }; if (*node).type == NODE_UNARY_EXPRESSION { let xd = (*cast(*NODE_UNARY_EXPRESSION_DATA, (*node).data)).expression; ptr = codegen_generate_expression_value(c, xd, ""); }; assert(ptr != cast(*Variable, null)); let typ = cast(*Node, null); let ptr_typ = (*ptr).node_type; if (*ptr_typ).type == NODE_TYPE_STRUCT_TYPE { typ = ptr_typ; }; if (*ptr_typ).type == NODE_TYPE_POINTER_TYPE { let pt = *cast(*NODE_TYPE_POINTER_TYPE_DATA, (*ptr_typ).data); let pt_type = pt.type; assert((*pt_type).type == NODE_TYPE_SIMPLE_TYPE); let simple_type = *cast(*NODE_TYPE_SIMPLE_TYPE_DATA, (*pt_type).data); let v = environment_get_variable((*c).environment, simple_type.name); assert(v != cast(*Variable, null)); typ = (*v).node_type; }; if (*ptr_typ).type == NODE_TYPE_SIMPLE_TYPE { let simple_type = *cast(*NODE_TYPE_SIMPLE_TYPE_DATA, (*ptr_typ).data); let v = environment_get_variable((*c).environment, simple_type.name); assert(v != cast(*Variable, null)); typ = (*v).node_type; }; assert(typ != cast(*Node, null)); assert((*typ).type == NODE_TYPE_SIMPLE_TYPE); let simple_type = *cast(*NODE_TYPE_SIMPLE_TYPE_DATA, (*typ).data); assert((*simple_type.underlying_type).type == NODE_TYPE_STRUCT_TYPE); let struc_type = *cast(*NODE_TYPE_STRUCT_TYPE_DATA, (*simple_type.underlying_type).data); let fieldIndex = cast(*i64, null); let i = 0; while i < struc_type.fields_len { let field = *(struc_type.fields + cast(**Node, i)); assert((*field).type == NODE_PRIMARY_EXPRESSION_IDENTIFIER); let field_data = *cast(*NODE_PRIMARY_EXPRESSION_IDENTIFIER_DATA, (*field).data); if strcmp(name, field_data.name) { let ii = cast(*i64, arena_alloc((*c).arena, sizeof(i64))); *ii = i; fieldIndex = ii; break; }; i = i + 1; }; assert(fieldIndex != cast(*i64, null)); let zero = LLVMConstInt(LLVMInt32Type(), 0, 0); let llvmFieldIndex = LLVMConstInt(LLVMInt32Type(), *fieldIndex, 0); let indices = cast(*LLVMValueRef, arena_alloc((*c).arena, sizeof(LLVMValueRef) * 2)); (*(indices + cast(*LLVMValueRef, 0))) = zero; (*(indices + cast(*LLVMValueRef, 1))) = llvmFieldIndex; let res = cast(*StructField, arena_alloc((*c).arena, sizeof(StructField))); let x = codegen_get_llvm_type(c, typ); assert(x != cast(*LLVMTypeRef, null)); (*res).value = LLVMBuildGEP2((*c).builder, *x, (*ptr).value, indices, 2, name); let no = *(struc_type.fields + cast(**Node, *fieldIndex)); assert((*no).type == NODE_PRIMARY_EXPRESSION_IDENTIFIER); let no_d = *cast(*NODE_PRIMARY_EXPRESSION_IDENTIFIER_DATA, (*no).data); (*res).type = no_d.type; return res; }; let codegen_generate_expression_value = (c: *codegen, expression: *Node, name: *i8) => *Variable { printf("NAME %d: \n", (*expression).type); if ((*expression).type == NODE_PRIMARY_EXPRESSION_NULL) { let inner_type_data = cast(*NODE_TYPE_SIMPLE_TYPE_DATA, arena_alloc((*c).arena, sizeof(NODE_TYPE_SIMPLE_TYPE_DATA))); (*inner_type_data).name = "void"; let inner_type = Node{}; inner_type.type = NODE_TYPE_SIMPLE_TYPE; inner_type.data = cast(*void, inner_type_data); let node_type_data = cast(*NODE_TYPE_POINTER_TYPE_DATA, arena_alloc((*c).arena, sizeof(NODE_TYPE_POINTER_TYPE_DATA))); (*node_type_data).type = create_node(c, inner_type); let node_type = Node{}; node_type.type = NODE_TYPE_POINTER_TYPE; node_type.data = cast(*void, node_type_data); return codegen_generate_literal(c, LLVMConstNull(LLVMPointerType(LLVMInt8Type(), 0)), name, expression, create_node(c, node_type)); }; if ((*expression).type == NODE_PRIMARY_EXPRESSION_NUMBER) { let n = (*cast(*NODE_PRIMARY_EXPRESSION_NUMBER_DATA, (*expression).data)).value; let node_type = Node{}; node_type.type = NODE_TYPE_SIMPLE_TYPE; let d = cast(*NODE_TYPE_SIMPLE_TYPE_DATA, arena_alloc((*c).arena, sizeof(NODE_TYPE_SIMPLE_TYPE_DATA))); (*d).name = "i64"; (*d).underlying_type = cast(*Node, null); node_type.data = cast(*void, d); return codegen_generate_literal(c, LLVMConstInt(LLVMInt64Type(), n, 0), name, expression, create_node(c, node_type)); }; if ((*expression).type == NODE_PRIMARY_EXPRESSION_BOOLEAN) { let b = (*cast(*NODE_PRIMARY_EXPRESSION_BOOLEAN_DATA, (*expression).data)).value; let node_type = Node{}; node_type.type = NODE_TYPE_SIMPLE_TYPE; let d = cast(*NODE_TYPE_SIMPLE_TYPE_DATA, arena_alloc((*c).arena, sizeof(NODE_TYPE_SIMPLE_TYPE_DATA))); (*d).name = "bool"; (*d).underlying_type = cast(*Node, null); node_type.data = cast(*void, d); let int_value = 0; if b == true { int_value = 1; }; return codegen_generate_literal(c, LLVMConstInt(LLVMInt1Type(), int_value, 0), name, expression, create_node(c, node_type)); }; if ((*expression).type == NODE_PRIMARY_EXPRESSION_CHAR) { let ch = cast(i64, (*cast(*NODE_PRIMARY_EXPRESSION_CHAR_DATA, (*expression).data)).value); let node_type = Node{}; node_type.type = NODE_TYPE_SIMPLE_TYPE; let d = cast(*NODE_TYPE_SIMPLE_TYPE_DATA, arena_alloc((*c).arena, sizeof(NODE_TYPE_SIMPLE_TYPE_DATA))); (*d).name = "i8"; (*d).underlying_type = cast(*Node, null); node_type.data = cast(*void, d); return codegen_generate_literal(c, LLVMConstInt(LLVMInt8Type(), cast(i64, ch), 0), name, expression, create_node(c, node_type)); }; if ((*expression).type == NODE_PRIMARY_EXPRESSION_STRING) { let str = (*cast(*NODE_PRIMARY_EXPRESSION_STRING_DATA, (*expression).data)).value; let x = LLVMBuildGlobalStringPtr((*c).builder, str, ""); let inner_type_data = cast(*NODE_TYPE_SIMPLE_TYPE_DATA, arena_alloc((*c).arena, sizeof(NODE_TYPE_SIMPLE_TYPE_DATA))); (*inner_type_data).name = "i8"; let inner_type = Node{}; inner_type.type = NODE_TYPE_SIMPLE_TYPE; inner_type.data = cast(*void, inner_type_data); let node_type_data = cast(*NODE_TYPE_POINTER_TYPE_DATA, arena_alloc((*c).arena, sizeof(NODE_TYPE_POINTER_TYPE_DATA))); (*node_type_data).type = create_node(c, inner_type); let node_type = Node{}; node_type.type = NODE_TYPE_POINTER_TYPE; node_type.data = cast(*void, node_type_data); let v = Variable{}; v.value = x; v.type = cast(LLVMTypeRef, null); v.stack_level = cast(*i64, null); v.node = expression; v.node_type = create_node(c, node_type); return codegen_create_variable(c, v); }; if ((*expression).type == NODE_PRIMARY_EXPRESSION_IDENTIFIER) { let identifier = *cast(*NODE_PRIMARY_EXPRESSION_IDENTIFIER_DATA, (*expression).data); let variable = environment_get_variable((*c).environment, identifier.name); assert(variable != cast(*Variable, null)); let param_value = (*variable).value; let v_type = (*variable).node_type; let done = false; if (*v_type).type != NODE_TYPE_FUNCTION_TYPE { let param_type = codegen_get_llvm_type(c, v_type); assert(param_type != cast(*LLVMTypeRef, null)); if (*v_type).type == NODE_TYPE_FUNCTION_TYPE { (*param_type) = LLVMPointerType(*param_type, 0); }; param_value = LLVMBuildLoad2((*c).builder, *param_type, (*variable).value, ""); done = true; }; if !done { if (*(*variable).stack_level) != 0 { let param_type = codegen_get_llvm_type(c, v_type); assert(param_type != cast(*LLVMTypeRef, null)); if (*v_type).type == NODE_TYPE_FUNCTION_TYPE { (*param_type) = LLVMPointerType(*param_type, 0); }; param_value = LLVMBuildLoad2((*c).builder, *param_type, (*variable).value, ""); done = true; }; }; return codegen_generate_literal(c, param_value, name, expression, (*variable).node_type); }; if ((*expression).type == NODE_FUNCTION_DEFINITION) { /* Functions should be declared "globally" */ let builder_pos = LLVMGetInsertBlock((*c).builder); let llvm_param_types = cast(*LLVMTypeRef, arena_alloc((*c).arena, sizeof(LLVMTypeRef) * 20)); let param_types = cast(**Node, arena_alloc((*c).arena, sizeof(*Node) * 20)); let function_definition = *cast(*NODE_FUNCTION_DEFINITION_DATA, (*expression).data); let i = 0; let is_varargs = 0; while i < function_definition.parameters_len { let node = *(function_definition.parameters + cast(**Node, i)); assert((*node).type == NODE_PRIMARY_EXPRESSION_IDENTIFIER); let param = *cast(*NODE_PRIMARY_EXPRESSION_IDENTIFIER_DATA, (*node).data); let param_type = param.type; if (*param_type).type == NODE_TYPE_SIMPLE_TYPE { let simple_type = *(cast(*NODE_TYPE_SIMPLE_TYPE_DATA, (*param_type).data)); if strcmp(simple_type.name, "varargs") { is_varargs = 1; }; }; let llvm_param_type = codegen_get_llvm_type(c, param_type); assert(llvm_param_type != cast(*LLVMTypeRef, null)); if (*param_type).type == NODE_TYPE_FUNCTION_TYPE { (*llvm_param_type) = LLVMPointerType(*llvm_param_type, 0); }; (*(llvm_param_types + cast(*LLVMTypeRef, i))) = *llvm_param_type; (*(param_types + cast(**Node, i))) = param_type; i = i + 1; }; let f_ret = function_definition.retur_type; let retur_type = codegen_get_llvm_type(c, f_ret); assert(retur_type != cast(*LLVMTypeRef, null)); if (*f_ret).type == NODE_TYPE_FUNCTION_TYPE { (*retur_type) = LLVMPointerType(*retur_type, 0); }; let function = cast(LLVMValueRef, null); if name != cast(*i8, null) { let v = environment_get_variable((*c).environment, name); if (v != cast(*Variable, null)) { function = (*v).value; }; }; if function == cast(LLVMValueRef, null) { let function_type = LLVMFunctionType(*retur_type, llvm_param_types, i, is_varargs); let n_name = name; if name == cast(*i8, null) { n_name = "unnamed_func"; }; function = LLVMAddFunction((*c).llvm_module, n_name, function_type); }; let function_entry = LLVMAppendBasicBlock(function, "entrypoint"); LLVMPositionBuilderAtEnd((*c).builder, function_entry); environment_create_scope((*c).environment); let last_function = (*c).current_function; (*c).current_function = function; let last_function_retur_type = (*c).current_function_retur_type; (*c).current_function_retur_type = function_definition.retur_type; /* TODO: Defer. For now we do at the end */ let d = cast(*NODE_TYPE_FUNCTION_TYPE_DATA, arena_alloc((*c).arena, sizeof(NODE_TYPE_FUNCTION_TYPE_DATA))); (*d).parameters = param_types; (*d).parameters_len = i; (*d).retur_type = function_definition.retur_type; let n = Node{}; let node_type = create_node(c, n); (*node_type).type = NODE_TYPE_FUNCTION_TYPE; (*node_type).data = cast(*void, d); /* Needed for recursive functions */ if name != cast(*i8, null) { let v = Variable{}; v.value = function; v.type = cast(LLVMTypeRef, null); v.stack_level = cast(*i64, null); v.node = expression; v.node_type = node_type; environment_add_variable((*c).environment, name, codegen_create_variable(c, v)); }; let params = cast(*LLVMValueRef, arena_alloc((*c).arena, sizeof(LLVMValueRef) * function_definition.parameters_len)); LLVMGetParams(function, params); let parameters_index = 0; while parameters_index < function_definition.parameters_len { let p = (*(params + cast(*LLVMValueRef, parameters_index))); let param_node = *(function_definition.parameters + cast(**Node, parameters_index)); assert((*param_node).type == NODE_PRIMARY_EXPRESSION_IDENTIFIER); let param = *cast(*NODE_PRIMARY_EXPRESSION_IDENTIFIER_DATA, (*param_node).data); let param_type = param.type; let llvm_param_type = codegen_get_llvm_type(c, param_type); assert(llvm_param_type != cast(*LLVMTypeRef, null)); if (*param_type).type == NODE_TYPE_FUNCTION_TYPE { (*llvm_param_type) = LLVMPointerType(*llvm_param_type, 0); }; let alloca = LLVMBuildAlloca((*c).builder, *llvm_param_type, param.name); LLVMBuildStore((*c).builder, p, alloca); let v = Variable{}; v.value = alloca; v.type = cast(LLVMTypeRef, null); v.stack_level = cast(*i64, null); v.node = param_node; v.node_type = param_type; environment_add_variable((*c).environment, param.name, codegen_create_variable(c, v)); parameters_index = parameters_index + 1; }; i = 0; while i < function_definition.statements_len { let stmt = *(function_definition.statements + cast(**Node, i)); let res = codegen_generate_statement(c, stmt); assert(res == 0); i = i + 1; }; LLVMPositionBuilderAtEnd((*c).builder, builder_pos); let v = Variable{}; v.value = function; v.type = cast(LLVMTypeRef, null); v.stack_level = cast(*i64, null); v.node = expression; v.node_type = node_type; /* TODO: Move to defer */ (*c).current_function = last_function; environment_drop_scope((*c).environment); return codegen_create_variable(c, v); }; if ((*expression).type == NODE_EQUALITY_EXPRESSION) { let exp = (*(cast(*NODE_EQUALITY_EXPRESSION_DATA, (*expression).data))); let lhs_value = codegen_generate_expression_value(c, exp.lhs, cast(*i8, null)); assert(lhs_value != cast(*Variable, null)); let rhs_value = codegen_generate_expression_value(c, exp.rhs, cast(*i8, null)); assert(rhs_value != cast(*Variable, null)); /* TODO: compare types */ let op = -1; if exp.typ == EQUALITY_EXPRESSION_TYPE_EQ { op = LLVMIntEQ; }; if exp.typ == EQUALITY_EXPRESSION_TYPE_NE { op = LLVMIntNE; }; if exp.typ == EQUALITY_EXPRESSION_TYPE_GE { op = LLVMIntSGE; }; if exp.typ == EQUALITY_EXPRESSION_TYPE_LE { op = LLVMIntSLE; }; if exp.typ == EQUALITY_EXPRESSION_TYPE_LT { op = LLVMIntSLT; }; if exp.typ == EQUALITY_EXPRESSION_TYPE_GT { op = LLVMIntSGT; }; assert(op != -1); let cmp = LLVMBuildICmp((*c).builder, cast(LLVMIntPredicate, op), (*lhs_value).value, (*rhs_value).value, ""); let node_type = Node{}; node_type.type = NODE_TYPE_SIMPLE_TYPE; let d = cast(*NODE_TYPE_SIMPLE_TYPE_DATA, arena_alloc((*c).arena, sizeof(NODE_TYPE_SIMPLE_TYPE_DATA))); (*d).name = "bool"; (*d).underlying_type = cast(*Node, null); node_type.data = cast(*void, d); return codegen_generate_literal(c, cmp, name, expression, create_node(c, node_type)); }; if ((*expression).type == NODE_ADDITIVE_EXPRESSION) { let exp = (*(cast(*NODE_ADDITIVE_EXPRESSION_DATA, (*expression).data))); let lhs_value = codegen_generate_expression_value(c, exp.lhs, cast(*i8, null)); assert(lhs_value != cast(*Variable, null)); let rhs_value = codegen_generate_expression_value(c, exp.rhs, cast(*i8, null)); assert(rhs_value != cast(*Variable, null)); /* TODO: Compare types */ let result = cast(LLVMValueRef, null); let node_type = Node{}; node_type.type = NODE_TYPE_SIMPLE_TYPE; let d = cast(*NODE_TYPE_SIMPLE_TYPE_DATA, arena_alloc((*c).arena, sizeof(NODE_TYPE_SIMPLE_TYPE_DATA))); (*d).name = "i64"; (*d).underlying_type = cast(*Node, null); node_type.data = cast(*void, d); let pnode_type = create_node(c, node_type); if exp.addition { let nt = (*lhs_value).node_type; if (*nt).type == NODE_TYPE_POINTER_TYPE { let ipt = cast(*NODE_TYPE_POINTER_TYPE_DATA, (*nt).data); let llvmipt = codegen_get_llvm_type(c, (*ipt).type); assert(llvmipt != cast(*LLVMTypeRef, null)); let arr = cast(*LLVMValueRef, arena_alloc((*c).arena, sizeof(LLVMValueRef) * 1)); (*(arr + cast(*LLVMValueRef, 0))) = (*rhs_value).value; result = LLVMBuildGEP2((*c).builder, *llvmipt, (*lhs_value).value, arr, 1, ""); pnode_type = (*lhs_value).node_type; }; if (*nt).type != NODE_TYPE_POINTER_TYPE { result = LLVMBuildAdd((*c).builder, (*lhs_value).value, (*rhs_value).value, ""); }; }; if !exp.addition { result = LLVMBuildSub((*c).builder, (*lhs_value).value, (*rhs_value).value, ""); }; return codegen_generate_literal(c, result, name, expression, pnode_type); }; if ((*expression).type == NODE_MULTIPLICATIVE_EXPRESSION) { let exp = (*(cast(*NODE_MULTIPLICATIVE_EXPRESSION_DATA, (*expression).data))); let lhs_value = codegen_generate_expression_value(c, exp.lhs, cast(*i8, null)); assert(lhs_value != cast(*Variable, null)); let rhs_value = codegen_generate_expression_value(c, exp.rhs, cast(*i8, null)); assert(rhs_value != cast(*Variable, null)); /* TODO: Compare types */ let result = cast(LLVMValueRef, null); if exp.typ == MULTIPLICATIVE_EXPRESSION_TYPE_MUL { result = LLVMBuildMul((*c).builder, (*lhs_value).value, (*rhs_value).value, ""); }; if exp.typ == MULTIPLICATIVE_EXPRESSION_TYPE_DIV { result = LLVMBuildSDiv((*c).builder, (*lhs_value).value, (*rhs_value).value, ""); }; if exp.typ == MULTIPLICATIVE_EXPRESSION_TYPE_MOD { result = LLVMBuildSRem((*c).builder, (*lhs_value).value, (*rhs_value).value, ""); }; assert(result != cast(LLVMValueRef, null)); return codegen_generate_literal(c, result, name, expression, (*lhs_value).node_type); }; if ((*expression).type == NODE_UNARY_EXPRESSION) { let exp = (*(cast(*NODE_UNARY_EXPRESSION_DATA, (*expression).data))); let k = codegen_generate_expression_value(c, exp.expression, cast(*i8, null)); assert(k != cast(*Variable, null)); let r = cast(LLVMValueRef, null); let typ = (*k).node_type; if exp.typ == UNARY_EXPRESSION_TYPE_NOT { assert((*typ).type == NODE_TYPE_SIMPLE_TYPE); let simple_type = *cast(*NODE_TYPE_SIMPLE_TYPE_DATA, (*typ).data); assert(strcmp(simple_type.name, "bool")); r = LLVMBuildICmp((*c).builder, cast(LLVMIntPredicate, LLVMIntEQ), (*k).value, LLVMConstInt(LLVMInt1Type(), 0, 0), ""); let node_type = Node{}; node_type.type = NODE_TYPE_SIMPLE_TYPE; let d = cast(*NODE_TYPE_SIMPLE_TYPE_DATA, arena_alloc((*c).arena, sizeof(NODE_TYPE_SIMPLE_TYPE_DATA))); (*d).name = "bool"; (*d).underlying_type = cast(*Node, null); node_type.data = cast(*void, d); typ = create_node(c, node_type); }; if exp.typ == UNARY_EXPRESSION_TYPE_MINUS { r = LLVMBuildNeg((*c).builder, (*k).value, ""); let node_type = Node{}; node_type.type = NODE_TYPE_SIMPLE_TYPE; let d = cast(*NODE_TYPE_SIMPLE_TYPE_DATA, arena_alloc((*c).arena, sizeof(NODE_TYPE_SIMPLE_TYPE_DATA))); (*d).name = "i64"; (*d).underlying_type = cast(*Node, null); node_type.data = cast(*void, d); typ = create_node(c, node_type); }; if exp.typ == UNARY_EXPRESSION_TYPE_STAR { assert((*typ).type == NODE_TYPE_POINTER_TYPE); let n = (*k).node_type; typ = (*cast(*NODE_TYPE_POINTER_TYPE_DATA, (*n).data)).type; let ptr_type = codegen_get_llvm_type(c, typ); assert(ptr_type != cast(*LLVMTypeRef, null)); r = LLVMBuildLoad2((*c).builder, *ptr_type, (*k).value, ""); }; return codegen_generate_literal(c, r, name, expression, typ); }; if ((*expression).type == NODE_TYPE_FUNCTION_TYPE) { let e = *((*c).environment); assert(e.scope_stack_len == 1); let existing = environment_get_variable((*c).environment, name); if (existing != cast(*Variable, null)) { return existing; }; let function_type = codegen_get_llvm_type(c, expression); assert(function_type != cast(*LLVMTypeRef, null)); let function = LLVMAddFunction((*c).llvm_module, name, *function_type); let v = Variable{}; v.value = function; v.type = cast(LLVMTypeRef, null); v.stack_level = cast(*i64, null); v.node = expression; v.node_type = expression; return codegen_create_variable(c, v); }; if ((*expression).type == NODE_FUNCTION_CALL_STATEMENT) { return codegen_generate_function_call_statement(c, expression); }; if ((*expression).type == NODE_CAST_STATEMENT) { let exp = *cast(*NODE_CAST_STATEMENT_DATA, (*expression).data); let val = codegen_generate_expression_value(c, exp.expression, ""); assert(val != cast(*Variable, null)); let v = Variable{}; v.value = (*val).value; v.type = cast(LLVMTypeRef, null); v.stack_level = cast(*i64, null); v.node = expression; v.node_type = exp.typ; return codegen_create_variable(c, v); }; if ((*expression).type == NODE_SIZEOF_STATEMENT) { let exp = *cast(*NODE_SIZEOF_STATEMENT_DATA, (*expression).data); let typ = codegen_get_llvm_type(c, exp.typ); assert(typ != cast(*LLVMTypeRef, null)); let size_in_bytes = LLVMStoreSizeOfType((*c).llvm_target_data, *typ); let size_val = LLVMConstInt(LLVMInt64Type(), size_in_bytes, 0); let node_type = Node{}; node_type.type = NODE_TYPE_SIMPLE_TYPE; let d = cast(*NODE_TYPE_SIMPLE_TYPE_DATA, arena_alloc((*c).arena, sizeof(NODE_TYPE_SIMPLE_TYPE_DATA))); (*d).name = "i64"; (*d).underlying_type = cast(*Node, null); node_type.data = cast(*void, d); let v = Variable{}; v.value = size_val; v.type = cast(LLVMTypeRef, null); v.stack_level = cast(*i64, null); v.node = expression; v.node_type = create_node(c, node_type); return codegen_create_variable(c, v); }; if ((*expression).type == NODE_TYPE_STRUCT_TYPE) { let struc_data = *cast(*NODE_TYPE_STRUCT_TYPE_DATA, (*expression).data); let dd = cast(*NODE_TYPE_SIMPLE_TYPE_DATA, arena_alloc((*c).arena, sizeof(NODE_TYPE_SIMPLE_TYPE_DATA))); (*dd).name = name; (*dd).underlying_type = expression; let n = Node{}; n.type = NODE_TYPE_SIMPLE_TYPE; n.data = cast(*void, dd); let simple_type_node = create_node(c, n); let struc_type = LLVMStructCreateNamed((*c).llvm_context, name); if name != cast(*i8, null) { let v = Variable{}; v.value = cast(LLVMValueRef, null); v.type = struc_type; v.stack_level = cast(*i64, null); v.node = expression; v.node_type = simple_type_node; environment_add_variable((*c).environment, name, codegen_create_variable(c, v)); }; let llvm_types = cast(*LLVMTypeRef, arena_alloc((*c).arena, sizeof(LLVMTypeRef) * 20)); let i = 0; while i < struc_data.fields_len { let field = *(struc_data.fields + cast(**Node, i)); assert((*field).type == NODE_PRIMARY_EXPRESSION_IDENTIFIER); let t = (*cast(*NODE_PRIMARY_EXPRESSION_IDENTIFIER_DATA, (*field).data)).type; let lt = codegen_get_llvm_type(c, t); assert(lt != cast(*LLVMTypeRef, null)); (*(llvm_types + cast(*LLVMTypeRef, i))) = *lt; i = i + 1; }; LLVMStructSetBody(struc_type, llvm_types, i, 0); let v = Variable{}; v.value = cast(LLVMValueRef, null); v.type = struc_type; v.stack_level = cast(*i64, null); v.node = expression; v.node_type = simple_type_node; return codegen_create_variable(c, v); }; if ((*expression).type == NODE_TYPE_SIMPLE_TYPE) { let simple_type_data = *cast(*NODE_TYPE_SIMPLE_TYPE_DATA, (*expression).data); let typ = codegen_get_llvm_type(c, simple_type_data.underlying_type); assert(typ != cast(*LLVMTypeRef, null)); let v = Variable{}; v.value = cast(LLVMValueRef, null); v.type = *typ; v.stack_level = cast(*i64, null); v.node = expression; v.node_type = simple_type_data.underlying_type; return codegen_create_variable(c, v); }; if ((*expression).type == NODE_STRUCT_INSTANCIATION) { let struc_data = *cast(*NODE_STRUCT_INSTANCIATION_DATA, (*expression).data); let v = environment_get_variable((*c).environment, struc_data.typ); assert(v != cast(*Variable, null)); return v; }; if ((*expression).type == NODE_FIELD_ACCESS) { let field_access = *cast(*NODE_FIELD_ACCESS_DATA, (*expression).data); let x = codegen_get_struct_field(c, field_access.expression, field_access.name); assert(x != cast(*StructField, null)); let t = codegen_get_llvm_type(c, (*x).type); assert(t != cast(*LLVMTypeRef, null)); let loaded = LLVMBuildLoad2((*c).builder, *t, (*x).value, ""); let v = Variable{}; v.value = loaded; v.type = cast(LLVMTypeRef, null); v.stack_level = cast(*i64, null); v.node = expression; v.node_type = (*x).type; return codegen_create_variable(c, v); }; printf("ASSERT 1: %d\n", (*expression).type); assert(false); return cast(*Variable, null); }; let codegen_generate_assignment_statement = (c: *codegen, stmt: *NODE_ASSIGNMENT_STATEMENT_DATA) => i64 { let lhs = *((*stmt).lhs); let prhs = (*stmt).rhs; if (lhs.type == NODE_PRIMARY_EXPRESSION_IDENTIFIER) { let identifier = (*cast(*NODE_PRIMARY_EXPRESSION_IDENTIFIER_DATA, lhs.data)).name; let variable = codegen_generate_expression_value(c, prhs, identifier); assert(variable != cast(*Variable, null)); let env = (*(*c).environment); if env.scope_stack_len == 1 { environment_add_variable((*c).environment, identifier, variable); return 0; }; let ptr = cast(LLVMValueRef, null); let typ = (*variable).node_type; if (*stmt).is_declaration { let x = codegen_get_llvm_type(c, typ); assert(x != cast(*LLVMTypeRef, null)); if (*typ).type == NODE_TYPE_FUNCTION_TYPE { *x = LLVMPointerType(*x, 0); }; ptr = LLVMBuildAlloca((*c).builder, *x, identifier); }; if !(*stmt).is_declaration { let v = environment_get_variable((*c).environment, identifier); assert(v != cast(*Variable, null)); ptr = (*v).value; typ = (*v).node_type; /* TODO: compare types */ }; if (*stmt).is_dereference { let ltyp = codegen_get_llvm_type(c, typ); assert(ltyp != cast(*LLVMTypeRef, null)); ptr = LLVMBuildLoad2((*c).builder, *ltyp, ptr, ""); }; /* NOTE: structs have a null variable.value */ if (*variable).value != cast(LLVMValueRef, null) { LLVMBuildStore((*c).builder, (*variable).value, ptr); }; if (*stmt).is_dereference { let v = environment_get_variable((*c).environment, identifier); assert(v != cast(*Variable, null)); ptr = (*v).value; }; let new_variable = Variable{}; new_variable.value = ptr; new_variable.type = (*variable).type; new_variable.stack_level = cast(*i64, null); new_variable.node = (*variable).node; new_variable.node_type = typ; if (*stmt).is_declaration { environment_add_variable((*c).environment, identifier, codegen_create_variable(c, new_variable)); }; if !(*stmt).is_declaration { environment_set_variable((*c).environment, identifier, codegen_create_variable(c, new_variable)); }; return 0; }; if (lhs.type == NODE_UNARY_EXPRESSION) { let xd = (*cast(*NODE_UNARY_EXPRESSION_DATA, lhs.data)).expression; let a = codegen_generate_expression_value(c, xd, cast(*i8, null)); assert(a != cast(*Variable, null)); let variable = codegen_generate_expression_value(c, prhs, cast(*i8, null)); assert(variable != cast(*Variable, null)); /* TODO: Check type */ LLVMBuildStore((*c).builder, (*variable).value, (*a).value); return 0; }; if (lhs.type == NODE_FIELD_ACCESS) { let field_access = (*cast(*NODE_FIELD_ACCESS_DATA, lhs.data)); let xd = field_access.expression; let name = field_access.name; let x = codegen_get_struct_field(c, xd, name); assert(x != cast(*StructField, null)); let variable = codegen_generate_expression_value(c, prhs, cast(*i8, null)); /* TODO: Typecheck */ LLVMBuildStore((*c).builder, (*variable).value, (*x).value); return 0; }; printf("ASSERT 2 %d\n", lhs.type); assert(false); return 0; }; let codegen_generate_return_statement = (c: *codegen, stmt: *NODE_RETURN_STATEMENT_DATA) => i64 { let expression = (*stmt).expression; if expression == cast(*Node, null) { LLVMBuildRetVoid((*c).builder); return 0; }; let val = codegen_generate_expression_value(c, expression, cast(*i8, null)); assert(val != cast(*Variable, null)); /* TODO: Check type */ LLVMBuildRet((*c).builder, (*val).value); return 0; }; let get_function_return_type = (ic: *codegen, fun: *Node) => *Node { if (*fun).type == NODE_FUNCTION_DEFINITION { let d = cast(*NODE_FUNCTION_DEFINITION_DATA, (*fun).data); return (*d).retur_type; }; if (*fun).type == NODE_PRIMARY_EXPRESSION_IDENTIFIER { let d = cast(*NODE_PRIMARY_EXPRESSION_IDENTIFIER_DATA, (*fun).data); let f = environment_get_variable((*ic).environment, (*d).name); if f == cast(*Variable, null) { printf("NO variable 2: %s\n", (*d).name); assert(false); }; let f_type = (*f).node_type; assert((*f_type).type == NODE_TYPE_FUNCTION_TYPE); return get_function_return_type(ic, f_type); }; if (*fun).type == NODE_TYPE_FUNCTION_TYPE { let d = cast(*NODE_TYPE_FUNCTION_TYPE_DATA, (*fun).data); return (*d).retur_type; }; assert(false); return cast(*Node, null); }; let codegen_generate_function_call_statement = (c: *codegen, statement: *Node) => *Variable { assert((*statement).type == NODE_FUNCTION_CALL_STATEMENT); let stmt = cast(*NODE_FUNCTION_CALL_STATEMENT_DATA, (*statement).data); let expression = (*stmt).expression; let node = statement; let function = cast(*Variable, null); if (*expression).type == NODE_PRIMARY_EXPRESSION_IDENTIFIER { let ident = (*cast(*NODE_PRIMARY_EXPRESSION_IDENTIFIER_DATA, (*expression).data)); function = environment_get_variable((*c).environment, ident.name); if function == cast(*Variable, null) { printf("NO variable 1: %s\n", ident.name); assert(false); }; if LLVMGetValueKind((*function).value) != LLVMFunctionValueKind { let lt = codegen_get_llvm_type(c, (*function).node_type); assert(lt != cast(*LLVMTypeRef, null)); (*function).value = LLVMBuildLoad2((*c).builder, LLVMPointerType(*lt, 0), (*function).value, ""); node = (*function).node; }; }; if (*expression).type == NODE_FUNCTION_DEFINITION { function = codegen_generate_expression_value(c, expression, cast(*i8, null)); }; assert(function != cast(*Variable, null)); let arguments = cast(*LLVMValueRef, arena_alloc((*c).arena, sizeof(LLVMValueRef) * (*stmt).arguments_len)); let i = 0; while i < (*stmt).arguments_len { let argument = (*((*stmt).arguments + cast(**Node, i))); let arg = codegen_generate_expression_value(c, argument, cast(*i8, null)); assert(arg != cast(*Variable, null)); /* TODO: Typecheck */ (*(arguments + cast(*LLVMValueRef, i))) = (*arg).value; i = i + 1; }; let function_type = codegen_get_llvm_type(c, (*function).node_type); assert(function_type != cast(*LLVMTypeRef, null)); let res = LLVMBuildCall2((*c).builder, *function_type, (*function).value, arguments, i, ""); let function_return_type = get_function_return_type(c, (*function).node_type); let v = Variable{}; v.value = res; v.type = cast(LLVMTypeRef, null); v.stack_level = cast(*i64, null); v.node = node; v.node_type = function_return_type; return codegen_create_variable(c, v); }; let codegen_generate_break_statement = (c: *codegen) => i64 { assert((*c).whil_loop_exit != cast(LLVMBasicBlockRef, null)); LLVMBuildBr((*c).builder, (*c).whil_loop_exit); return 0; }; let codegen_generate_continue_statement = (c: *codegen) => i64 { assert((*c).whil_block != cast(LLVMBasicBlockRef, null)); LLVMBuildBr((*c).builder, (*c).whil_block); return 0; }; let codegen_generate_if_statement = (c: *codegen, statement: *NODE_IF_STATEMENT_DATA) => *void { let condition_value = codegen_generate_expression_value(c, (*statement).condition, cast(*i8, null)); assert(condition_value != cast(*Variable, null)); let current_block = LLVMGetInsertBlock((*c).builder); let then_block = LLVMAppendBasicBlock((*c).current_function, "then_block"); LLVMPositionBuilderAtEnd((*c).builder, then_block); let i = 0; while i < (*statement).statements_len { let stmt = (*((*statement).statements + cast(**Node, i))); let res = codegen_generate_statement(c, stmt); assert(res == 0); i = i + 1; }; let merge_block = LLVMAppendBasicBlock((*c).current_function, "merge_block"); let last_instr = LLVMGetLastInstruction(LLVMGetInsertBlock((*c).builder)); if last_instr == cast(LLVMValueRef, null) { LLVMBuildBr((*c).builder, merge_block); }; if last_instr != cast(LLVMValueRef, null) { if LLVMIsATerminatorInst(last_instr) == cast(LLVMValueRef, null) { LLVMBuildBr((*c).builder, merge_block); }; }; LLVMPositionBuilderAtEnd((*c).builder, current_block); LLVMBuildCondBr((*c).builder, (*condition_value).value, then_block, merge_block); LLVMPositionBuilderAtEnd((*c).builder, merge_block); return null; }; let codegen_generate_while_statement = (c: *codegen, statement: *NODE_WHILE_STATEMENT_DATA) => *void { let whil_block = LLVMAppendBasicBlock((*c).current_function, "while_block"); LLVMBuildBr((*c).builder, whil_block); LLVMPositionBuilderAtEnd((*c).builder, whil_block); let condition_value = codegen_generate_expression_value(c, (*statement).condition, cast(*i8, null)); assert(condition_value != cast(*Variable, null)); let inner_block = LLVMAppendBasicBlock((*c).current_function, "inner_block"); let outer_block = LLVMAppendBasicBlock((*c).current_function, "outer_block"); LLVMBuildCondBr((*c).builder, (*condition_value).value, inner_block, outer_block); (*c).whil_loop_exit = outer_block; (*c).whil_block = whil_block; LLVMPositionBuilderAtEnd((*c).builder, inner_block); let i = 0; while i < (*statement).statements_len { let stmt = (*((*statement).statements + cast(**Node, i))); let res = codegen_generate_statement(c, stmt); assert(res == 0); i = i + 1; }; LLVMBuildBr((*c).builder, whil_block); LLVMPositionBuilderAtEnd((*c).builder, outer_block); (*c).whil_loop_exit = cast(LLVMBasicBlockRef, null); (*c).whil_block = cast(LLVMBasicBlockRef, null); return null; }; extern codegen_generate = (*codegen, *Node) => i64; let codegen_generate_import_declaration = (c: *codegen, statement: *NODE_IMPORT_DECLARATION_DATA) => i64 { return codegen_generate(c, (*statement).program); }; let codegen_generate_statement = (c: *codegen, statement: *Node) => i64 { let stmt = *statement; if stmt.type == NODE_ASSIGNMENT_STATEMENT { return codegen_generate_assignment_statement(c, cast(*NODE_ASSIGNMENT_STATEMENT_DATA, stmt.data)); }; if stmt.type == NODE_RETURN_STATEMENT { return codegen_generate_return_statement(c, cast(*NODE_RETURN_STATEMENT_DATA, stmt.data)); }; if stmt.type == NODE_FUNCTION_CALL_STATEMENT { codegen_generate_function_call_statement(c, statement); return 0; }; if stmt.type == NODE_IF_STATEMENT { codegen_generate_if_statement(c, cast(*NODE_IF_STATEMENT_DATA, stmt.data)); return 0; }; if stmt.type == NODE_WHILE_STATEMENT { codegen_generate_while_statement(c, cast(*NODE_WHILE_STATEMENT_DATA, stmt.data)); return 0; }; if stmt.type == NODE_IMPORT_DECLARATION { return codegen_generate_import_declaration(c, cast(*NODE_IMPORT_DECLARATION_DATA, stmt.data)); }; if stmt.type == NODE_CONTINUE_STATEMENT { return codegen_generate_continue_statement(c); }; if stmt.type == NODE_BREAK_STATEMENT { return codegen_generate_break_statement(c); }; printf("ASSERT 3 %d\n", stmt.type); assert(false); return 0; }; let codegen_generate = (c: *codegen, ast: *Node) => i64 { assert((*ast).type == NODE_PROGRAM); let program = *cast(*NODE_PROGRAM_DATA, (*ast).data); let i = 0; while i < program.statements_len { let stmt = *(program.statements + cast(**Node, i)); let res = codegen_generate_statement(c, stmt); if res != 0 { return 1; }; i = i + 1; }; return 0; }; let codegen_compile = (c: *codegen) => i64 { /* Dump module */ LLVMDumpModule((*c).llvm_module); /* Generate code */ let triple = LLVMGetDefaultTargetTriple(); let target_ref = cast(*LLVMTargetRef, arena_alloc((*c).arena, sizeof(*LLVMTargetRef))); let message = cast(**i8, null); let result = LLVMGetTargetFromTriple(triple, target_ref, message); if result != 0 { printf("Target output: %s\n", *message); LLVMDisposeMessage(*message); }; let target_machine = LLVMCreateTargetMachine( *target_ref, triple, "", "", LLVMCodeGenLevelDefault, LLVMRelocDefault, LLVMCodeModelDefault, ); LLVMDisposeMessage(triple); result = LLVMVerifyModule((*c).llvm_module, LLVMAbortProcessAction, message); if result != 0 { printf("Verification output: %s\n", *message); LLVMDisposeMessage(*message); }; /* Generate the object file */ let filename = "bootstrap_output.o"; LLVMTargetMachineEmitToFile( target_machine, (*c).llvm_module, filename, LLVMObjectFile, cast(**i8, null), ); LLVMDisposeTargetMachine(target_machine); printf("Object file generated: %s\n", filename); return 0; }; let codegen_deinit = (c: *codegen) => void { LLVMDisposeModule((*c).llvm_module); LLVMShutdown(); LLVMDisposeBuilder((*c).builder); return; };