From fb29356b0abe997ed8ba5ac842202ac0a1c3e532 Mon Sep 17 00:00:00 2001
From: Andrea Shepard <andrea@persephoneslair.org>
Date: Mon, 21 Nov 2016 05:40:49 +0000
Subject: [PATCH] Implement IR generation for CHARSET_ACTION_SPLIT

---
 src/backends/llvm/llvm_charset.c | 69 +++++++++++++++++++++++++++++---
 1 file changed, 63 insertions(+), 6 deletions(-)

diff --git a/src/backends/llvm/llvm_charset.c b/src/backends/llvm/llvm_charset.c
index e2f52b18..87dea54d 100644
--- a/src/backends/llvm/llvm_charset.c
+++ b/src/backends/llvm/llvm_charset.c
@@ -796,6 +796,20 @@ static void h_llvm_pretty_print_charset_exec_plan(HAllocator *mm__, llvm_charset
   h_llvm_pretty_print_charset_exec_plan_impl(mm__, cep, "", "", 0);
 }
 
+/* Forward declares for IR-emission functions */
+static bool h_llvm_build_ir_for_scan(LLVMModuleRef mod, LLVMValueRef func, LLVMBuilderRef builder,
+                                     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(HAllocator *mm__,
+                                      LLVMModuleRef mod, LLVMValueRef func, LLVMBuilderRef builder,
+                                      llvm_charset_exec_plan_t *cep, LLVMValueRef r,
+                                      LLVMBasicBlockRef in, LLVMBasicBlockRef yes, LLVMBasicBlockRef no);
+static bool h_llvm_cep_to_ir(HAllocator* mm__,
+                             LLVMModuleRef mod, LLVMValueRef func, LLVMBuilderRef builder,
+                             LLVMValueRef r, llvm_charset_exec_plan_t *cep,
+                             LLVMBasicBlockRef in, LLVMBasicBlockRef yes, LLVMBasicBlockRef no);
+
 /*
  * Build IR for a CHARSET_ACTION_SCAN
  */
@@ -831,6 +845,53 @@ static bool h_llvm_build_ir_for_scan(LLVMModuleRef mod, LLVMValueRef func, LLVMB
   return true;
 }
 
+/*
+ * Build IR for a CHARSET_ACTION_SPLIT
+ */
+
+static bool h_llvm_build_ir_for_split(HAllocator *mm__,
+                                      LLVMModuleRef mod, LLVMValueRef func, LLVMBuilderRef builder,
+                                      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 (!cep) return false;
+  if (cep->action != CHARSET_ACTION_SPLIT) return false;
+  if (cep->idx_start >= cep->idx_end) return false;
+  if (cep->split_point < cep->idx_start) return false;
+  if (cep->split_point >= cep->idx_end) return false;
+  if (!(cep->children[0] && cep->children[1])) return false;
+  if (cep->idx_start != cep->children[0]->idx_start) return false;
+  if (cep->split_point != cep->children[0]->idx_end) return false;
+  if (cep->split_point + 1 != cep->children[1]->idx_start) return false;
+  if (cep->idx_end != cep->children[1]->idx_end) return false;
+
+  /*
+   * Compare the value against the split point, and branch to the left
+   * child if <=, right child if >.
+   */
+  snprintf(name, 18, "cs_split_left_%02X", cep->split_point);
+  LLVMBasicBlockRef left = LLVMAppendBasicBlock(func, name);
+  snprintf(name, 18, "cs_split_right_%02X", cep->split_point);
+  LLVMBasicBlockRef right = LLVMAppendBasicBlock(func, name);
+  LLVMPositionBuilderAtEnd(builder, in);
+  snprintf(name, 18, "r <= %02X", cep->split_point);
+  LLVMValueRef icmp = LLVMBuildICmp(builder, LLVMIntULE,
+      r, LLVMConstInt(LLVMInt8Type(), cep->split_point, 0), name);
+  LLVMBuildCondBr(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(mm__, mod, func, builder, r, cep->children[0], left, yes, no);
+  right_ok = h_llvm_cep_to_ir(mm__, mod, func, builder, r, cep->children[1], right, yes, no);
+
+  return left_ok && right_ok;
+}
+
 /*
  * Turn an llvm_charset_exec_plan_t into IR
  */
@@ -852,6 +913,7 @@ static bool h_llvm_cep_to_ir(HAllocator* mm__,
       /* Easy case; just unconditionally branch to the yes output */
       LLVMPositionBuilderAtEnd(builder, in);
       LLVMBuildBr(builder, yes);
+      rv = true;
       break;
     case CHARSET_ACTION_BITMAP:
 #ifdef HAMMER_LLVM_CHARSET_DEBUG
@@ -866,12 +928,7 @@ static bool h_llvm_cep_to_ir(HAllocator* mm__,
       rv = h_llvm_cep_to_ir(mm__, mod, func, builder, r, cep->children[0], in, no, yes);
       break;
     case CHARSET_ACTION_SPLIT:
-#ifdef HAMMER_LLVM_CHARSET_DEBUG
-      fprintf(stderr,
-              "CHARSET_ACTION_SPLIT not yet implemented (cep %p)\n",
-              (void *)cep);
-#endif /* defined(HAMMER_LLVM_CHARSET_DEBUG) */
-      rv = false;
+      rv = h_llvm_build_ir_for_split(mm__, mod, func, builder, cep, r, in, yes, no);
       break;
     default:
       /* Unknown action type */
-- 
GitLab