From 8dcb3fed548dbb8c25aa9958e9b683af574b6782 Mon Sep 17 00:00:00 2001
From: "Meredith L. Patterson" <mlp@thesmartpolitenerd.com>
Date: Wed, 24 Feb 2016 06:52:30 +0100
Subject: [PATCH] converting the simplest combinators to LLVM IR

---
 src/parsers/bits.c |  69 ++++++++++++++++++++++++++++++
 src/parsers/ch.c   | 104 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 173 insertions(+)

diff --git a/src/parsers/bits.c b/src/parsers/bits.c
index be8f13f1..12823285 100644
--- a/src/parsers/bits.c
+++ b/src/parsers/bits.c
@@ -1,4 +1,5 @@
 #include <assert.h>
+#include <llvm-c/Core.h>
 #include "parser_internal.h"
 
 struct bits_env {
@@ -17,6 +18,73 @@ static HParseResult* parse_bits(void* env, HParseState *state) {
   return make_result(state->arena, result);
 }
 
+static bool bits_llvm(LLVMBuilderRef builder, LLVMModuleRef mod, void* env) {
+  /*   %result = alloca %struct.HParsedToken_*, align 8 */
+  LLVMValueRef result = LLVMBuildAlloca(builder, LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HParsedToken_"), 0), "result");
+  /*   store i8* %env, i8** %1, align 8 */
+  /*   store %struct.HParseState_* %state, %struct.HParseState_** %2, align 8 */
+  /*   %3 = load i8** %1, align 8 */
+  /*   %4 = bitcast i8* %3 to %struct.bits_env* */
+  /*   store %struct.bits_env* %4, %struct.bits_env** %env, align 8 */
+  /*   %5 = load %struct.HParseState_** %2, align 8 */
+  /*   %6 = getelementptr inbounds %struct.HParseState_* %5, i32 0, i32 2 */
+  /*   %7 = load %struct.HArena_** %6, align 8 */
+  /*   %8 = call noalias i8* @h_arena_malloc(%struct.HArena_* %7, i64 48) */
+  /*   %9 = bitcast i8* %8 to %struct.HParsedToken_* */
+  /*   store %struct.HParsedToken_* %9, %struct.HParsedToken_** %result, align 8 */
+  /*   %10 = load %struct.bits_env** %env_, align 8 */
+  /*   %11 = getelementptr inbounds %struct.bits_env* %10, i32 0, i32 1 */
+  /*   %12 = load i8* %11, align 1 */
+  /*   %13 = zext i8 %12 to i32 */
+  /*   %14 = icmp ne i32 %13, 0 */
+  /*   %15 = select i1 %14, i32 4, i32 8 */
+  /*   %16 = load %struct.HParsedToken_** %result, align 8 */
+  /*   %17 = getelementptr inbounds %struct.HParsedToken_* %16, i32 0, i32 0 */
+  /*   store i32 %15, i32* %17, align 4 */
+  /*   %18 = load %struct.bits_env** %env_, align 8 */
+  /*   %19 = getelementptr inbounds %struct.bits_env* %18, i32 0, i32 1 */
+  /*   %20 = load i8* %19, align 1 */
+  /*   %21 = icmp ne i8 %20, 0 */
+  /*   br i1 %21, label %22, label %33 */
+
+  /* ; <label>:22                                      ; preds = %0 */
+  /*   %23 = load %struct.HParseState_** %2, align 8 */
+  /*   %24 = getelementptr inbounds %struct.HParseState_* %23, i32 0, i32 1 */
+  /*   %25 = load %struct.bits_env** %env_, align 8 */
+  /*   %26 = getelementptr inbounds %struct.bits_env* %25, i32 0, i32 0 */
+  /*   %27 = load i8* %26, align 1 */
+  /*   %28 = zext i8 %27 to i32 */
+  /*   %29 = call i64 @h_read_bits(%struct.HInputStream_* %24, i32 %28, i8 signext 1) */
+  /*   %30 = load %struct.HParsedToken_** %result, align 8 */
+  /*   %31 = getelementptr inbounds %struct.HParsedToken_* %30, i32 0, i32 1 */
+  /*   %32 = bitcast %union.anon* %31 to i64* */
+  /*   store i64 %29, i64* %32, align 8 */
+  /*   br label %44 */
+
+  /* ; <label>:33                                      ; preds = %0 */
+  /*   %34 = load %struct.HParseState_** %2, align 8 */
+  /*   %35 = getelementptr inbounds %struct.HParseState_* %34, i32 0, i32 1 */
+  /*   %36 = load %struct.bits_env** %env_, align 8 */
+  /*   %37 = getelementptr inbounds %struct.bits_env* %36, i32 0, i32 0 */
+  /*   %38 = load i8* %37, align 1 */
+  /*   %39 = zext i8 %38 to i32 */
+  /*   %40 = call i64 @h_read_bits(%struct.HInputStream_* %35, i32 %39, i8 signext 0) */
+  /*   %41 = load %struct.HParsedToken_** %result, align 8 */
+  /*   %42 = getelementptr inbounds %struct.HParsedToken_* %41, i32 0, i32 1 */
+  /*   %43 = bitcast %union.anon* %42 to i64* */
+  /*   store i64 %40, i64* %43, align 8 */
+  /*   br label %44 */
+  
+  /* ; <label>:44                                      ; preds = %33, %22 */
+  /*   %45 = load %struct.HParseState_** %2, align 8 */
+  /*   %46 = getelementptr inbounds %struct.HParseState_* %45, i32 0, i32 2 */
+  /*   %47 = load %struct.HArena_** %46, align 8 */
+  /*   %48 = load %struct.HParsedToken_** %result, align 8 */
+  /*   %49 = call %struct.HParseResult_* @make_result(%struct.HArena_* %47, %struct.HParsedToken_* %48) */
+  /*   ret %struct.HParseResult_* %49 */
+  return true;
+}
+
 static HParsedToken *reshape_bits(const HParseResult *p, void* signedp_p) {
   // signedp == NULL iff unsigned
   bool signedp = (signedp_p != NULL);
@@ -102,6 +170,7 @@ static const HParserVtable bits_vt = {
   .isValidCF = h_true,
   .desugar = desugar_bits,
   .compile_to_rvm = bits_ctrvm,
+  .llvm = bits_llvm,
   .higher = false,
 };
 
diff --git a/src/parsers/ch.c b/src/parsers/ch.c
index 3da1091a..d7743bc9 100644
--- a/src/parsers/ch.c
+++ b/src/parsers/ch.c
@@ -1,5 +1,6 @@
 #include <stdint.h>
 #include <assert.h>
+#include <llvm-c/Core.h>
 #include "parser_internal.h"
 
 static HParseResult* parse_ch(void* env, HParseState *state) {
@@ -41,12 +42,115 @@ static bool ch_ctrvm(HRVMProg *prog, void* env) {
   return true;
 }
 
+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);
+  LLVMValueRef ch = LLVMAddFunction(mod, "ch", ret_type);
+  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");
+  // %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");
+  // %10 = trunc i64 %9 to i8
+  LLVMValueRef tmp = LLVMBuildTrunc(builder, bits, LLVMInt8Type(), "");
+  // store i8 %10, i8* %r, align 1
+  LLVMBuildStore(builder, bits, r);
+  // %11 = load i8* %c
+  // %12 = zext i8 %11 to i32
+  // %13 = load i8* %r, align 1
+  // %14 = zext i8 %13 to i32
+  // %15 = icmp eq i32 %12, %14
+  LLVMValueRef icmp = LLVMBuildICmp(builder, LLVMIntEQ, c, r, "c == r");
+  // br i1 %15, label %16, label %34
+  LLVMBuildCondBr(builder, icmp, success, fail);
+
+  // ; <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");
+  // %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");
+  // %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[] = {
+    LLVMConstInt(LLVMInt32Type(), 0, 0),
+    LLVMConstInt(LLVMInt32Type(), 0, 0)
+  };
+  LLVMValueRef toktype = LLVMBuildInBoundsGEP(builder, tok, bounds3, 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");
+  // %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");
+  // store %struct.HParseResult_* %33, %struct.HParseResult_** %1
+  LLVMBuildStore(builder, mr, ret);
+  // br label %35
+  LLVMBuildBr(builder, end);
+  
+  // ; <label>:34 - failure case
+  LLVMPositionBuilderAtEnd(builder, fail);
+  // store %struct.HParseResult* null, %struct.HParseResult_** %1
+  LLVMBuildStore(builder, LLVMConstNull(LLVMPointerType(LLVMStructCreateNamed(LLVMGetGlobalContext(), "%struct.HParsedToken"), 0)), ret);
+  // br label %35
+  LLVMBuildBr(builder, end);
+
+  // ; <label>:35
+  LLVMPositionBuilderAtEnd(builder, end);
+  // %36 = load %struct.HParseResult_** %1
+  // ret %struct.HParseResult_* %36
+  LLVMBuildRet(builder, ret);
+  return true;
+}
+
 static const HParserVtable ch_vt = {
   .parse = parse_ch,
   .isValidRegular = h_true,
   .isValidCF = h_true,
   .desugar = desugar_ch,
   .compile_to_rvm = ch_ctrvm,
+  .llvm = ch_llvm,
   .higher = false,
 };
 
-- 
GitLab