From 523f4e7335fdbfa20e35edba178cb0de12bb8af2 Mon Sep 17 00:00:00 2001
From: Andrea Shepard <andrea@special-circumstanc.es>
Date: Fri, 15 Nov 2019 22:41:52 +0000
Subject: [PATCH] Implement h_int_range() for LLVM backend

---
 src/parsers/int_range.c | 626 +++++++++++++++++++++++++++++++++++++++-
 src/t_parser.c          |  37 ++-
 2 files changed, 659 insertions(+), 4 deletions(-)

diff --git a/src/parsers/int_range.c b/src/parsers/int_range.c
index 49b06421..8d536f3b 100644
--- a/src/parsers/int_range.c
+++ b/src/parsers/int_range.c
@@ -1,5 +1,12 @@
-#include "parser_internal.h"
+#ifdef HAMMER_LLVM_BACKEND
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpedantic"
+#include <llvm-c/Core.h>
+#pragma GCC diagnostic pop
+#include "../backends/llvm/llvm.h"
+#endif
 
+#include "parser_internal.h"
 
 typedef struct {
   const HParser *p;
@@ -111,12 +118,629 @@ static bool ir_ctrvm(HRVMProg *prog, void *env) {
   return false;
 }
 
+#ifdef HAMMER_LLVM_BACKEND
+
+static bool ir_llvm(HLLVMParserCompileContext *ctxt,
+                    const HParser *p,
+                    LLVMValueRef *res) {
+  /* Build some LLVM IR to parse an intrange */
+
+  /* The allocator */
+  HAllocator *mm__ = NULL;
+  /* Names */
+  char *ir_entry_name = NULL;
+  int ir_entry_name_len = 0;
+  char *ir_check_res_name = NULL;
+  int ir_check_res_name_len = 0;
+  char *ir_check_res_ast_name = NULL;
+  int ir_check_res_ast_name_len = 0;
+  char *ir_check_token_type_name = NULL;
+  int ir_check_token_type_name_len = 0;
+  char *ir_check_tt_uint_name = NULL;
+  int ir_check_tt_uint_name_len = 0;
+  char *ir_check_tt_sint_name = NULL;
+  int ir_check_tt_sint_name_len = 0;
+  char *ir_handle_tt_uint_name = NULL;
+  int ir_handle_tt_uint_name_len = 0;
+  char *ir_handle_tt_sint_name = NULL;
+  int ir_handle_tt_sint_name_len = 0;
+  char *ir_check_bounds_name = NULL;
+  int ir_check_bounds_name_len = 0;
+  char *ir_check_upper_bound_name = NULL;
+  int ir_check_upper_bound_name_len = 0;
+  char *ir_success_name = NULL;
+  int ir_success_name_len = 0;
+  char *ir_fail_name = NULL;
+  int ir_fail_name_len = 0;
+  char *ir_end_name = NULL;
+  int ir_end_name_len = 0;
+  char *inner_res_icmp_name = NULL;
+  int inner_res_icmp_name_len = 0;
+  char *ret_ast_ptr_name = NULL;
+  int ret_ast_ptr_name_len = 0;
+  char *ret_ast_name = NULL;
+  int ret_ast_name_len = 0;
+  char *ret_ast_icmp_name = NULL;
+  int ret_ast_icmp_name_len = 0;
+  char *token_type_ptr_name = NULL;
+  int token_type_ptr_name_len = 0;
+  char *token_type_name = NULL;
+  int token_type_name_len = 0;
+  char *token_length_ptr_name = NULL;
+  int token_length_ptr_name_len = 0;
+  char *token_length_name = NULL;
+  int token_length_name_len = 0;
+  char *token_data_ptr_name = NULL;
+  int token_data_ptr_name_len = 0;
+  char *token_data_name = NULL;
+  int token_data_name_len = 0;
+  char *tt_uint_icmp_name = NULL;
+  int tt_uint_icmp_name_len = 0;
+  char *tt_sint_icmp_name = NULL;
+  int tt_sint_icmp_name_len = 0;
+  char *lower_uint_icmp_name = NULL;
+  int lower_uint_icmp_name_len = 0;
+  char *lower_sint_icmp_name = NULL;
+  int lower_sint_icmp_name_len = 0;
+  char *lower_icmp_name = NULL;
+  int lower_icmp_name_len = 0;
+  char *upper_uint_icmp_name = NULL;
+  int upper_uint_icmp_name_len = 0;
+  char *upper_sint_icmp_name = NULL;
+  int upper_sint_icmp_name_len = 0;
+  char *upper_icmp_name = NULL;
+  int upper_icmp_name_len = 0;
+  char *rv_name = NULL;
+  int rv_name_len = 0;
+  /* The HRange */
+  HRange *r = NULL;
+  /* Our status */
+  bool status = true;
+  /* intrange basic blocks */
+  LLVMBasicBlockRef entry, check_res, check_res_ast, check_token_type;
+  LLVMBasicBlockRef check_tt_uint, check_tt_sint, handle_tt_uint, handle_tt_sint;
+  LLVMBasicBlockRef check_bounds, check_upper_bound;
+  LLVMBasicBlockRef success, fail, end;
+  /* Result of the parser this intrange wraps */
+  LLVMValueRef inner_res;
+  /* Result of result-not-zero icmp */
+  LLVMValueRef inner_res_icmp;
+  /* Pointer to AST pointer from inner_res */
+  LLVMValueRef ret_ast_ptr;
+  /* AST pointer from inner_res */
+  LLVMValueRef ret_ast;
+  /* Result of res_ast != 0 icmp */
+  LLVMValueRef ret_ast_icmp;
+  /* Pointer to token type from ret->ast */
+  LLVMValueRef token_type_ptr;
+  /* Value of token type from ret->ast */
+  LLVMValueRef token_type;
+  /* Pointer to token length from ret->ast */
+  LLVMValueRef token_length_ptr;
+  /* Value of token length from ret->ast */
+  LLVMValueRef token_length;
+  /* Pointer to token data from ret->ast */
+  LLVMValueRef token_data_ptr;
+  /* Value of token data from ret->ast */
+  LLVMValueRef token_data;
+  /* Result of comparing token_type to TT_UINT */
+  LLVMValueRef tt_uint_icmp;
+  /* Result of comparing token_type to TT_SINT */
+  LLVMValueRef tt_sint_icmp;
+  /* Result of icmp against lower bound */
+  LLVMValueRef lower_sint_icmp, lower_uint_icmp, lower_icmp;
+  /* Result of icmp against upper bound */
+  LLVMValueRef upper_sint_icmp, upper_uint_icmp, upper_icmp;
+  /* Inputs to the phis for lower_icmp and upper_icmp */
+  LLVMBasicBlockRef lower_icmp_incoming_blocks[2];
+  LLVMValueRef lower_icmp_incoming_values[2];
+  LLVMBasicBlockRef upper_icmp_incoming_blocks[2];
+  LLVMValueRef upper_icmp_incoming_values[2];
+  /* Our result */
+  LLVMValueRef rv;
+  /* Inputs to the phi */
+  LLVMBasicBlockRef rv_phi_incoming_blocks[2];
+  LLVMValueRef rv_phi_incoming_values[2];
+  /* Width of the integer in the token type */
+  unsigned int token_int_width;
+
+
+  if (!res) return false;
+  if (!p) return false;
+  if (!ctxt) return false;
+
+  /* Unpack the allocator */
+  mm__ = ctxt->mm__;
+
+  /* Get the range */
+  r = (HRange *)(p->env);
+  if (!r) return false;
+
+  /* Set up our basic blocks */
+  ir_entry_name_len = snprintf(NULL, 0, "ir_entry_%p", p);
+  ir_entry_name = h_new(char, ir_entry_name_len + 1);
+  snprintf(ir_entry_name, ir_entry_name_len + 1,
+           "ir_entry_%p", p);
+  entry = LLVMAppendBasicBlock(ctxt->func, ir_entry_name);
+  ir_check_res_name_len = snprintf(NULL, 0, "ir_check_res_%p", p);
+  ir_check_res_name = h_new(char, ir_check_res_name_len + 1);
+  snprintf(ir_check_res_name, ir_check_res_name_len + 1,
+           "ir_check_res_%p", p);
+  check_res = LLVMAppendBasicBlock(ctxt->func, ir_check_res_name);
+  ir_check_res_ast_name_len = snprintf(NULL, 0, "ir_check_res_ast_%p", p);
+  ir_check_res_ast_name = h_new(char, ir_check_res_ast_name_len + 1);
+  snprintf(ir_check_res_ast_name, ir_check_res_ast_name_len + 1,
+           "ir_check_res_ast_%p", p);
+  check_res_ast = LLVMAppendBasicBlock(ctxt->func, ir_check_res_ast_name);
+  ir_check_token_type_name_len =
+    snprintf(NULL, 0, "ir_check_token_type_%p", p);
+  ir_check_token_type_name = h_new(char, ir_check_token_type_name_len + 1);
+  snprintf(ir_check_token_type_name, ir_check_token_type_name_len + 1,
+           "ir_check_token_type_%p", p);
+  check_token_type =
+    LLVMAppendBasicBlock(ctxt->func, ir_check_token_type_name);
+  ir_check_tt_uint_name_len =
+    snprintf(NULL, 0, "ir_check_tt_uint_%p", p);
+  ir_check_tt_uint_name = h_new(char, ir_check_tt_uint_name_len + 1);
+  snprintf(ir_check_tt_uint_name, ir_check_tt_uint_name_len + 1,
+           "ir_check_tt_uint_%p", p);
+  check_tt_uint =
+    LLVMAppendBasicBlock(ctxt->func, ir_check_tt_uint_name);
+  ir_check_tt_sint_name_len =
+    snprintf(NULL, 0, "ir_check_tt_sint_%p", p);
+  ir_check_tt_sint_name = h_new(char, ir_check_tt_sint_name_len + 1);
+  snprintf(ir_check_tt_sint_name, ir_check_tt_sint_name_len + 1,
+           "ir_check_tt_sint_%p", p);
+  check_tt_sint =
+    LLVMAppendBasicBlock(ctxt->func, ir_check_tt_sint_name);
+  ir_handle_tt_uint_name_len =
+    snprintf(NULL, 0, "ir_handle_tt_uint_%p", p);
+  ir_handle_tt_uint_name = h_new(char, ir_handle_tt_uint_name_len + 1);
+  snprintf(ir_handle_tt_uint_name, ir_handle_tt_uint_name_len + 1,
+           "ir_handle_tt_uint_%p", p);
+  handle_tt_uint =
+    LLVMAppendBasicBlock(ctxt->func, ir_handle_tt_uint_name);
+  ir_handle_tt_sint_name_len =
+    snprintf(NULL, 0, "ir_handle_tt_sint_%p", p);
+  ir_handle_tt_sint_name = h_new(char, ir_handle_tt_sint_name_len + 1);
+  snprintf(ir_handle_tt_sint_name, ir_handle_tt_sint_name_len + 1,
+           "ir_handle_tt_sint_%p", p);
+  handle_tt_sint =
+    LLVMAppendBasicBlock(ctxt->func, ir_handle_tt_sint_name);
+  ir_check_bounds_name_len = snprintf(NULL, 0, "ir_check_bounds_%p", p);
+  ir_check_bounds_name = h_new(char, ir_check_bounds_name_len + 1);
+  snprintf(ir_check_bounds_name, ir_check_bounds_name_len + 1,
+           "ir_check_bounds_%p", p);
+  check_bounds = LLVMAppendBasicBlock(ctxt->func, ir_check_bounds_name);
+  ir_check_upper_bound_name_len =
+    snprintf(NULL, 0, "ir_check_upper_bound_%p", p);
+  ir_check_upper_bound_name =
+    h_new(char, ir_check_upper_bound_name_len + 1);
+  snprintf(ir_check_upper_bound_name, ir_check_upper_bound_name_len + 1,
+           "ir_check_upper_bound_%p", p);
+  check_upper_bound = LLVMAppendBasicBlock(ctxt->func,
+      ir_check_upper_bound_name);
+  ir_success_name_len = snprintf(NULL, 0, "ir_success_%p", p);
+  ir_success_name = h_new(char, ir_success_name_len + 1);
+  snprintf(ir_success_name, ir_success_name_len + 1,
+           "ir_success_%p", p);
+  success = LLVMAppendBasicBlock(ctxt->func, ir_success_name);
+  ir_fail_name_len = snprintf(NULL, 0, "ir_fail_%p", p);
+  ir_fail_name = h_new(char, ir_fail_name_len + 1);
+  snprintf(ir_fail_name, ir_fail_name_len + 1,
+           "ir_fail_%p", p);
+  fail = LLVMAppendBasicBlock(ctxt->func, ir_fail_name);
+  ir_end_name_len = snprintf(NULL, 0, "ir_end_%p", p);
+  ir_end_name = h_new(char, ir_end_name_len + 1);
+  snprintf(ir_end_name, ir_end_name_len + 1,
+           "ir_end_%p", p);
+  end = LLVMAppendBasicBlock(ctxt->func, ir_end_name);
+
+  /* Basic block: entry */
+  LLVMBuildBr(ctxt->builder, entry);
+  LLVMPositionBuilderAtEnd(ctxt->builder, entry);
+
+  /* Try the inner parser */
+  if (r->p && r->p->vtable && r->p->vtable->llvm) {
+    if (r->p->vtable->llvm(ctxt, r->p, &inner_res)) {
+      /* w00t, the inner parser compiled */
+
+      /*
+       * Okay, now we should have a pointer to an HParseResult in inner_res,
+       * and we need to check that the result is a TT_SINT or a TT_UINT and
+       * matches the required range.
+       *
+       * XXX we could probably look at the type of parser we have under the
+       * h_int_range at compile time and build a fast-path common case.
+       */
+
+      /* Set up the int_range bb */
+      LLVMBuildBr(ctxt->builder, check_res);
+
+      /* Check that the result is not null */
+      LLVMPositionBuilderAtEnd(ctxt->builder, check_res);
+      inner_res_icmp_name_len = snprintf(NULL, 0,
+          "ir_inner_res_null_icmp_%p", p);
+      inner_res_icmp_name = h_new(char, inner_res_icmp_name_len + 1);
+      snprintf(inner_res_icmp_name, inner_res_icmp_name_len + 1,
+               "ir_inner_res_null_icmp_%p", p);
+      inner_res_icmp = LLVMBuildICmp(ctxt->builder, LLVMIntNE,
+          inner_res, LLVMConstNull(ctxt->llvm_parseresultptr),
+          inner_res_icmp_name);
+      LLVMBuildCondBr(ctxt->builder, inner_res_icmp, check_res_ast, fail);
+
+      /* First, get the AST pointer out */
+      LLVMPositionBuilderAtEnd(ctxt->builder, check_res_ast);
+      ret_ast_ptr_name_len = snprintf(NULL, 0, "ret_ast_ptr_%p", p);
+      ret_ast_ptr_name = h_new(char, ret_ast_ptr_name_len + 1);
+      snprintf(ret_ast_ptr_name, ret_ast_ptr_name_len + 1,
+               "ret_ast_ptr_%p", p);
+      ret_ast_ptr = LLVMBuildStructGEP(ctxt->builder, inner_res,
+          0, ret_ast_ptr_name);
+
+      /* Deref ret_ast_ptr */
+      ret_ast_name_len = snprintf(NULL, 0, "ret_ast_%p", p);
+      ret_ast_name = h_new(char, ret_ast_name_len + 1);
+      snprintf(ret_ast_name, ret_ast_name_len + 1,
+               "ret_ast_%p", p);
+      ret_ast = LLVMBuildLoad(ctxt->builder, ret_ast_ptr, ret_ast_name);
+
+      /* Check that the AST pointer is not null */
+      ret_ast_icmp_name_len = snprintf(NULL, 0,
+          "ir_ret_ast_null_icmp_%p", p);
+      ret_ast_icmp_name = h_new(char, ret_ast_icmp_name_len + 1);
+      snprintf(ret_ast_icmp_name, ret_ast_icmp_name_len + 1,
+               "ir_ret_ast_null_icmp_%p", p);
+      ret_ast_icmp = LLVMBuildICmp(ctxt->builder, LLVMIntNE,
+          ret_ast, LLVMConstNull(ctxt->llvm_parsedtokenptr),
+          ret_ast_icmp_name);
+      LLVMBuildCondBr(ctxt->builder, ret_ast_icmp, check_token_type, fail);
+
+      /* Holly shit, it's a real token! */
+      LLVMPositionBuilderAtEnd(ctxt->builder, check_token_type);
+      token_type_ptr_name_len = snprintf(NULL, 0, "ir_token_type_ptr_%p", p);
+      token_type_ptr_name = h_new(char, token_type_ptr_name_len + 1);
+      snprintf(token_type_ptr_name, token_type_ptr_name_len + 1,
+               "ir_token_type_ptr_%p", p);
+      token_type_ptr = LLVMBuildStructGEP(ctxt->builder, ret_ast,
+          0, token_type_ptr_name);
+      token_type_name_len = snprintf(NULL, 0, "ir_token_type_%p", p);
+      token_type_name = h_new(char, token_type_name_len + 1);
+      snprintf(token_type_name, token_type_name_len + 1,
+               "ir_token_type_%p", p);
+      token_type =
+        LLVMBuildLoad(ctxt->builder, token_type_ptr, token_type_name);
+      token_data_ptr_name_len =
+        snprintf(NULL, 0, "ir_token_data_ptr_%p", p);
+      token_data_ptr_name = h_new(char, token_data_ptr_name_len + 1);
+      snprintf(token_data_ptr_name, token_data_ptr_name_len + 1,
+               "ir_token_data_ptr_%p", p);
+      token_data_ptr = LLVMBuildStructGEP(ctxt->builder, ret_ast,
+          1, token_data_ptr_name);
+      token_data_name_len = snprintf(NULL, 0, "ir_token_data_%p", p);
+      token_data_name = h_new(char, token_data_name_len + 1);
+      snprintf(token_data_name, token_data_name_len + 1,
+               "ir_token_data_%p", p);
+      token_data =
+        LLVMBuildLoad(ctxt->builder, token_data_ptr, token_data_name);
+      /* Now check if we have a TT_UINT */
+      LLVMBuildBr(ctxt->builder, check_tt_uint);
+
+      /* Are we doing a TT_UINT? */
+      LLVMPositionBuilderAtEnd(ctxt->builder, check_tt_uint);
+      tt_uint_icmp_name_len = snprintf(NULL, 0, "ir_tt_uint_icmp_%p", p);
+      tt_uint_icmp_name = h_new(char, tt_uint_icmp_name_len + 1);
+      snprintf(tt_uint_icmp_name, tt_uint_icmp_name_len + 1,
+               "ir_tt_uint_null_icmp_%p", p);
+      tt_uint_icmp = LLVMBuildICmp(ctxt->builder, LLVMIntEQ,
+          token_type, LLVMConstInt(LLVMInt32Type(), TT_UINT, 0),
+          tt_uint_icmp_name);
+      LLVMBuildCondBr(ctxt->builder, tt_uint_icmp, handle_tt_uint, check_tt_sint);
+
+      /* Are we doing a TT_SINT? */
+      LLVMPositionBuilderAtEnd(ctxt->builder, check_tt_sint);
+      tt_sint_icmp_name_len = snprintf(NULL, 0, "ir_tt_sint_icmp_%p", p);
+      tt_sint_icmp_name = h_new(char, tt_sint_icmp_name_len + 1);
+      snprintf(tt_sint_icmp_name, tt_sint_icmp_name_len + 1,
+               "ir_tt_sint_null_icmp_%p", p);
+      tt_sint_icmp = LLVMBuildICmp(ctxt->builder, LLVMIntEQ,
+          token_type, LLVMConstInt(LLVMInt32Type(), TT_SINT, 0),
+          tt_sint_icmp_name);
+      LLVMBuildCondBr(ctxt->builder, tt_sint_icmp, handle_tt_sint, fail);
+
+      /*
+       * No need to dick around with sext/zext on token_data because
+       * it was already done on token creation; see h_llvm_make_tt_suint()
+       */
+
+      /* Handle the TT_UINT case */
+      LLVMPositionBuilderAtEnd(ctxt->builder, handle_tt_uint);
+      lower_uint_icmp_name_len =
+        snprintf(NULL, 0, "lower_uint_icmp_%p", p);
+      lower_uint_icmp_name = h_new(char, lower_uint_icmp_name_len + 1);
+      snprintf(lower_uint_icmp_name, lower_uint_icmp_name_len + 1,
+               "lower_uint_icmp_%p", p);
+      lower_uint_icmp = LLVMBuildICmp(ctxt->builder, LLVMIntULT,
+          token_data,
+          LLVMConstInt(LLVMTypeOf(token_data), (uint64_t)(r->lower), 0),
+          lower_uint_icmp_name);
+      upper_uint_icmp_name_len =
+        snprintf(NULL, 0, "upper_uint_icmp_%p", p);
+      upper_uint_icmp_name = h_new(char, upper_uint_icmp_name_len + 1);
+      snprintf(upper_uint_icmp_name, upper_uint_icmp_name_len + 1,
+               "upper_uint_icmp_%p", p);
+      upper_uint_icmp = LLVMBuildICmp(ctxt->builder, LLVMIntUGT,
+          token_data,
+          LLVMConstInt(LLVMTypeOf(token_data), (uint64_t)(r->upper), 0),
+          upper_uint_icmp_name);
+      LLVMBuildBr(ctxt->builder, check_bounds);
+
+      /* Handle the TT_SINT case */
+      LLVMPositionBuilderAtEnd(ctxt->builder, handle_tt_sint);
+      lower_sint_icmp_name_len =
+        snprintf(NULL, 0, "lower_sint_icmp_%p", p);
+      lower_sint_icmp_name = h_new(char, lower_sint_icmp_name_len + 1);
+      snprintf(lower_sint_icmp_name, lower_sint_icmp_name_len + 1,
+               "lower_sint_icmp_%p", p);
+      lower_sint_icmp = LLVMBuildICmp(ctxt->builder, LLVMIntSLT,
+          token_data,
+          LLVMConstInt(LLVMTypeOf(token_data), (int64_t)(r->lower), 0),
+          lower_sint_icmp_name);
+      upper_sint_icmp_name_len =
+        snprintf(NULL, 0, "upper_sint_icmp_%p", p);
+      upper_sint_icmp_name = h_new(char, upper_sint_icmp_name_len + 1);
+      snprintf(upper_sint_icmp_name, upper_sint_icmp_name_len + 1,
+               "upper_sint_icmp_%p", p);
+      upper_sint_icmp = LLVMBuildICmp(ctxt->builder, LLVMIntSGT,
+          token_data,
+          LLVMConstInt(LLVMTypeOf(token_data), (int64_t)(r->upper), 0),
+          upper_sint_icmp_name);
+      LLVMBuildBr(ctxt->builder, check_bounds);
+
+      /*
+       * The check_bounds block can come in from handle_tt_uint or
+       * handle_tt_sint, so the icmps it uses are phis
+       */
+      LLVMPositionBuilderAtEnd(ctxt->builder, check_bounds);
+      lower_icmp_name_len = snprintf(NULL, 0, "lower_icmp_%p", p);
+      lower_icmp_name = h_new(char, lower_icmp_name_len + 1);
+      snprintf(lower_icmp_name, lower_icmp_name_len + 1,
+               "lower_icmp_%p", p);
+      lower_icmp = LLVMBuildPhi(ctxt->builder,
+          LLVMTypeOf(lower_uint_icmp), lower_icmp_name);
+      lower_icmp_incoming_blocks[0] = handle_tt_uint;
+      lower_icmp_incoming_values[0] = lower_uint_icmp;
+      lower_icmp_incoming_blocks[1] = handle_tt_sint;
+      lower_icmp_incoming_values[1] = lower_sint_icmp;
+      LLVMAddIncoming(lower_icmp,
+                      lower_icmp_incoming_values,
+                      lower_icmp_incoming_blocks,
+                      2);
+      upper_icmp_name_len = snprintf(NULL, 0, "upper_icmp_%p", p);
+      upper_icmp_name = h_new(char, upper_icmp_name_len + 1);
+      snprintf(upper_icmp_name, upper_icmp_name_len + 1,
+               "upper_icmp_%p", p);
+      upper_icmp = LLVMBuildPhi(ctxt->builder,
+          LLVMTypeOf(upper_uint_icmp), upper_icmp_name);
+      upper_icmp_incoming_blocks[0] = handle_tt_uint;
+      upper_icmp_incoming_values[0] = upper_uint_icmp;
+      upper_icmp_incoming_blocks[1] = handle_tt_sint;
+      upper_icmp_incoming_values[1] = upper_sint_icmp;
+      LLVMAddIncoming(upper_icmp,
+                      upper_icmp_incoming_values,
+                      upper_icmp_incoming_blocks,
+                      2);
+      /* Did we fail the lower bound? */
+      LLVMBuildCondBr(ctxt->builder, lower_icmp, fail, check_upper_bound);
+
+      /* Okay, now we check the upper one */
+      LLVMPositionBuilderAtEnd(ctxt->builder, check_upper_bound);
+      LLVMBuildCondBr(ctxt->builder, upper_icmp, fail, success);
+
+      /*
+       * From success, branch to end (and the phi for rv will know to
+       * use ret)
+       */
+      LLVMPositionBuilderAtEnd(ctxt->builder, success);
+      LLVMBuildBr(ctxt->builder, end);
+
+      /*
+       * From fail, branch to end (and the phi for rv will know to
+       * use NULL)
+       */
+      LLVMPositionBuilderAtEnd(ctxt->builder, fail);
+      LLVMBuildBr(ctxt->builder, end);
+
+      /*
+       * In end, phi for rv
+       */
+      LLVMPositionBuilderAtEnd(ctxt->builder, end);
+      rv_name_len = snprintf(NULL, 0, "int_range_rv_%p", p);
+      rv_name = h_new(char, rv_name_len + 1);
+      snprintf(rv_name, rv_name_len + 1, "int_range_rv_%p", p);
+      rv = LLVMBuildPhi(ctxt->builder, ctxt->llvm_parseresultptr, rv_name);
+      rv_phi_incoming_blocks[0] = success;
+      rv_phi_incoming_values[0] = inner_res;
+      rv_phi_incoming_blocks[1] = fail;
+      rv_phi_incoming_values[1] = LLVMConstNull(ctxt->llvm_parseresultptr);
+      LLVMAddIncoming(rv, rv_phi_incoming_values, rv_phi_incoming_blocks, 2);
+      *res = rv;
+
+      /* Pass it back out */
+      *res = rv;
+    } else {
+      status = false;
+    }
+  } else {
+    status = false;
+  }
+
+  /* Free names */
+
+  if (ir_entry_name) {
+    h_free(ir_entry_name);
+    ir_entry_name = NULL;
+  }
+
+  if (ir_check_res_name) {
+    h_free(ir_check_res_name);
+    ir_check_res_name = NULL;
+  }
+
+  if (ir_check_res_ast_name) {
+    h_free(ir_check_res_ast_name);
+    ir_check_res_ast_name = NULL;
+  }
+
+  if (ir_check_token_type_name) {
+    h_free(ir_check_token_type_name);
+    ir_check_token_type_name = NULL;
+  }
+
+  if (ir_handle_tt_uint_name) {
+    h_free(ir_handle_tt_uint_name);
+    ir_handle_tt_uint_name = NULL;
+  }
+
+  if (ir_handle_tt_sint_name) {
+    h_free(ir_handle_tt_sint_name);
+    ir_handle_tt_sint_name = NULL;
+  }
+
+  if (ir_check_tt_uint_name) {
+    h_free(ir_check_tt_uint_name);
+    ir_check_tt_uint_name = NULL;
+  }
+
+  if (ir_check_tt_sint_name) {
+    h_free(ir_check_tt_sint_name);
+    ir_check_tt_sint_name = NULL;
+  }
+
+  if (ir_check_bounds_name) {
+    h_free(ir_check_bounds_name);
+    ir_check_bounds_name = NULL;
+  }
+
+  if (ir_check_upper_bound_name) {
+    h_free(ir_check_upper_bound_name);
+    ir_check_upper_bound_name = NULL;
+  }
+
+  if (ir_success_name) {
+    h_free(ir_success_name);
+    ir_success_name = NULL;
+  }
+
+  if (ir_fail_name) {
+    h_free(ir_fail_name);
+    ir_fail_name = NULL;
+  }
+
+  if (ir_end_name) {
+    h_free(ir_end_name);
+    ir_end_name = NULL;
+  }
+
+  if (inner_res_icmp_name) {
+    h_free(inner_res_icmp_name);
+    inner_res_icmp_name = NULL;
+  }
+
+  if (ret_ast_ptr_name) {
+    h_free(ret_ast_ptr_name);
+    ret_ast_ptr_name = NULL;
+  }
+
+  if (ret_ast_name) {
+    h_free(ret_ast_name);
+    ret_ast_name = NULL;
+  }
+
+  if (ret_ast_icmp_name) {
+    h_free(ret_ast_icmp_name);
+    ret_ast_icmp_name = NULL;
+  }
+
+  if (token_type_ptr_name) {
+    h_free(token_type_ptr_name);
+    token_type_ptr_name = NULL;
+  }
+
+  if (token_type_name) {
+    h_free(token_type_name);
+    token_type_name = NULL;
+  }
+
+  if (token_data_ptr_name) {
+    h_free(token_data_ptr_name);
+    token_data_ptr_name = NULL;
+  }
+
+  if (token_data_name) {
+    h_free(token_data_name);
+    token_data_name = NULL;
+  }
+
+  if (tt_uint_icmp_name) {
+    h_free(tt_uint_icmp_name);
+    tt_uint_icmp_name = NULL;
+  }
+
+  if (tt_sint_icmp_name) {
+    h_free(tt_sint_icmp_name);
+    tt_sint_icmp_name = NULL;
+  }
+
+  if (lower_uint_icmp_name) {
+    h_free(lower_uint_icmp_name);
+    lower_uint_icmp_name = NULL;
+  }
+
+  if (lower_sint_icmp_name) {
+    h_free(lower_sint_icmp_name);
+    lower_sint_icmp_name = NULL;
+  }
+
+  if (lower_icmp_name) {
+    h_free(lower_icmp_name);
+    lower_icmp_name = NULL;
+  }
+
+  if (upper_uint_icmp_name) {
+    h_free(upper_uint_icmp_name);
+    upper_uint_icmp_name = NULL;
+  }
+
+  if (upper_sint_icmp_name) {
+    h_free(upper_sint_icmp_name);
+    upper_sint_icmp_name = NULL;
+  }
+
+  if (upper_icmp_name) {
+    h_free(upper_icmp_name);
+    upper_icmp_name = NULL;
+  }
+
+  if (rv_name) {
+    h_free(rv_name);
+    rv_name = NULL;
+  }
+
+  return status;
+}
+
+#endif
+
 static const HParserVtable int_range_vt = {
   .parse = parse_int_range,
   .isValidRegular = h_true,
   .isValidCF = h_true,
   .desugar = desugar_int_range,
   .compile_to_rvm = ir_ctrvm,
+#ifdef HAMMER_LLVM_BACKEND
+  .llvm = ir_llvm,
+#endif
   .higher = false,
 };
 
diff --git a/src/t_parser.c b/src/t_parser.c
index 52f81544..1c06fa9d 100644
--- a/src/t_parser.c
+++ b/src/t_parser.c
@@ -118,10 +118,40 @@ static void test_uint8(gconstpointer backend) {
 //@MARK_END
 
 static void test_int_range(gconstpointer backend) {
-  const HParser *int_range_ = h_int_range(h_uint8(), 3, 10);
+  const HParser *int_range_8_1_ = h_int_range(h_uint8(), 3, 10);
+  const HParser *int_range_8_2_ = h_int_range(h_int8(), -2, 5);
+  const HParser *int_range_8_3_ = h_int_range(h_int8(), 4, 12);
+  const HParser *int_range_8_4_ = h_int_range(h_int8(), -12, -3);
+  const HParser *int_range_16_1_ = h_int_range(h_uint16(), 3, 432);
+  const HParser *int_range_16_2_ = h_int_range(h_int16(), -22, 588);
+  const HParser *int_range_16_3_ = h_int_range(h_int16(), 129, 201);
+  const HParser *int_range_16_4_ = h_int_range(h_int16(), -301, -7);
   
-  g_check_parse_match(int_range_, (HParserBackend)GPOINTER_TO_INT(backend), "\x05", 1, "u0x5");
-  g_check_parse_failed(int_range_, (HParserBackend)GPOINTER_TO_INT(backend), "\xb", 1);
+  g_check_parse_match(int_range_8_1_, (HParserBackend)GPOINTER_TO_INT(backend), "\x05", 1, "u0x5");
+  g_check_parse_match(int_range_8_1_, (HParserBackend)GPOINTER_TO_INT(backend), "\x0a", 1, "u0xa");
+  g_check_parse_match(int_range_8_1_, (HParserBackend)GPOINTER_TO_INT(backend), "\x03", 1, "u0x3");
+  g_check_parse_failed(int_range_8_1_, (HParserBackend)GPOINTER_TO_INT(backend), "\xb", 1);
+  g_check_parse_failed(int_range_8_1_, (HParserBackend)GPOINTER_TO_INT(backend), "\x2", 1);
+
+  g_check_parse_match(int_range_8_2_, (HParserBackend)GPOINTER_TO_INT(backend), "\x02", 1, "s0x2");
+  g_check_parse_match(int_range_8_2_, (HParserBackend)GPOINTER_TO_INT(backend), "\x05", 1, "s0x5");
+  g_check_parse_match(int_range_8_2_, (HParserBackend)GPOINTER_TO_INT(backend), "\xfe", 1, "s-0x2");
+  g_check_parse_failed(int_range_8_2_, (HParserBackend)GPOINTER_TO_INT(backend), "\x7", 1);
+  g_check_parse_failed(int_range_8_2_, (HParserBackend)GPOINTER_TO_INT(backend), "\xfa", 1);
+
+  g_check_parse_match(int_range_8_3_, (HParserBackend)GPOINTER_TO_INT(backend), "\x06", 1, "s0x6");
+  g_check_parse_match(int_range_8_3_, (HParserBackend)GPOINTER_TO_INT(backend), "\x0c", 1, "s0xc");
+  g_check_parse_match(int_range_8_3_, (HParserBackend)GPOINTER_TO_INT(backend), "\x04", 1, "s0x4");
+  g_check_parse_failed(int_range_8_3_, (HParserBackend)GPOINTER_TO_INT(backend), "\x0f", 1);
+  g_check_parse_failed(int_range_8_3_, (HParserBackend)GPOINTER_TO_INT(backend), "\x03", 1);
+  g_check_parse_failed(int_range_8_3_, (HParserBackend)GPOINTER_TO_INT(backend), "\xfe", 1);
+
+  g_check_parse_match(int_range_8_4_, (HParserBackend)GPOINTER_TO_INT(backend), "\xfb", 1, "s-0x5");
+  g_check_parse_match(int_range_8_4_, (HParserBackend)GPOINTER_TO_INT(backend), "\xfd", 1, "s-0x3");
+  g_check_parse_match(int_range_8_4_, (HParserBackend)GPOINTER_TO_INT(backend), "\xf4", 1, "s-0xc");
+  g_check_parse_failed(int_range_8_4_, (HParserBackend)GPOINTER_TO_INT(backend), "\xff", 1);
+  g_check_parse_failed(int_range_8_4_, (HParserBackend)GPOINTER_TO_INT(backend), "\xf0", 1);
+  g_check_parse_failed(int_range_8_4_, (HParserBackend)GPOINTER_TO_INT(backend), "\x02", 1);
 }
 
 #if 0
@@ -1055,6 +1085,7 @@ void register_parser_tests(void) {
   g_test_add_data_func("/core/parser/llvm/uint32", GINT_TO_POINTER(PB_LLVM), test_uint32);
   g_test_add_data_func("/core/parser/llvm/uint16", GINT_TO_POINTER(PB_LLVM), test_uint16);
   g_test_add_data_func("/core/parser/llvm/uint8", GINT_TO_POINTER(PB_LLVM), test_uint8);
+  g_test_add_data_func("/core/parser/llvm/int_range", GINT_TO_POINTER(PB_LLVM), test_int_range);
   g_test_add_data_func("/core/parser/llvm/in", GINT_TO_POINTER(PB_LLVM), test_in);
   g_test_add_data_func("/core/parser/llvm/not_in", GINT_TO_POINTER(PB_LLVM), test_not_in);
   g_test_add_data_func("/core/parser/llvm/nothing_p", GINT_TO_POINTER(PB_LLVM), test_nothing_p);
-- 
GitLab