#include #include #include #include #include #include "alloc.h" #include "codegen.h" #include "common.h" #include "errors.h" #include "parser.h" #include "types.h" static size_t codegenstmt(LLVMBuilderRef, struct ast, struct lexemes, size_t); static size_t codegenexpr(LLVMBuilderRef, struct ast, struct lexemes, size_t, LLVMValueRef *) __attribute__((nonnull)); void codegen(struct ast ast, struct lexemes toks) { LLVMModuleRef mod = LLVMModuleCreateWithName("oryx"); LLVMBuilderRef builder = LLVMCreateBuilder(); for (size_t i = 0; i < ast.len;) { switch (ast.kinds[i]) { case ASTDECL: { /* TODO: Temporary allocator */ struct strview sv = toks.strs[ast.lexemes[i]]; char *name = bufalloc(NULL, sv.len + 1, 1); ((uchar *)memcpy(name, sv.p, sv.len))[sv.len] = 0; LLVMValueRef globl, val; globl = LLVMAddGlobal(mod, LLVMInt64Type(), name); i = codegenexpr(builder, ast, toks, ast.kids[i].rhs, &val); LLVMSetInitializer(globl, val); free(name); break; } case ASTCDECL: { idx_t_ expr = ast.kids[i].rhs; if (ast.kinds[expr] != ASTFN) { assert(!"not implemented"); __builtin_unreachable(); } idx_t_ proto = ast.kids[expr].lhs, body = ast.kids[expr].rhs; LLVMTypeRef ret; LLVMTypeRef params[] = {0}; if (ast.kids[proto].rhs == AST_EMPTY) ret = LLVMVoidType(); else { size_t type = ast.kids[proto].rhs; struct strview sv = toks.strs[ast.lexemes[type]]; /* TODO: Make int 32bit on 32bit platforms */ if (strncmp("int", sv.p, sv.len) == 0) ret = LLVMInt64Type(); else err("codegen: Unknown type: %.*s", (int)sv.len, sv.p); } LLVMTypeRef fnproto = LLVMFunctionType(ret, params, 0, false); struct strview sv = toks.strs[ast.lexemes[i]]; char *fnname = bufalloc(NULL, sv.len + 1, 1); ((char *)memcpy(fnname, sv.p, sv.len))[sv.len] = 0; LLVMValueRef fn = LLVMAddFunction(mod, fnname, fnproto); LLVMBasicBlockRef entry = LLVMAppendBasicBlock(fn, "entry"); LLVMPositionBuilderAtEnd(builder, entry); free(fnname); for (i = ast.kids[body].lhs; i <= ast.kids[body].rhs;) i = codegenstmt(builder, ast, toks, i); break; } default: err("codegen: Expected declaration"); } } LLVMDisposeBuilder(builder); char *error = NULL; LLVMVerifyModule(mod, LLVMAbortProcessAction, &error); LLVMDisposeMessage(error); LLVMDumpModule(mod); LLVMDisposeModule(mod); } size_t codegenstmt(LLVMBuilderRef builder, struct ast ast, struct lexemes toks, size_t i) { switch (ast.kinds[i]) { case ASTRET: if (ast.kids[i].rhs == AST_EMPTY) { LLVMBuildRetVoid(builder); return i + 1; } LLVMValueRef v; i = codegenexpr(builder, ast, toks, ast.kids[i].rhs, &v); LLVMBuildRet(builder, v); return i; } assert(!"unreachable"); __builtin_unreachable(); } size_t codegenexpr(LLVMBuilderRef builder, struct ast ast, struct lexemes toks, size_t i, LLVMValueRef *v) { (void)builder; switch (ast.kinds[i]) { case ASTNUMLIT: { /* TODO: Arbitrary precision? */ struct strview sv = toks.strs[ast.lexemes[i]]; /* TODO: Temporary one-time-use allocator? */ size_t len = 0; char *p = bufalloc(NULL, sv.len, 1); for (size_t i = 0; i < sv.len; i++) { if (sv.p[i] != '\'') p[len++] = sv.p[i]; } *v = LLVMConstIntOfStringAndSize(LLVMInt64Type(), p, len, 10); free(p); return i + 1; } } assert(!"unreachable"); __builtin_unreachable(); }