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 4c4e7c4694be1c7bcd453a124817c6c2c1d6361a..893f7a6cb891f635084ff959a2e234ca19bb5e23 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;
 }