diff options
Diffstat (limited to 'src/bootstrap/codegen.pry')
| -rw-r--r-- | src/bootstrap/codegen.pry | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/src/bootstrap/codegen.pry b/src/bootstrap/codegen.pry new file mode 100644 index 0000000..7293c09 --- /dev/null +++ b/src/bootstrap/codegen.pry @@ -0,0 +1,187 @@ +import "llvm.pry"; + +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; + + printf("X: %d\n", 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) { + printf("ASS %d\n", (*expression).type); + assert(false); /* TODO */ + printf("ERT\n"); + }; + + 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; + printf("XX %s\n", 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; + }; + printf("STMT: %d\n", 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 { + 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; +}; |