From bf986a167f6270c0220befd9b5a000f7f9d635ac Mon Sep 17 00:00:00 2001
From: Andrea Shepard <andrea@persephoneslair.org>
Date: Tue, 6 Dec 2016 05:24:40 +0000
Subject: [PATCH] Implement looped version of LLVM backend h_token()

---
 src/parsers/token.c | 109 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 108 insertions(+), 1 deletion(-)

diff --git a/src/parsers/token.c b/src/parsers/token.c
index 6f016064..3899abe8 100644
--- a/src/parsers/token.c
+++ b/src/parsers/token.c
@@ -81,7 +81,114 @@ static bool token_ctrvm(HRVMProg *prog, void *env) {
  */
 
 static bool token_llvm_with_global(HLLVMParserCompileContext *ctxt, HToken *t) {
-  /* TODO */
+  LLVMValueRef bits_args[3], bits, i, i_init, i_incr, str, str_const, len;
+  LLVMValueRef r, c, mr, icmp_i_len, icmp_c_r, rv;
+  LLVMValueRef c_gep_indices[2], c_gep;
+  LLVMBasicBlockRef entry, loop_start, loop_middle, loop_incr, success, end;
+
+  /* Set up basic blocks: entry, success and exit branches */
+  entry = LLVMAppendBasicBlock(ctxt->func, "tok_seq_entry");
+  loop_start = LLVMAppendBasicBlock(ctxt->func, "tok_seq_loop_start");
+  loop_middle = LLVMAppendBasicBlock(ctxt->func, "tok_seq_loop_middle");
+  loop_incr = LLVMAppendBasicBlock(ctxt->func, "tok_seq_loop_incr");
+  success = LLVMAppendBasicBlock(ctxt->func, "tok_seq_success");
+  end = LLVMAppendBasicBlock(ctxt->func, "tok_seq_end");
+
+  /* Branch to entry block */
+  LLVMBuildBr(ctxt->builder, entry);
+  LLVMPositionBuilderAtEnd(ctxt->builder, entry);
+
+  /*
+   * Get our string into the globals as a constant; skip the null termination
+   * and save a byte since we can compare to length in the loop.
+   */
+  str_const = LLVMConstString((const char *)(t->str), t->len, 1);
+  str = LLVMAddGlobal(ctxt->mod, LLVMArrayType(LLVMInt8Type(), t->len), "tok_str");
+  LLVMSetLinkage(str, LLVMInternalLinkage);
+  LLVMSetGlobalConstant(str, 1);
+  LLVMSetInitializer(str, str_const);
+
+  /* Have the token length available */
+  len = LLVMConstInt(ctxt->llvm_size_t, t->len, 0);
+
+  /* For each char of token... */
+  bits_args[0] = ctxt->stream;
+  bits_args[1] = LLVMConstInt(LLVMInt32Type(), 8, 0);
+  bits_args[2] = LLVMConstInt(LLVMInt8Type(), 0, 0);
+
+  /* Start the loop */
+  LLVMBuildBr(ctxt->builder, loop_start);
+  LLVMPositionBuilderAtEnd(ctxt->builder, loop_start);
+
+  /* Keep an index counter */
+  i = LLVMBuildPhi(ctxt->builder, ctxt->llvm_size_t, "i");
+  i_init = LLVMConstInt(ctxt->llvm_size_t, 0, 0);
+  /*
+   * We'll need another one once we know the value of i at the end of
+   * the loop
+   */
+  LLVMAddIncoming(i, &i_init, &entry, 1);
+
+  /*
+   * Compare i to token string length (i.e., have we hit the end of the
+   * token?); if ==, branch to success, if <, continue loop.
+   */
+  icmp_i_len = LLVMBuildICmp(ctxt->builder, LLVMIntULT, i, len, "i < len");
+  LLVMBuildCondBr(ctxt->builder, icmp_i_len, loop_middle, success);
+
+  /* Basic block loop_middle */
+  LLVMPositionBuilderAtEnd(ctxt->builder, loop_middle);
+
+  /* Get a char from the token string */
+  c_gep_indices[0] = LLVMConstInt(LLVMInt32Type(), 0, 0);
+  c_gep_indices[1] = i;
+  c_gep = LLVMBuildInBoundsGEP(ctxt->builder, str, c_gep_indices, 2, "c_p");
+  c = LLVMBuildLoad(ctxt->builder, c_gep, "c");
+
+  /* Read one char from input */
+  bits = LLVMBuildCall(ctxt->builder,
+      LLVMGetNamedFunction(ctxt->mod, "h_read_bits"), bits_args, 3, "read_bits");
+  /* Clamp to i8 */
+  r = LLVMBuildTrunc(ctxt->builder, bits, LLVMInt8Type(), "");
+
+  /*
+   * Compare c and r; if !=, token mismatches, break out of loop and
+   * fail.  If ==, increment counter and go to next iteration.
+   */
+  icmp_c_r = LLVMBuildICmp(ctxt->builder, LLVMIntEQ, c, r, "c == r");
+  LLVMBuildCondBr(ctxt->builder, icmp_c_r, loop_incr, end);
+
+  /* Basic block loop_incr */
+  LLVMPositionBuilderAtEnd(ctxt->builder, loop_incr);
+  /* End of loop, 2nd LLVMAddIncoming() for i */
+  i_incr = LLVMBuildAdd(ctxt->builder, i,
+      LLVMConstInt(ctxt->llvm_size_t, 1, 0), "i_incr");
+  LLVMAddIncoming(i, &i_incr, &loop_incr, 1);
+
+  /* Next iteration */
+  LLVMBuildBr(ctxt->builder, loop_start);
+
+  /* Basic block: success */
+  LLVMPositionBuilderAtEnd(ctxt->builder, success);
+  h_llvm_make_tt_bytes_fixed(ctxt, t->str, t->len, &mr);
+  LLVMBuildBr(ctxt->builder, end);
+
+  /* Basic block: end */
+  LLVMPositionBuilderAtEnd(ctxt->builder, end);
+  /* phi the token or a null depending on where we came from */
+  rv = LLVMBuildPhi(ctxt->builder, ctxt->llvm_parseresultptr, "rv");
+  LLVMBasicBlockRef rv_phi_incoming_blocks[] = {
+    success,
+    loop_middle
+  };
+  LLVMValueRef rv_phi_incoming_values[] = {
+    mr,
+    LLVMConstNull(ctxt->llvm_parseresultptr)
+  };
+  LLVMAddIncoming(rv, rv_phi_incoming_values, rv_phi_incoming_blocks, 2);
+  /* Return it */
+  LLVMBuildRet(ctxt->builder, rv);
+
   return true;
 }
 
-- 
GitLab