diff --git a/src/backends/llvm/llvm.c b/src/backends/llvm/llvm.c index e393b0e7294ac32b6274aa9c5eab7b08df2f21a0..a2c15a102a532106e5497cb41c3a1ec4cc69bab1 100644 --- a/src/backends/llvm/llvm.c +++ b/src/backends/llvm/llvm.c @@ -14,6 +14,7 @@ typedef struct HLLVMParser_ { LLVMValueRef func; LLVMExecutionEngineRef engine; LLVMBuilderRef builder; + HLLVMParserCompileContext *compile_ctxt; } HLLVMParser; HParseResult* make_result(HArena *arena, HParsedToken *tok) { @@ -24,8 +25,8 @@ HParseResult* make_result(HArena *arena, HParsedToken *tok) { return ret; } -void h_llvm_declare_common(LLVMModuleRef mod) { - llvm_inputstream = LLVMStructCreateNamed(LLVMGetGlobalContext(), "struct.HInputStream_"); +void h_llvm_declare_common(HLLVMParserCompileContext *ctxt) { + ctxt->llvm_inputstream = LLVMStructCreateNamed(LLVMGetGlobalContext(), "struct.HInputStream_"); LLVMTypeRef llvm_inputstream_struct_types[] = { LLVMPointerType(LLVMInt8Type(), 0), LLVMInt64Type(), @@ -37,11 +38,11 @@ void h_llvm_declare_common(LLVMModuleRef mod) { LLVMInt8Type(), LLVMInt8Type() }; - LLVMStructSetBody(llvm_inputstream, llvm_inputstream_struct_types, 9, 0); - llvm_inputstreamptr = LLVMPointerType(llvm_inputstream, 0); - llvm_arena = LLVMStructCreateNamed(LLVMGetGlobalContext(), "struct.HArena_"); - llvm_arenaptr = LLVMPointerType(llvm_arena, 0); - llvm_parsedtoken = LLVMStructCreateNamed(LLVMGetGlobalContext(), "struct.HParsedToken_"); + LLVMStructSetBody(ctxt->llvm_inputstream, llvm_inputstream_struct_types, 9, 0); + ctxt->llvm_inputstreamptr = LLVMPointerType(ctxt->llvm_inputstream, 0); + ctxt->llvm_arena = LLVMStructCreateNamed(LLVMGetGlobalContext(), "struct.HArena_"); + ctxt->llvm_arenaptr = LLVMPointerType(ctxt->llvm_arena, 0); + ctxt->llvm_parsedtoken = LLVMStructCreateNamed(LLVMGetGlobalContext(), "struct.HParsedToken_"); LLVMTypeRef llvm_parsedtoken_struct_types[] = { LLVMInt32Type(), // actually an enum value LLVMInt64Type(), // actually this is a union; the largest thing in it is 64 bits @@ -49,59 +50,83 @@ void h_llvm_declare_common(LLVMModuleRef mod) { LLVMInt64Type(), // FIXME ditto LLVMInt8Type() }; - LLVMStructSetBody(llvm_parsedtoken, llvm_parsedtoken_struct_types, 5, 0); - llvm_parsedtokenptr = LLVMPointerType(llvm_parsedtoken, 0); - llvm_parseresult = LLVMStructCreateNamed(LLVMGetGlobalContext(), "struct.HParseResult_"); + LLVMStructSetBody(ctxt->llvm_parsedtoken, llvm_parsedtoken_struct_types, 5, 0); + ctxt->llvm_parsedtokenptr = LLVMPointerType(ctxt->llvm_parsedtoken, 0); + ctxt->llvm_parseresult = LLVMStructCreateNamed(LLVMGetGlobalContext(), "struct.HParseResult_"); LLVMTypeRef llvm_parseresult_struct_types[] = { - llvm_parsedtokenptr, + ctxt->llvm_parsedtokenptr, LLVMInt64Type(), - llvm_arenaptr + ctxt->llvm_arenaptr }; - LLVMStructSetBody(llvm_parseresult, llvm_parseresult_struct_types, 3, 0); - llvm_parseresultptr = LLVMPointerType(llvm_parseresult, 0); + LLVMStructSetBody(ctxt->llvm_parseresult, llvm_parseresult_struct_types, 3, 0); + ctxt->llvm_parseresultptr = LLVMPointerType(ctxt->llvm_parseresult, 0); LLVMTypeRef readbits_pt[] = { - llvm_inputstreamptr, + ctxt->llvm_inputstreamptr, LLVMInt32Type(), LLVMInt8Type() }; LLVMTypeRef readbits_ret = LLVMFunctionType(LLVMInt64Type(), readbits_pt, 3, 0); - LLVMAddFunction(mod, "h_read_bits", readbits_ret); + LLVMAddFunction(ctxt->mod, "h_read_bits", readbits_ret); LLVMTypeRef amalloc_pt[] = { - llvm_arenaptr, + ctxt->llvm_arenaptr, LLVMInt32Type() }; LLVMTypeRef amalloc_ret = LLVMFunctionType(LLVMPointerType(LLVMVoidType(), 0), amalloc_pt, 2, 0); - LLVMAddFunction(mod, "h_arena_malloc", amalloc_ret); + LLVMAddFunction(ctxt->mod, "h_arena_malloc", amalloc_ret); LLVMTypeRef makeresult_pt[] = { - llvm_arenaptr, - llvm_parsedtokenptr + ctxt->llvm_arenaptr, + ctxt->llvm_parsedtokenptr }; - LLVMTypeRef makeresult_ret = LLVMFunctionType(llvm_parseresultptr, makeresult_pt, 2, 0); - LLVMAddFunction(mod, "make_result", makeresult_ret); + LLVMTypeRef makeresult_ret = LLVMFunctionType(ctxt->llvm_parseresultptr, makeresult_pt, 2, 0); + LLVMAddFunction(ctxt->mod, "make_result", makeresult_ret); } int h_llvm_compile(HAllocator* mm__, HParser* parser, const void* params) { + HLLVMParserCompileContext *ctxt; // 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); + + /* Build a parser compilation context */ + ctxt = h_new(HLLVMParserCompileContext, 1); + memset(ctxt, 0, sizeof(*ctxt)); + ctxt->mm__ = mm__; + ctxt->mod = LLVMModuleCreateWithName(name); + h_llvm_declare_common(ctxt); + // Boilerplate to set up the parser function to add to the module. It takes an HInputStream* and // returns an HParseResult. LLVMTypeRef param_types[] = { - llvm_inputstreamptr, - llvm_arenaptr + ctxt->llvm_inputstreamptr, + ctxt->llvm_arenaptr }; - LLVMTypeRef ret_type = LLVMFunctionType(llvm_parseresultptr, param_types, 2, 0); - LLVMValueRef parse_func = LLVMAddFunction(mod, name, ret_type); + LLVMTypeRef ret_type = LLVMFunctionType(ctxt->llvm_parseresultptr, param_types, 2, 0); + ctxt->func = LLVMAddFunction(ctxt->mod, name, ret_type); + // Parse function is now declared; time to define it - LLVMBuilderRef builder = LLVMCreateBuilder(); + ctxt->builder = LLVMCreateBuilder(); + LLVMBasicBlockRef preamble = LLVMAppendBasicBlock(ctxt->func, "preamble"); + LLVMPositionBuilderAtEnd(ctxt->builder, preamble); + + /* + * First thing it needs to do is get its stream and arena args and stick + * value refs in the context. + * + * XXX do we always need arena? Can we make a dummy valueref the generated + * IR refers to, and then fill in arena if we need it after we know whether + * we need it? Similar concerns apply to setting up storage needed for, e.g. + * memoizing charsets. + */ + ctxt->stream = LLVMBuildBitCast(ctxt->builder, LLVMGetFirstParam(ctxt->func), + ctxt->llvm_inputstreamptr, "stream"); + ctxt->arena = LLVMGetLastParam(ctxt->func); + // Translate the contents of the children of `parser` into their LLVM instruction equivalents - if (parser->vtable->llvm(mm__, builder, parse_func, mod, parser->env)) { + if (parser->vtable->llvm(ctxt, parser->env)) { // But first, verification char *error = NULL; - LLVMVerifyModule(mod, LLVMAbortProcessAction, &error); + LLVMVerifyModule(ctxt->mod, LLVMAbortProcessAction, &error); LLVMDisposeMessage(error); error = NULL; // OK, link that sonofabitch @@ -109,20 +134,21 @@ int h_llvm_compile(HAllocator* mm__, HParser* parser, const void* params) { LLVMInitializeNativeTarget(); LLVMInitializeNativeAsmPrinter(); LLVMExecutionEngineRef engine = NULL; - LLVMCreateExecutionEngineForModule(&engine, mod, &error); + LLVMCreateExecutionEngineForModule(&engine, ctxt->mod, &error); if (error) { fprintf(stderr, "error: %s\n", error); LLVMDisposeMessage(error); return -1; } - char* dump = LLVMPrintModuleToString(mod); + char* dump = LLVMPrintModuleToString(ctxt->mod); fprintf(stderr, "\n\n%s\n\n", dump); // 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; + llvm_parser->mod = ctxt->mod; + llvm_parser->func = ctxt->func; llvm_parser->engine = engine; - llvm_parser->builder = builder; + llvm_parser->builder = ctxt->builder; + llvm_parser->compile_ctxt = ctxt; parser->backend_data = llvm_parser; return 0; } else { @@ -131,10 +157,16 @@ int h_llvm_compile(HAllocator* mm__, HParser* parser, const void* params) { } void h_llvm_free(HParser *parser) { + HAllocator *mm__; HLLVMParser *llvm_parser = parser->backend_data; LLVMModuleRef mod_out; char *err_out; + mm__ = llvm_parser->compile_ctxt->mm__; + h_free(llvm_parser->compile_ctxt); + llvm_parser->compile_ctxt = NULL; + mm__ = NULL; + llvm_parser->func = NULL; LLVMRemoveModule(llvm_parser->engine, llvm_parser->mod, &mod_out, &err_out); LLVMDisposeExecutionEngine(llvm_parser->engine); @@ -161,17 +193,17 @@ void h_llvm_free(HParser *parser) { * TODO actually support TT_SINT, inputs other than 8 bit */ -void h_llvm_make_tt_suint(LLVMModuleRef mod, LLVMBuilderRef builder, - LLVMValueRef stream, LLVMValueRef arena, +void h_llvm_make_tt_suint(HLLVMParserCompileContext *ctxt, LLVMValueRef r, LLVMValueRef *mr_out) { /* Set up call to h_arena_malloc() for a new HParsedToken */ LLVMValueRef tok_size = LLVMConstInt(LLVMInt32Type(), sizeof(HParsedToken), 0); - LLVMValueRef amalloc_args[] = { arena, tok_size }; + LLVMValueRef amalloc_args[] = { ctxt->arena, tok_size }; /* %h_arena_malloc = call void* @h_arena_malloc(%struct.HArena_.1* %1, i32 48) */ - LLVMValueRef amalloc = LLVMBuildCall(builder, LLVMGetNamedFunction(mod, "h_arena_malloc"), + LLVMValueRef amalloc = LLVMBuildCall(ctxt->builder, + LLVMGetNamedFunction(ctxt->mod, "h_arena_malloc"), amalloc_args, 2, "h_arena_malloc"); /* %tok = bitcast void* %h_arena_malloc to %struct.HParsedToken_.2* */ - LLVMValueRef tok = LLVMBuildBitCast(builder, amalloc, llvm_parsedtokenptr, "tok"); + LLVMValueRef tok = LLVMBuildBitCast(ctxt->builder, amalloc, ctxt->llvm_parsedtokenptr, "tok"); /* * tok->token_type = TT_UINT; @@ -180,45 +212,46 @@ void h_llvm_make_tt_suint(LLVMModuleRef mod, LLVMBuilderRef builder, * * TODO if we handle TT_SINT too, adjust here and the zero-ext below */ - LLVMValueRef toktype = LLVMBuildStructGEP(builder, tok, 0, "token_type"); + LLVMValueRef toktype = LLVMBuildStructGEP(ctxt->builder, tok, 0, "token_type"); /* store i32 8, i32* %token_type */ - LLVMBuildStore(builder, LLVMConstInt(LLVMInt32Type(), 8, 0), toktype); + LLVMBuildStore(ctxt->builder, LLVMConstInt(LLVMInt32Type(), 8, 0), toktype); /* * tok->uint = r; * * %token_data = getelementptr inbounds %struct.HParsedToken_.2, %struct.HParsedToken_.2* %3, i32 0, i32 1 */ - LLVMValueRef tokdata = LLVMBuildStructGEP(builder, tok, 1, "token_data"); + LLVMValueRef tokdata = LLVMBuildStructGEP(ctxt->builder, tok, 1, "token_data"); /* * TODO * * This is where we'll need to adjust to handle other types (sign vs. zero extend, omit extend if * r is 64-bit already */ - LLVMBuildStore(builder, LLVMBuildZExt(builder, r, LLVMInt64Type(), "r"), tokdata); + LLVMBuildStore(ctxt->builder, LLVMBuildZExt(ctxt->builder, r, LLVMInt64Type(), "r"), tokdata); /* * Store the index from the stream into the token */ /* %t_index = getelementptr inbounds %struct.HParsedToken_.2, %struct.HParsedToken_.2* %3, i32 0, i32 2 */ - LLVMValueRef tokindex = LLVMBuildStructGEP(builder, tok, 2, "t_index"); + LLVMValueRef tokindex = LLVMBuildStructGEP(ctxt->builder, tok, 2, "t_index"); /* %s_index = getelementptr inbounds %struct.HInputStream_.0, %struct.HInputStream_.0* %0, i32 0, i32 2 */ - LLVMValueRef streamindex = LLVMBuildStructGEP(builder, stream, 2, "s_index"); + LLVMValueRef streamindex = LLVMBuildStructGEP(ctxt->builder, ctxt->stream, 2, "s_index"); /* %4 = load i64, i64* %s_index */ /* store i64 %4, i64* %t_index */ - LLVMBuildStore(builder, LLVMBuildLoad(builder, streamindex, ""), tokindex); + LLVMBuildStore(ctxt->builder, LLVMBuildLoad(ctxt->builder, streamindex, ""), tokindex); /* Store the bit length into the token */ - LLVMValueRef tokbitlen = LLVMBuildStructGEP(builder, tok, 3, "bit_length"); + LLVMValueRef tokbitlen = LLVMBuildStructGEP(ctxt->builder, tok, 3, "bit_length"); /* TODO handle multiple bit lengths */ - LLVMBuildStore(builder, LLVMConstInt(LLVMInt64Type(), 8, 0), tokbitlen); + LLVMBuildStore(ctxt->builder, LLVMConstInt(LLVMInt64Type(), 8, 0), tokbitlen); /* * Now call make_result() * * %make_result = call %struct.HParseResult_.3* @make_result(%struct.HArena_.1* %1, %struct.HParsedToken_.2* %3) */ - LLVMValueRef result_args[] = { arena, tok }; - LLVMValueRef mr = LLVMBuildCall(builder, LLVMGetNamedFunction(mod, "make_result"), + LLVMValueRef result_args[] = { ctxt->arena, tok }; + LLVMValueRef mr = LLVMBuildCall(ctxt->builder, + LLVMGetNamedFunction(ctxt->mod, "make_result"), result_args, 2, "make_result"); *mr_out = mr; diff --git a/src/backends/llvm/llvm.h b/src/backends/llvm/llvm.h index a05693bc3035ab7c9a2f0f6e0328e5c2a236a4c6..900f53ff337d664d77b73a0974ca3c1b26c58cbe 100644 --- a/src/backends/llvm/llvm.h +++ b/src/backends/llvm/llvm.h @@ -10,15 +10,33 @@ #include <llvm-c/Core.h> #pragma GCC diagnostic pop -LLVMTypeRef llvm_inputstream, llvm_inputstreamptr, llvm_arena, llvm_arenaptr; -LLVMTypeRef llvm_parsedtoken, llvm_parsedtokenptr, llvm_parseresult, llvm_parseresultptr; +/* The typedef is in internal.h */ -bool h_llvm_make_charset_membership_test(HAllocator* mm__, - LLVMModuleRef mod, LLVMValueRef func, LLVMBuilderRef builder, +struct HLLVMParserCompileContext_ { + /* Allocator */ + HAllocator* mm__; + /* Module/function/builder */ + LLVMModuleRef mod; + LLVMValueRef func; + LLVMBuilderRef builder; + /* Typerefs */ + LLVMTypeRef llvm_inputstream; + LLVMTypeRef llvm_inputstreamptr; + LLVMTypeRef llvm_arena; + LLVMTypeRef llvm_arenaptr; + LLVMTypeRef llvm_parsedtoken; + LLVMTypeRef llvm_parsedtokenptr; + LLVMTypeRef llvm_parseresult; + LLVMTypeRef llvm_parseresultptr; + /* Set up in function preamble */ + LLVMValueRef stream; + LLVMValueRef arena; +}; + +bool h_llvm_make_charset_membership_test(HLLVMParserCompileContext *ctxt, LLVMValueRef r, HCharset cs, LLVMBasicBlockRef yes, LLVMBasicBlockRef no); -void h_llvm_make_tt_suint(LLVMModuleRef mod, LLVMBuilderRef builder, - LLVMValueRef stream, LLVMValueRef arena, +void h_llvm_make_tt_suint(HLLVMParserCompileContext *ctxt, LLVMValueRef r, LLVMValueRef *mr_out); #endif // #ifndef HAMMER_LLVM__H diff --git a/src/backends/llvm/llvm_charset.c b/src/backends/llvm/llvm_charset.c index 8b598ba4c19ef9825fbba7d80d993fc915b414c4..56e3e80c1d421f37d6bf32bd5a1ba20e393d6676 100644 --- a/src/backends/llvm/llvm_charset.c +++ b/src/backends/llvm/llvm_charset.c @@ -797,18 +797,18 @@ static void h_llvm_pretty_print_charset_exec_plan(HAllocator *mm__, llvm_charset } /* Forward declares for IR-emission functions */ -static bool h_llvm_build_ir_for_bitmap(LLVMModuleRef mod, LLVMValueRef func, LLVMBuilderRef builder, +static bool h_llvm_build_ir_for_bitmap(HLLVMParserCompileContext *ctxt, HCharset cs, uint8_t idx_start, uint8_t idx_end, LLVMValueRef r, LLVMBasicBlockRef in, LLVMBasicBlockRef yes, LLVMBasicBlockRef no); -static bool h_llvm_build_ir_for_scan(LLVMModuleRef mod, LLVMValueRef func, LLVMBuilderRef builder, +static bool h_llvm_build_ir_for_scan(HLLVMParserCompileContext *ctxt, HCharset cs, uint8_t idx_start, uint8_t idx_end, LLVMValueRef r, LLVMBasicBlockRef in, LLVMBasicBlockRef yes, LLVMBasicBlockRef no); -static bool h_llvm_build_ir_for_split(LLVMModuleRef mod, LLVMValueRef func, LLVMBuilderRef builder, +static bool h_llvm_build_ir_for_split(HLLVMParserCompileContext *ctxt, llvm_charset_exec_plan_t *cep, LLVMValueRef r, LLVMBasicBlockRef in, LLVMBasicBlockRef yes, LLVMBasicBlockRef no); -static bool h_llvm_cep_to_ir(LLVMModuleRef mod, LLVMValueRef func, LLVMBuilderRef builder, +static bool h_llvm_cep_to_ir(HLLVMParserCompileContext *ctxt, LLVMValueRef r, llvm_charset_exec_plan_t *cep, LLVMBasicBlockRef in, LLVMBasicBlockRef yes, LLVMBasicBlockRef no); @@ -816,7 +816,7 @@ static bool h_llvm_cep_to_ir(LLVMModuleRef mod, LLVMValueRef func, LLVMBuilderRe * Build IR for a CHARSET_ACTION_BITMAP */ -static bool h_llvm_build_ir_for_bitmap(LLVMModuleRef mod, LLVMValueRef func, LLVMBuilderRef builder, +static bool h_llvm_build_ir_for_bitmap(HLLVMParserCompileContext *ctxt, HCharset cs, uint8_t idx_start, uint8_t idx_end, LLVMValueRef r, LLVMBasicBlockRef in, LLVMBasicBlockRef yes, LLVMBasicBlockRef no) { @@ -824,6 +824,7 @@ static bool h_llvm_build_ir_for_bitmap(LLVMModuleRef mod, LLVMValueRef func, LLV uint32_t bitmap_entry; if (!cs) return false; + if (!ctxt) return false; if (idx_start > idx_end) return false; /* @@ -832,7 +833,7 @@ static bool h_llvm_build_ir_for_bitmap(LLVMModuleRef mod, LLVMValueRef func, LLV * from the low-order 5 bits of the input value. & the mask with the bitmap * byte, and compare. If non-zero, accept, otherwise reject. */ - LLVMPositionBuilderAtEnd(builder, in); + LLVMPositionBuilderAtEnd(ctxt->builder, in); /* Construct the bitmap */ LLVMValueRef bitmap_entries[8]; @@ -855,11 +856,11 @@ static bool h_llvm_build_ir_for_bitmap(LLVMModuleRef mod, LLVMValueRef func, LLV /* Now make an array out of them */ LLVMValueRef bitmap_initializer = LLVMConstArray(LLVMInt32Type(), bitmap_entries, 8); /* ...and we need a global variable to stick it in to GEP it */ - LLVMValueRef bitmap = LLVMAddGlobal(mod, LLVMTypeOf(bitmap_initializer), "bitmap"); + LLVMValueRef bitmap = LLVMAddGlobal(ctxt->mod, LLVMTypeOf(bitmap_initializer), "bitmap"); LLVMSetInitializer(bitmap, bitmap_initializer); /* Compute the index into the bitmap */ - LLVMValueRef word_index = LLVMBuildLShr(builder, r, + LLVMValueRef word_index = LLVMBuildLShr(ctxt->builder, r, LLVMConstInt(LLVMInt8Type(), 5, 0), "word_index"); /* Get a pointer to that word in the bitmap */ @@ -867,28 +868,28 @@ static bool h_llvm_build_ir_for_bitmap(LLVMModuleRef mod, LLVMValueRef func, LLV gep_indices[0] = LLVMConstInt(LLVMInt32Type(), 0, 0); gep_indices[1] = word_index; LLVMValueRef bitmap_word_p = - LLVMBuildInBoundsGEP(builder, bitmap, gep_indices, 2, "bitmap_word_p"); + LLVMBuildInBoundsGEP(ctxt->builder, bitmap, gep_indices, 2, "bitmap_word_p"); LLVMValueRef bitmap_word = - LLVMBuildLoad(builder, bitmap_word_p, "bitmap_word"); + LLVMBuildLoad(ctxt->builder, bitmap_word_p, "bitmap_word"); /* * Extract the low-order 5 bits of r, and expand to a 32-bit int for the * mask */ - LLVMValueRef bit_index = LLVMBuildAnd(builder, r, + LLVMValueRef bit_index = LLVMBuildAnd(ctxt->builder, r, LLVMConstInt(LLVMInt8Type(), 0x1f, 0), "bit_index"); - LLVMValueRef bit_index_zext = LLVMBuildZExt(builder, bit_index, + LLVMValueRef bit_index_zext = LLVMBuildZExt(ctxt->builder, bit_index, LLVMInt32Type(), "bit_index_zext"); /* Compute mask */ - LLVMValueRef mask = LLVMBuildShl(builder, LLVMConstInt(LLVMInt32Type(), 1, 0), + LLVMValueRef mask = LLVMBuildShl(ctxt->builder, LLVMConstInt(LLVMInt32Type(), 1, 0), bit_index_zext, "mask"); /* AND the mask with the bitmap word */ - LLVMValueRef masked_bitmap_word = LLVMBuildAnd(builder, bitmap_word, mask, + LLVMValueRef masked_bitmap_word = LLVMBuildAnd(ctxt->builder, bitmap_word, mask, "masked_bitmap_word"); /* Compare it to zero */ - LLVMValueRef bitmap_icmp = LLVMBuildICmp(builder, LLVMIntNE, + LLVMValueRef bitmap_icmp = LLVMBuildICmp(ctxt->builder, LLVMIntNE, masked_bitmap_word, LLVMConstInt(LLVMInt32Type(), 0, 0), "bitmap_icmp"); /* If not zero, the char is in the set */ - LLVMBuildCondBr(builder, bitmap_icmp, yes, no); + LLVMBuildCondBr(ctxt->builder, bitmap_icmp, yes, no); return true; } @@ -897,33 +898,34 @@ static bool h_llvm_build_ir_for_bitmap(LLVMModuleRef mod, LLVMValueRef func, LLV * Build IR for a CHARSET_ACTION_SCAN */ -static bool h_llvm_build_ir_for_scan(LLVMModuleRef mod, LLVMValueRef func, LLVMBuilderRef builder, +static bool h_llvm_build_ir_for_scan(HLLVMParserCompileContext *ctxt, HCharset cs, uint8_t idx_start, uint8_t idx_end, LLVMValueRef r, LLVMBasicBlockRef in, LLVMBasicBlockRef yes, LLVMBasicBlockRef no) { if (!cs) return false; + if (!ctxt) return false; if (idx_start > idx_end) return false; /* * Scan the range of indices, and for each thing in the charset, * compare and conditional branch. */ - LLVMPositionBuilderAtEnd(builder, in); + LLVMPositionBuilderAtEnd(ctxt->builder, in); for (int i = idx_start; i <= idx_end; ++i) { if (charset_isset(cs, i)) { char bbname[16]; uint8_t c = (uint8_t)i; snprintf(bbname, 16, "cs_memb_%02x", c); - LLVMValueRef icmp = LLVMBuildICmp(builder, LLVMIntEQ, + LLVMValueRef icmp = LLVMBuildICmp(ctxt->builder, LLVMIntEQ, LLVMConstInt(LLVMInt8Type(), c, 0), r, "c == r"); - LLVMBasicBlockRef bb = LLVMAppendBasicBlock(func, bbname); - LLVMBuildCondBr(builder, icmp, yes, bb); - LLVMPositionBuilderAtEnd(builder, bb); + LLVMBasicBlockRef bb = LLVMAppendBasicBlock(ctxt->func, bbname); + LLVMBuildCondBr(ctxt->builder, icmp, yes, bb); + LLVMPositionBuilderAtEnd(ctxt->builder, bb); } } - LLVMBuildBr(builder, no); + LLVMBuildBr(ctxt->builder, no); return true; } @@ -932,13 +934,14 @@ static bool h_llvm_build_ir_for_scan(LLVMModuleRef mod, LLVMValueRef func, LLVMB * Build IR for a CHARSET_ACTION_SPLIT */ -static bool h_llvm_build_ir_for_split(LLVMModuleRef mod, LLVMValueRef func, LLVMBuilderRef builder, +static bool h_llvm_build_ir_for_split(HLLVMParserCompileContext *ctxt, llvm_charset_exec_plan_t *cep, LLVMValueRef r, LLVMBasicBlockRef in, LLVMBasicBlockRef yes, LLVMBasicBlockRef no) { char name[18]; bool left_ok, right_ok; /* Split validation */ + if (!ctxt) return false; if (!cep) return false; if (cep->action != CHARSET_ACTION_SPLIT) return false; if (cep->idx_start >= cep->idx_end) return false; @@ -955,21 +958,21 @@ static bool h_llvm_build_ir_for_split(LLVMModuleRef mod, LLVMValueRef func, LLVM * child if <=, right child if >. */ snprintf(name, 18, "cs_split_left_%02X", cep->split_point); - LLVMBasicBlockRef left = LLVMAppendBasicBlock(func, name); + LLVMBasicBlockRef left = LLVMAppendBasicBlock(ctxt->func, name); snprintf(name, 18, "cs_split_right_%02X", cep->split_point); - LLVMBasicBlockRef right = LLVMAppendBasicBlock(func, name); - LLVMPositionBuilderAtEnd(builder, in); + LLVMBasicBlockRef right = LLVMAppendBasicBlock(ctxt->func, name); + LLVMPositionBuilderAtEnd(ctxt->builder, in); snprintf(name, 18, "r <= %02X", cep->split_point); - LLVMValueRef icmp = LLVMBuildICmp(builder, LLVMIntULE, + LLVMValueRef icmp = LLVMBuildICmp(ctxt->builder, LLVMIntULE, r, LLVMConstInt(LLVMInt8Type(), cep->split_point, 0), name); - LLVMBuildCondBr(builder, icmp, left, right); + LLVMBuildCondBr(ctxt->builder, icmp, left, right); /* * Now build the subtrees starting from each of the output basic blocks * of the comparison. */ - left_ok = h_llvm_cep_to_ir(mod, func, builder, r, cep->children[0], left, yes, no); - right_ok = h_llvm_cep_to_ir(mod, func, builder, r, cep->children[1], right, yes, no); + left_ok = h_llvm_cep_to_ir(ctxt, r, cep->children[0], left, yes, no); + right_ok = h_llvm_cep_to_ir(ctxt, r, cep->children[1], right, yes, no); return left_ok && right_ok; } @@ -978,34 +981,35 @@ static bool h_llvm_build_ir_for_split(LLVMModuleRef mod, LLVMValueRef func, LLVM * Turn an llvm_charset_exec_plan_t into IR */ -static bool h_llvm_cep_to_ir(LLVMModuleRef mod, LLVMValueRef func, LLVMBuilderRef builder, +static bool h_llvm_cep_to_ir(HLLVMParserCompileContext *ctxt, LLVMValueRef r, llvm_charset_exec_plan_t *cep, LLVMBasicBlockRef in, LLVMBasicBlockRef yes, LLVMBasicBlockRef no) { bool rv; + if (!ctxt) return false; if (!cep) return false; switch (cep->action) { case CHARSET_ACTION_SCAN: - rv = h_llvm_build_ir_for_scan(mod, func, builder, - cep->cs, cep->idx_start, cep->idx_end, r, in, yes, no); + rv = h_llvm_build_ir_for_scan(ctxt, cep->cs, + cep->idx_start, cep->idx_end, r, in, yes, no); break; case CHARSET_ACTION_ACCEPT: /* Easy case; just unconditionally branch to the yes output */ - LLVMPositionBuilderAtEnd(builder, in); - LLVMBuildBr(builder, yes); + LLVMPositionBuilderAtEnd(ctxt->builder, in); + LLVMBuildBr(ctxt->builder, yes); rv = true; break; case CHARSET_ACTION_BITMAP: - rv = h_llvm_build_ir_for_bitmap(mod, func, builder, - cep->cs, cep->idx_start, cep->idx_end, r, in, yes, no); + rv = h_llvm_build_ir_for_bitmap(ctxt, cep->cs, + cep->idx_start, cep->idx_end, r, in, yes, no); break; case CHARSET_ACTION_COMPLEMENT: /* This is trivial; just swap the 'yes' and 'no' outputs and build the child */ - rv = h_llvm_cep_to_ir(mod, func, builder, r, cep->children[0], in, no, yes); + rv = h_llvm_cep_to_ir(ctxt, r, cep->children[0], in, no, yes); break; case CHARSET_ACTION_SPLIT: - rv = h_llvm_build_ir_for_split(mod, func, builder, cep, r, in, yes, no); + rv = h_llvm_build_ir_for_split(ctxt, cep, r, in, yes, no); break; default: /* Unknown action type */ @@ -1037,8 +1041,7 @@ static bool h_llvm_cep_to_ir(LLVMModuleRef mod, LLVMValueRef func, LLVMBuilderRe * Returns: true on success, false on failure */ -bool h_llvm_make_charset_membership_test(HAllocator* mm__, - LLVMModuleRef mod, LLVMValueRef func, LLVMBuilderRef builder, +bool h_llvm_make_charset_membership_test(HLLVMParserCompileContext *ctxt, LLVMValueRef r, HCharset cs, LLVMBasicBlockRef yes, LLVMBasicBlockRef no) { /* @@ -1055,8 +1058,12 @@ bool h_llvm_make_charset_membership_test(HAllocator* mm__, * and then transforming the tree into IR. */ + HAllocator *mm__; bool rv; + if (!ctxt) return false; + mm__ = ctxt->mm__; + /* Try building a charset exec plan */ llvm_charset_exec_plan_t *cep = h_llvm_build_charset_exec_plan(mm__, cs); if (!cep) { @@ -1092,14 +1099,14 @@ bool h_llvm_make_charset_membership_test(HAllocator* mm__, */ /* Create input block */ - LLVMBasicBlockRef start = LLVMAppendBasicBlock(func, "cs_start"); + LLVMBasicBlockRef start = LLVMAppendBasicBlock(ctxt->func, "cs_start"); /* * Make unconditional branch into input block from wherever our caller * had us positioned. */ - LLVMBuildBr(builder, start); + LLVMBuildBr(ctxt->builder, start); - rv = h_llvm_cep_to_ir(mod, func, builder, r, cep, start, yes, no); + rv = h_llvm_cep_to_ir(ctxt, r, cep, start, yes, no); h_llvm_free_charset_exec_plan(mm__, cep); cep = NULL; diff --git a/src/internal.h b/src/internal.h index d02245988f83ad7d3d1aa65c0a24e42fa4aa6d27..2b2d6004266680b5a4a8ae7d20da80506d7082da 100644 --- a/src/internal.h +++ b/src/internal.h @@ -491,6 +491,10 @@ struct HCFSequence_ { HCFChoice **items; // last one is NULL }; +#ifdef HAMMER_LLVM_BACKEND +typedef struct HLLVMParserCompileContext_ HLLVMParserCompileContext; +#endif + struct HParserVtable_ { HParseResult* (*parse)(void *env, HParseState *state); bool (*isValidRegular)(void *env); @@ -498,7 +502,7 @@ struct HParserVtable_ { 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); #ifdef HAMMER_LLVM_BACKEND - bool (*llvm)(HAllocator *mm__, LLVMBuilderRef builder, LLVMValueRef func, LLVMModuleRef mod, void *env); + bool (*llvm)(HLLVMParserCompileContext *ctxt, void *env); #endif bool higher; // false if primitive }; diff --git a/src/parsers/bits.c b/src/parsers/bits.c index d8c90dda80730946dab7964ebe7281414a4c1343..159a20ddee6e41fc52d1e66b95c4ae039c623af6 100644 --- a/src/parsers/bits.c +++ b/src/parsers/bits.c @@ -26,13 +26,13 @@ static HParseResult* parse_bits(void* env, HParseState *state) { #ifdef HAMMER_LLVM_BACKEND -static bool bits_llvm(HAllocator *mm__, - LLVMBuilderRef builder, LLVMValueRef func, LLVMModuleRef mod, - void* env) { +static bool bits_llvm(HLLVMParserCompileContext *ctxt, void* env) { + if (!ctxt) return false; + /* %result = alloca %struct.HParsedToken_*, align 8 */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-variable" - LLVMValueRef result = LLVMBuildAlloca(builder, llvm_parsedtoken, "result"); + LLVMValueRef result = LLVMBuildAlloca(ctxt->builder, ctxt->llvm_parsedtoken, "result"); #pragma GCC diagnostic pop /* store i8* %env, i8** %1, align 8 */ /* store %struct.HParseState_* %state, %struct.HParseState_** %2, align 8 */ diff --git a/src/parsers/ch.c b/src/parsers/ch.c index 63067ba9767f90e9a91d9667466b364cecc0cec6..2a46ae16be33eea2017ec73e2fc4ab30cf3cbe7b 100644 --- a/src/parsers/ch.c +++ b/src/parsers/ch.c @@ -50,67 +50,67 @@ static bool ch_ctrvm(HRVMProg *prog, void* env) { #ifdef HAMMER_LLVM_BACKEND -static bool ch_llvm(HAllocator *mm__, LLVMBuilderRef builder, LLVMValueRef func, LLVMModuleRef mod, void* env) { +static bool ch_llvm(HLLVMParserCompileContext *ctxt, void* env) { // Build a new LLVM function to parse a character // Set up params for calls to h_read_bits() and h_arena_malloc() LLVMValueRef bits_args[3]; - LLVMValueRef stream = LLVMGetFirstParam(func); - stream = LLVMBuildBitCast(builder, stream, llvm_inputstreamptr, "stream"); - bits_args[0] = stream; + bits_args[0] = ctxt->stream; bits_args[1] = LLVMConstInt(LLVMInt32Type(), 8, 0); bits_args[2] = LLVMConstInt(LLVMInt8Type(), 0, 0); - LLVMValueRef arena = LLVMGetLastParam(func); // Set up basic blocks: entry, success and failure branches, then exit - LLVMBasicBlockRef entry = LLVMAppendBasicBlock(func, "ch_entry"); - LLVMBasicBlockRef success = LLVMAppendBasicBlock(func, "ch_success"); - LLVMBasicBlockRef end = LLVMAppendBasicBlock(func, "ch_end"); + LLVMBasicBlockRef entry = LLVMAppendBasicBlock(ctxt->func, "ch_entry"); + LLVMBasicBlockRef success = LLVMAppendBasicBlock(ctxt->func, "ch_success"); + LLVMBasicBlockRef end = LLVMAppendBasicBlock(ctxt->func, "ch_end"); // Basic block: entry - LLVMPositionBuilderAtEnd(builder, entry); + LLVMBuildBr(ctxt->builder, entry); + LLVMPositionBuilderAtEnd(ctxt->builder, entry); // Call to h_read_bits() // %read_bits = call i64 @h_read_bits(%struct.HInputStream_* %8, i32 8, i8 signext 0) - LLVMValueRef bits = LLVMBuildCall(builder, LLVMGetNamedFunction(mod, "h_read_bits"), bits_args, 3, "read_bits"); + LLVMValueRef bits = LLVMBuildCall(ctxt->builder, + LLVMGetNamedFunction(ctxt->mod, "h_read_bits"), bits_args, 3, "read_bits"); // %2 = trunc i64 %read_bits to i8 - LLVMValueRef r = LLVMBuildTrunc(builder, bits, LLVMInt8Type(), ""); // do we actually need this? + LLVMValueRef r = LLVMBuildTrunc(ctxt->builder, + bits, LLVMInt8Type(), ""); // do we actually need this? // Check if h_read_bits succeeded // %"c == r" = icmp eq i8 -94, %2 ; the -94 comes from c_ uint8_t c_ = (uint8_t)(uintptr_t)(env); LLVMValueRef c = LLVMConstInt(LLVMInt8Type(), c_, 0); - LLVMValueRef icmp = LLVMBuildICmp(builder, LLVMIntEQ, c, r, "c == r"); + LLVMValueRef icmp = LLVMBuildICmp(ctxt->builder, LLVMIntEQ, c, r, "c == r"); // Branch so success or failure basic block, as appropriate // br i1 %"c == r", label %ch_success, label %ch_fail - LLVMBuildCondBr(builder, icmp, success, end); + LLVMBuildCondBr(ctxt->builder, icmp, success, end); // Basic block: success - LLVMPositionBuilderAtEnd(builder, success); + LLVMPositionBuilderAtEnd(ctxt->builder, success); /* Make a token */ LLVMValueRef mr; - h_llvm_make_tt_suint(mod, builder, stream, arena, r, &mr); + h_llvm_make_tt_suint(ctxt, r, &mr); // br label %ch_end - LLVMBuildBr(builder, end); + LLVMBuildBr(ctxt->builder, end); // Basic block: end - LLVMPositionBuilderAtEnd(builder, end); + LLVMPositionBuilderAtEnd(ctxt->builder, end); // %rv = phi %struct.HParseResult_.3* [ %make_result, %ch_success ], [ null, %ch_entry ] - LLVMValueRef rv = LLVMBuildPhi(builder, llvm_parseresultptr, "rv"); + LLVMValueRef rv = LLVMBuildPhi(ctxt->builder, ctxt->llvm_parseresultptr, "rv"); LLVMBasicBlockRef rv_phi_incoming_blocks[] = { success, entry }; LLVMValueRef rv_phi_incoming_values[] = { mr, - LLVMConstNull(llvm_parseresultptr) + LLVMConstNull(ctxt->llvm_parseresultptr) }; LLVMAddIncoming(rv, rv_phi_incoming_values, rv_phi_incoming_blocks, 2); // ret %struct.HParseResult_.3* %rv - LLVMBuildRet(builder, rv); + LLVMBuildRet(ctxt->builder, rv); return true; } diff --git a/src/parsers/charset.c b/src/parsers/charset.c index 5870fc2ce095a8ba32d20d99c0fb97003feca390..08b45f280be9d0c8d717dd0bac3126a2d3c50da6 100644 --- a/src/parsers/charset.c +++ b/src/parsers/charset.c @@ -79,72 +79,72 @@ static bool cs_ctrvm(HRVMProg *prog, void *env) { #ifdef HAMMER_LLVM_BACKEND -static bool cs_llvm(HAllocator *mm__, LLVMBuilderRef builder, LLVMValueRef func, - LLVMModuleRef mod, void* env) { +static bool cs_llvm(HLLVMParserCompileContext *ctxt, void* env) { /* * LLVM to build a function to parse a charset; the args are a stream and an * arena. */ bool ok; - LLVMValueRef stream = LLVMGetFirstParam(func); - stream = LLVMBuildBitCast(builder, stream, llvm_inputstreamptr, "stream"); - LLVMValueRef arena = LLVMGetLastParam(func); + if (!ctxt) return false; /* Set up our basic blocks */ - LLVMBasicBlockRef entry = LLVMAppendBasicBlock(func, "cs_entry"); - LLVMBasicBlockRef success = LLVMAppendBasicBlock(func, "cs_success"); - LLVMBasicBlockRef fail = LLVMAppendBasicBlock(func, "cs_fail"); - LLVMBasicBlockRef end = LLVMAppendBasicBlock(func, "cs_end"); + LLVMBasicBlockRef entry = LLVMAppendBasicBlock(ctxt->func, "cs_entry"); + LLVMBasicBlockRef success = LLVMAppendBasicBlock(ctxt->func, "cs_success"); + LLVMBasicBlockRef fail = LLVMAppendBasicBlock(ctxt->func, "cs_fail"); + LLVMBasicBlockRef end = LLVMAppendBasicBlock(ctxt->func, "cs_end"); /* Basic block: entry */ - LLVMPositionBuilderAtEnd(builder, entry); + LLVMBuildBr(ctxt->builder, entry); + LLVMPositionBuilderAtEnd(ctxt->builder, entry); /* First we read the char */ LLVMValueRef bits_args[3]; - bits_args[0] = stream; + bits_args[0] = ctxt->stream; bits_args[1] = LLVMConstInt(LLVMInt32Type(), 8, 0); bits_args[2] = LLVMConstInt(LLVMInt8Type(), 0, 0); - LLVMValueRef bits = LLVMBuildCall(builder, LLVMGetNamedFunction(mod, "h_read_bits"), bits_args, 3, "read_bits"); - LLVMValueRef r = LLVMBuildTrunc(builder, bits, LLVMInt8Type(), ""); // TODO Necessary? (same question in ch_llvm()) + LLVMValueRef bits = LLVMBuildCall(ctxt->builder, + LLVMGetNamedFunction(ctxt->mod, "h_read_bits"), bits_args, 3, "read_bits"); + LLVMValueRef r = + LLVMBuildTrunc(ctxt->builder, bits, LLVMInt8Type(), ""); // TODO Necessary? (same question in ch_llvm()) /* We have a char, need to check if it's in the charset */ HCharset cs = (HCharset)env; /* Branch to either success or end, conditional on whether r is in cs */ - ok = h_llvm_make_charset_membership_test(mm__, mod, func, builder, r, cs, success, fail); + ok = h_llvm_make_charset_membership_test(ctxt, r, cs, success, fail); /* Basic block: success */ - LLVMPositionBuilderAtEnd(builder, success); + LLVMPositionBuilderAtEnd(ctxt->builder, success); LLVMValueRef mr; - h_llvm_make_tt_suint(mod, builder, stream, arena, r, &mr); + h_llvm_make_tt_suint(ctxt, r, &mr); /* br label %ch_end */ - LLVMBuildBr(builder, end); + LLVMBuildBr(ctxt->builder, end); /* Basic block: fail */ - LLVMPositionBuilderAtEnd(builder, fail); + LLVMPositionBuilderAtEnd(ctxt->builder, fail); /* * We just branch straight to end; this exists so that the phi node in * end knows where all the incoming edges are from, rather than needing * some basic block constructed in h_llvm_make_charset_membership_test() */ - LLVMBuildBr(builder, end); + LLVMBuildBr(ctxt->builder, end); /* Basic block: end */ - LLVMPositionBuilderAtEnd(builder, end); + LLVMPositionBuilderAtEnd(ctxt->builder, end); // %rv = phi %struct.HParseResult_.3* [ %make_result, %ch_success ], [ null, %ch_entry ] - LLVMValueRef rv = LLVMBuildPhi(builder, llvm_parseresultptr, "rv"); + LLVMValueRef rv = LLVMBuildPhi(ctxt->builder, ctxt->llvm_parseresultptr, "rv"); LLVMBasicBlockRef rv_phi_incoming_blocks[] = { success, fail }; LLVMValueRef rv_phi_incoming_values[] = { mr, - LLVMConstNull(llvm_parseresultptr) + LLVMConstNull(ctxt->llvm_parseresultptr) }; LLVMAddIncoming(rv, rv_phi_incoming_values, rv_phi_incoming_blocks, 2); // ret %struct.HParseResult_.3* %rv - LLVMBuildRet(builder, rv); + LLVMBuildRet(ctxt->builder, rv); return ok; }