import "llvm.src"; let codegen = struct { llvm_module: LLVMModuleRef, llvm_context: LLVMContextRef, builder: LLVMBuilderRef, arena: *arena, }; 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_context = context; (*c).builder = builder; (*c).arena = 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 Variable = struct { value: LLVMValueRef, type: LLVMTypeRef, node: *Node, node_type: *Node, stack_level: *i64, }; 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_generate_literal = (c: *codegen, literal_val: LLVMValueRef, name: *i8, node: *Node, node_type: *Node) => *Variable { /* TODO: Global */ 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); }; let codegen_generate_expression_value = (c: *codegen, expression: *Node, name: *i8) => *Variable { if ((*expression).type == NODE_PRIMARY_EXPRESSION_NUMBER) { let n = (*cast(*NODE_PRIMARY_EXPRESSION_NUMBER_DATA, (*expression).data)).value; println("X: %d", n); 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_FUNCTION_DEFINITION) { println("ASS %d", (*expression).type); assert(false); /* TODO */ println("ERT"); }; 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; println("XX %s", identifier); let variable = codegen_generate_expression_value(c, prhs, identifier); assert(variable != cast(*Variable, null)); return 0; }; assert(false); return 0; }; let codegen_generate_statement = (c: *codegen, statement: *Node) => i64 { let stmt = *statement; assert(stmt.type == NODE_ASSIGNMENT_STATEMENT); /* TODO: generate other node types */ let res = codegen_generate_assignment_statement(c, cast(*NODE_ASSIGNMENT_STATEMENT_DATA, stmt.data)); if res != 0 { return 1; }; println("STMT: %d", stmt.type); 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 { println("Target output: %s", *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 { println("Verification output: %s", *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); println("Object file generated: %s", filename); return 0; }; let codegen_deinit = (c: *codegen) => void { LLVMDisposeModule((*c).llvm_module); LLVMShutdown(); LLVMDisposeBuilder((*c).builder); return; };