From a340a6fce89f6558f28787945e39ee6764a261db Mon Sep 17 00:00:00 2001
From: "Meredith L. Patterson" <mlp@thesmartpolitenerd.com>
Date: Fri, 29 Apr 2016 00:01:53 +0200
Subject: [PATCH] LLVM test compiles, links, and runs, but does not work.

---
 SConstruct          |  2 +-
 src/SConscript      |  7 +++---
 src/backends/llvm.c | 30 ++++++++++++------------
 src/parsers/ch.c    | 56 +++++++++++++++++++++------------------------
 src/t_parser.c      |  2 ++
 5 files changed, 49 insertions(+), 48 deletions(-)

diff --git a/SConstruct b/SConstruct
index bb2bb858..1ff257ae 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 689c7e03..575cf34c 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 d7904a0e..c4aafb3a 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 d7743bc9..a6822bac 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 c42eca91..17dc9a91 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);
 }
-- 
GitLab