diff --git a/src/backends/llvm.c b/src/backends/llvm.c new file mode 100644 index 0000000000000000000000000000000000000000..d7904a0ec52bc46d13b5fce71b2988d5459f2398 --- /dev/null +++ b/src/backends/llvm.c @@ -0,0 +1,101 @@ +#include <llvm-c/Analysis.h> +#include <llvm-c/Core.h> +#include <llvm-c/ExecutionEngine.h> +#include "../internal.h" +#include "../parsers/parser_internal.h" + +typedef struct HLLVMParser_ { + LLVMModuleRef mod; + LLVMValueRef func; + LLVMExecutionEngineRef engine; + LLVMBuilderRef builder; +} HLLVMParser; + +int h_llvm_walk(const HParser* parser, LLVMBuilderRef builder, LLVMModuleRef mod) { + return 0; +} + +void h_llvm_declare_common(LLVMModuleRef mod) { + LLVMTypeRef readbits_pt[] = { + LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HInputStream_"), 0), + LLVMInt32Type(), + LLVMInt8Type() + }; + LLVMTypeRef readbits_ret = LLVMFunctionType(LLVMInt64Type(), readbits_pt, 3, 0); + LLVMAddFunction(mod, "h_read_bits", readbits_ret); + + LLVMTypeRef amalloc_pt[] = { + LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HArena_"), 0), + LLVMInt32Type() + }; + LLVMTypeRef amalloc_ret = LLVMFunctionType(LLVMPointerType(LLVMVoidType(), 0), amalloc_pt, 2, 0); + LLVMAddFunction(mod, "h_arena_malloc", amalloc_ret); + + LLVMTypeRef makeresult_pt[] = { + LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HArena_"), 0), + LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HParsedToken_"), 0) + }; + LLVMTypeRef makeresult_ret = LLVMFunctionType(LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HParseResult_"), 0), makeresult_pt, 2, 0); + LLVMAddFunction(mod, "make_result", makeresult_ret); +} + +int h_llvm_compile(HAllocator* mm__, HParser* parser, const void* params) { + const char* name = params ? (const char*)params : "parse"; + LLVMModuleRef mod = LLVMModuleCreateWithName(name); + h_llvm_declare_common(mod); + // FIXME size_t isn't necessarily 32 bits everywhere + LLVMTypeRef param_types[] = { LLVMPointerType(LLVMInt8Type(), 0), LLVMInt32Type() }; + LLVMTypeRef ret_type = LLVMFunctionType(LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HParser_"), 0), param_types, 2, 0); + LLVMValueRef parse_func = LLVMAddFunction(mod, name, ret_type); + // function is now declared; time to define it + LLVMBasicBlockRef entry = LLVMAppendBasicBlock(parse_func, "entry"); + LLVMBuilderRef builder = LLVMCreateBuilder(); + LLVMPositionBuilderAtEnd(builder, entry); + if (0 == h_llvm_walk(parser, builder, mod)) { + char *error = NULL; + LLVMVerifyModule(mod, LLVMAbortProcessAction, &error); + LLVMDisposeMessage(error); + error = NULL; + LLVMInitializeNativeTarget(); + LLVMLinkInMCJIT(); + LLVMExecutionEngineRef engine = NULL; + LLVMCreateExecutionEngineForModule(&engine, mod, &error); + if (error) { + fprintf(stderr, "error: %s\n", error); + LLVMDisposeMessage(error); + return -1; + } + HLLVMParser *llvm_parser = h_new(HLLVMParser, 1); + llvm_parser->mod = mod; + llvm_parser->func = parse_func; + llvm_parser->engine = engine; + llvm_parser->builder = builder; + parser->backend_data = llvm_parser; + return 0; + } else { + return -1; + } +} + +void h_llvm_free(HParser *parser) { + HLLVMParser *llvm_parser = parser->backend_data; + LLVMDisposeBuilder(llvm_parser->builder); + LLVMDisposeExecutionEngine(llvm_parser->engine); + LLVMDisposeModule(llvm_parser->mod); +} + +HParseResult *h_llvm_parse(HAllocator* mm__, const HParser* parser, HInputStream *input_stream) { + const HLLVMParser *llvm_parser = parser->backend_data; + LLVMGenericValueRef args[] = { + LLVMCreateGenericValueOfPointer((uint8_t*)input_stream->input), + LLVMCreateGenericValueOfInt(LLVMInt32Type(), input_stream->length, 0) + }; + LLVMGenericValueRef ret = LLVMRunFunction(llvm_parser->engine, llvm_parser->func, 2, args); + return (HParseResult*)LLVMGenericValueToPointer(ret); +} + +HParserBackendVTable h__llvm_backend_vtable = { + .compile = h_llvm_compile, + .parse = h_llvm_parse, + .free = h_llvm_free +}; diff --git a/src/hammer.c b/src/hammer.c index 70ebc8a4943d8e1b3a25e036a745c2296bf8ddfd..2a7d5bc5be51059115b1af20a40c6a5de6633f2a 100644 --- a/src/hammer.c +++ b/src/hammer.c @@ -31,6 +31,7 @@ static HParserBackendVTable *backends[PB_MAX + 1] = { &h__llk_backend_vtable, &h__lalr_backend_vtable, &h__glr_backend_vtable, + &h__llvm_backend_vtable, }; diff --git a/src/hammer.h b/src/hammer.h index 1be297c7a3b1230f2595ba47366a6591946b8777..f06728eb3120b3f1ed0341a6e6f26dc4ed8059de 100644 --- a/src/hammer.h +++ b/src/hammer.h @@ -46,7 +46,8 @@ typedef enum HParserBackend_ { PB_LLk, PB_LALR, PB_GLR, - PB_MAX = PB_GLR + PB_LLVM, + PB_MAX = PB_LLVM } HParserBackend; typedef enum HTokenType_ { diff --git a/src/internal.h b/src/internal.h index 776f636811183a4b3e19de9de8c8ce5b2b66f27d..6f71f916a8f0a1404b10c4d333bc6860882cc410 100644 --- a/src/internal.h +++ b/src/internal.h @@ -25,6 +25,7 @@ #include <stdint.h> #include <assert.h> #include <string.h> +#include <llvm-c/Core.h> #include "hammer.h" #include "platform.h" @@ -322,6 +323,7 @@ extern HParserBackendVTable h__packrat_backend_vtable; extern HParserBackendVTable h__llk_backend_vtable; extern HParserBackendVTable h__lalr_backend_vtable; extern HParserBackendVTable h__glr_backend_vtable; +extern HParserBackendVTable h__llvm_backend_vtable; // }}} // TODO(thequux): Set symbol visibility for these functions so that they aren't exported. @@ -419,6 +421,7 @@ struct HParserVtable_ { bool (*isValidCF)(void *env); bool (*compile_to_rvm)(HRVMProg *prog, void* env); // FIXME: forgot what the bool return value was supposed to mean. void (*desugar)(HAllocator *mm__, HCFStack *stk__, void *env); + bool (*llvm)(LLVMBuilderRef builder, LLVMModuleRef mod, void *env); bool higher; // false if primitive };