diff --git a/SConstruct b/SConstruct index bb2bb858e51ecf84db7588ba1c212bdf164e2e5d..1ff257aec13579ca30da6322ae2de4bf56ef8842 100644 --- a/SConstruct +++ b/SConstruct @@ -100,7 +100,7 @@ if GetOption("coverage"): if env["CC"] == "gcc": env.Append(LIBS=['gcov']) else: - env.ParseConfig('llvm-config --ldflags') + env.ParseConfig('llvm-config --cflags --ldflags --libs core executionengine mcjit analysis x86codegen x86info') if os.getenv("CC") == "clang" or env['PLATFORM'] == 'darwin': env.Replace(CC="clang", diff --git a/src/SConscript b/src/SConscript index 689c7e0344c918074edd1c830195aea14662e39c..575cf34cbeef54540b3883ce06408d5ce5c96620 100644 --- a/src/SConscript +++ b/src/SConscript @@ -76,7 +76,7 @@ ctests = ['t_benchmark.c', 't_misc.c', 't_regression.c'] -env.ParseConfig('llvm-config --cflags') +env.ParseConfig('llvm-config --cflags --ldflags') libhammer_shared = env.SharedLibrary('hammer', parsers + backends + misc_hammer_parts) libhammer_static = env.StaticLibrary('hammer', parsers + backends + misc_hammer_parts) Default(libhammer_shared, libhammer_static) @@ -88,9 +88,10 @@ env.Install("$backendsincpath", backends_headers) env.Install("$pkgconfigpath", "../../../libhammer.pc") testenv = env.Clone() -testenv.ParseConfig('pkg-config --cflags --libs glib-2.0') -testenv.ParseConfig('llvm-config --cflags') testenv.Append(LIBS=['hammer'], LIBPATH=['.']) +testenv.ParseConfig('pkg-config --cflags --libs glib-2.0') +testenv.ParseConfig('llvm-config --cflags --ldflags --system-libs --libs core executionengine mcjit analysis x86codegen x86info') +testenv.Append(LIBS=['stdc++'], LIBPATH=['.']) ctestexec = testenv.Program('test_suite', ctests + ['test_suite.c'], LINKFLAGS="--coverage" if testenv.GetOption("coverage") else None) ctest = Alias('testc', [ctestexec], "".join(["env LD_LIBRARY_PATH=", os.path.dirname(ctestexec[0].path), " ", ctestexec[0].path])) AlwaysBuild(ctest) diff --git a/src/backends/llvm.c b/src/backends/llvm.c index d7904a0ec52bc46d13b5fce71b2988d5459f2398..c4aafb3a243f5ec4b327d7bba8e3ea61acbc55d6 100644 --- a/src/backends/llvm.c +++ b/src/backends/llvm.c @@ -11,10 +11,6 @@ typedef struct HLLVMParser_ { 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), @@ -40,22 +36,30 @@ void h_llvm_declare_common(LLVMModuleRef mod) { } int h_llvm_compile(HAllocator* mm__, HParser* parser, const void* params) { + // Boilerplate to set up a translation unit, aka a module. 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); + // Boilerplate to set up the parser function to add to the module. It takes an HInputStream* and + // returns an HParseResult. + LLVMTypeRef param_types[] = { + LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HInputStream_"), 0), + LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HArena_"), 0) + }; + LLVMTypeRef ret_type = LLVMFunctionType(LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HParseResult_"), 0), param_types, 2, 0); LLVMValueRef parse_func = LLVMAddFunction(mod, name, ret_type); - // function is now declared; time to define it + // Parse 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)) { + // Translate the contents of the children of `parser` into their LLVM instruction equivalents + if (parser->vtable->llvm(builder, mod, parser->env)) { + // But first, verification char *error = NULL; LLVMVerifyModule(mod, LLVMAbortProcessAction, &error); LLVMDisposeMessage(error); error = NULL; + // OK, link that sonofabitch LLVMInitializeNativeTarget(); LLVMLinkInMCJIT(); LLVMExecutionEngineRef engine = NULL; @@ -65,6 +69,7 @@ int h_llvm_compile(HAllocator* mm__, HParser* parser, const void* params) { LLVMDisposeMessage(error); return -1; } + // Package up the pointers that comprise the module and stash it in the original HParser HLLVMParser *llvm_parser = h_new(HLLVMParser, 1); llvm_parser->mod = mod; llvm_parser->func = parse_func; @@ -86,11 +91,8 @@ void h_llvm_free(HParser *parser) { 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); + LLVMGenericValueRef args[] = { LLVMCreateGenericValueOfPointer(input_stream) }; + LLVMGenericValueRef ret = LLVMRunFunction(llvm_parser->engine, llvm_parser->func, 1, args); return (HParseResult*)LLVMGenericValueToPointer(ret); } diff --git a/src/parsers/ch.c b/src/parsers/ch.c index d7743bc920099322cc7676e8886ec159b842253c..a6822baced84b240af71aee936573b7666f889a2 100644 --- a/src/parsers/ch.c +++ b/src/parsers/ch.c @@ -45,32 +45,33 @@ static bool ch_ctrvm(HRVMProg *prog, void* env) { static bool ch_llvm(LLVMBuilderRef builder, LLVMModuleRef mod, void* env) { uint8_t c_ = (uint8_t)(uintptr_t)(env); LLVMValueRef c = LLVMConstInt(LLVMInt8Type(), c_, 0); - LLVMTypeRef param_types[] = { LLVMPointerType(LLVMInt8Type(), 0) }; - LLVMTypeRef ret_type = LLVMFunctionType(LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HParseResult_"), 0), param_types, 1, 0); + LLVMTypeRef param_types[] = { + LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HInputStream_"), 0), + LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HArena_"), 0) + }; + LLVMTypeRef ret_type = LLVMFunctionType(LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HParseResult_"), 0), param_types, 2, 0); LLVMValueRef ch = LLVMAddFunction(mod, "ch", ret_type); + // get the parameter array to use later with h_bits + LLVMValueRef params[3]; + LLVMGetParams(ch, params); + params[1] = LLVMConstInt(LLVMInt32Type(), 8, 0); + params[2] = LLVMConstInt(LLVMInt8Type(), 0, 0); + LLVMValueRef arena = LLVMGetParam(ch, 1); LLVMBasicBlockRef entry = LLVMAppendBasicBlock(ch, "ch_entry"); LLVMBasicBlockRef success = LLVMAppendBasicBlock(ch, "ch_success"); LLVMBasicBlockRef fail = LLVMAppendBasicBlock(ch, "ch_fail"); LLVMBasicBlockRef end = LLVMAppendBasicBlock(ch, "ch_end"); LLVMPositionBuilderAtEnd(builder, entry); // %1 = alloca %struct.HParseResult_*, align 8 - // FIXME declare struct types like LL_HParsedToken with LLVMStructType() in some other header LLVMValueRef ret = LLVMBuildAlloca(builder, LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HParseResult_"), 0), "ret"); // skip %2 through %c 'cause we have these from arguments // %r = alloca i8, align 1 LLVMValueRef r = LLVMBuildAlloca(builder, LLVMInt8Type(), "r"); // %tok = alloca %struct.HParsedToken_*, align 8 LLVMValueRef tok = LLVMBuildAlloca(builder, LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HParsedToken_"), 0), "tok"); - // skip next instr through %7 - // %8 = getelementptr inbounds %struct.HParseState_* %7, i32 0, i32 1 - LLVMValueRef bounds1[] = { - LLVMConstInt(LLVMInt32Type(), 0, 0), - LLVMConstInt(LLVMInt32Type(), 1, 0), - }; - /* FIXME env is the wrong pointer to use here */ - LLVMValueRef stream = LLVMBuildInBoundsGEP(builder, env, bounds1, 1, "stream"); + // skip next instr through %8 // %9 = call i64 @h_read_bits(%struct.HInputStream_* %8, i32 8, i8 signext 0) - LLVMValueRef bits = LLVMBuildCall(builder, LLVMGetNamedFunction(mod, "h_read_bits"), &stream, 1, "h_read_bits"); + LLVMValueRef bits = LLVMBuildCall(builder, LLVMGetNamedFunction(mod, "h_read_bits"), params, 1, "h_read_bits"); // %10 = trunc i64 %9 to i8 LLVMValueRef tmp = LLVMBuildTrunc(builder, bits, LLVMInt8Type(), ""); // store i8 %10, i8* %r, align 1 @@ -86,44 +87,39 @@ static bool ch_llvm(LLVMBuilderRef builder, LLVMModuleRef mod, void* env) { // ; <label>:16 - success case LLVMPositionBuilderAtEnd(builder, success); - // %17 = load %struct.HParseState_** %3, align 8 - // %18 = getelementptr inbounds %struct.HParseState_* %17, i32 0, i32 2 - LLVMValueRef bounds2[] = { - LLVMConstInt(LLVMInt32Type(), 0, 0), - LLVMConstInt(LLVMInt32Type(), 2, 0), - }; - /* FIXME env is not the right pointer to use here */ - LLVMValueRef arena = LLVMBuildInBoundsGEP(builder, env, bounds2, 2, "arena"); + // skip %17-%19 because we have the arena as an argument + LLVMValueRef tok_size = LLVMConstInt(LLVMInt32Type(), sizeof(HParsedToken), 0); + LLVMValueRef amalloc_args[] = { arena, tok_size }; // %20 = call noalias i8* @h_arena_malloc(%struct.HArena_* %19, i64 48) - LLVMValueRef amalloc = LLVMBuildCall(builder, LLVMGetNamedFunction(mod, "h_arena_malloc"), &arena, 2, "h_arena_malloc"); + LLVMValueRef amalloc = LLVMBuildCall(builder, LLVMGetNamedFunction(mod, "h_arena_malloc"), amalloc_args, 2, "h_arena_malloc"); // %21 = bitcast i8* %20 to %struct.HParsedToken_* LLVMValueRef cast1 = LLVMBuildBitCast(builder, amalloc, LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HParsedToken_"), 0), ""); // store %struct.HParsedToken_* %21, %struct.HParsedToken_** %tok, align 8 LLVMBuildStore(builder, cast1, tok); // %22 = load %struct.HParsedToken_** %tok, align 8 // %23 = getelementptr inbounds %struct.HParsedToken_* %22, i32 0, i32 0 - LLVMValueRef bounds3[] = { + LLVMValueRef bounds1[] = { LLVMConstInt(LLVMInt32Type(), 0, 0), LLVMConstInt(LLVMInt32Type(), 0, 0) }; - LLVMValueRef toktype = LLVMBuildInBoundsGEP(builder, tok, bounds3, 0, "token_type"); + LLVMValueRef toktype = LLVMBuildInBoundsGEP(builder, tok, bounds1, 0, "token_type"); // store i32 8, i32* %23, align 4 LLVMBuildStore(builder, LLVMConstInt(LLVMInt32Type(), 8, 0), toktype); // %24 = load i8* %r, align 1 // %25 = zext i8 %24 to i64 // %26 = load %struct.HParsedToken_** %tok, align 8 // %27 = getelementptr inbounds %struct.HParsedToken_* %26, i32 0, i32 1 - LLVMValueRef uint = LLVMBuildInBoundsGEP(builder, tok, bounds1, 1, "uint"); + LLVMValueRef bounds2[] = { + LLVMConstInt(LLVMInt32Type(), 0, 0), + LLVMConstInt(LLVMInt32Type(), 0, 1) + }; + LLVMValueRef uint = LLVMBuildInBoundsGEP(builder, tok, bounds2, 1, "uint"); // %28 = bitcast %union.anon* %27 to i64* LLVMValueRef cast2 = LLVMBuildBitCast(builder, uint, LLVMInt64Type(), "result"); // we already have the arena and the token, so skip to %33 - // %29 = load %struct.HParseState_** %3, align 8 - // %30 = getelementptr inbounds %struct.HParseState_* %29, i32 0, i32 2 - // %31 = load %struct.HArena_** %30, align 8 - // %32 = load %struct.HParsedToken_** %tok, align 8 // %33 = call %struct.HParseResult_* @make_result(%struct.HArena_* %31, %struct.HParsedToken_* %32) - LLVMValueRef args[] = { arena, tok }; - LLVMValueRef mr = LLVMBuildCall(builder, LLVMGetNamedFunction(mod, "make_result"), args, 2, "make_result"); + LLVMValueRef result_args[] = { arena, tok }; + LLVMValueRef mr = LLVMBuildCall(builder, LLVMGetNamedFunction(mod, "make_result"), result_args, 2, "make_result"); // store %struct.HParseResult_* %33, %struct.HParseResult_** %1 LLVMBuildStore(builder, mr, ret); // br label %35 diff --git a/src/t_parser.c b/src/t_parser.c index c42eca91321c241a1987b99116c8c90deefbdf64..17dc9a91cc5671567a3db18bb5cb2f5148f5e90a 100644 --- a/src/t_parser.c +++ b/src/t_parser.c @@ -961,4 +961,6 @@ void register_parser_tests(void) { g_test_add_data_func("/core/parser/glr/ambiguous", GINT_TO_POINTER(PB_GLR), test_ambiguous); g_test_add_data_func("/core/parser/glr/result_length", GINT_TO_POINTER(PB_GLR), test_result_length); g_test_add_data_func("/core/parser/glr/token_position", GINT_TO_POINTER(PB_GLR), test_token_position); + + g_test_add_data_func("/core/parser/llvm/ch", GINT_TO_POINTER(PB_LLVM), test_ch); }