From 81616aeb748542f188c02e40f380b3ce5444862b Mon Sep 17 00:00:00 2001
From: Andrea Shepard <andrea@persephoneslair.org>
Date: Sun, 20 Nov 2016 23:18:30 +0000
Subject: [PATCH] Make LLVM backend a build-time option

---
 SConstruct               |  1 +
 src/SConscript           |  3 ++-
 src/backends/llvm/llvm.c |  4 ++++
 src/backends/llvm/llvm.h |  6 ++++++
 src/backends/missing.c   | 23 +++++++++++++++++++++++
 src/backends/missing.h   |  7 +++++++
 src/hammer.c             | 16 ++++++++++++++++
 src/hammer.h             |  4 ++++
 src/internal.h           |  7 +++++++
 src/parsers/bits.c       | 10 +++++++++-
 src/parsers/ch.c         | 10 +++++++++-
 src/parsers/charset.c    | 10 +++++++++-
 src/t_parser.c           |  2 ++
 13 files changed, 99 insertions(+), 4 deletions(-)
 create mode 100644 src/backends/missing.c
 create mode 100644 src/backends/missing.h

diff --git a/SConstruct b/SConstruct
index 707690c8..e4034548 100644
--- a/SConstruct
+++ b/SConstruct
@@ -119,6 +119,7 @@ if GetOption("use_llvm"):
     # Overridable default path to llvm-config
     env['LLVM_CONFIG'] = "llvm-config"
     env["LLVM_CONFIG"] = os.getenv("LLVM_CONFIG") or env["LLVM_CONFIG"]
+    env.MergeFlags("-DHAMMER_LLVM_BACKEND")
 
 if GetOption("coverage"):
     env.Append(CFLAGS=["--coverage"],
diff --git a/src/SConscript b/src/SConscript
index cdbe6c73..1495f42b 100644
--- a/src/SConscript
+++ b/src/SConscript
@@ -32,6 +32,7 @@ parsers_headers = [
 backends_headers = [
     "backends/regex.h",
     "backends/contextfree.h"
+    "backends/missing.h"
 ]
 
 parsers = ['parsers/%s.c'%s for s in
@@ -65,7 +66,7 @@ parsers = ['parsers/%s.c'%s for s in
             'value']]
 
 backends = ['backends/%s.c' % s for s in
-            ['packrat', 'llk', 'regex', 'glr', 'lalr', 'lr', 'lr0']]
+            ['packrat', 'llk', 'regex', 'glr', 'lalr', 'lr', 'lr0', "missing"]]
 
 # Add LLVM backend if enabled
 if GetOption("use_llvm"):
diff --git a/src/backends/llvm/llvm.c b/src/backends/llvm/llvm.c
index 523f0b5c..7af7d08a 100644
--- a/src/backends/llvm/llvm.c
+++ b/src/backends/llvm/llvm.c
@@ -1,3 +1,5 @@
+#ifdef HAMMER_LLVM_BACKEND
+
 #include <llvm-c/Analysis.h>
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wpedantic"
@@ -1111,3 +1113,5 @@ HParserBackendVTable h__llvm_backend_vtable = {
   .parse = h_llvm_parse,
   .free = h_llvm_free
 };
+
+#endif /* defined(HAMMER_LLVM_BACKEND) */
diff --git a/src/backends/llvm/llvm.h b/src/backends/llvm/llvm.h
index 233f3284..36f53fcb 100644
--- a/src/backends/llvm/llvm.h
+++ b/src/backends/llvm/llvm.h
@@ -1,6 +1,10 @@
+#ifdef HAMMER_LLVM_BACKEND
+
 #ifndef HAMMER_LLVM__H
 #define HAMMER_LLVM__H
 
+#include "../../internal.h"
+
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wpedantic"
 #include <llvm-c/Core.h>
@@ -18,3 +22,5 @@ void h_llvm_make_tt_suint(LLVMModuleRef mod, LLVMBuilderRef builder,
                           LLVMValueRef r, LLVMValueRef *mr_out);
 
 #endif // #ifndef HAMMER_LLVM__H
+
+#endif /* defined(HAMMER_LLVM_BACKEND) */
diff --git a/src/backends/missing.c b/src/backends/missing.c
new file mode 100644
index 00000000..2a46b574
--- /dev/null
+++ b/src/backends/missing.c
@@ -0,0 +1,23 @@
+#include "missing.h"
+
+int h_missing_compile(HAllocator* mm__, HParser* parser, const void* params) {
+  /* Always fail */
+
+  return -1;
+}
+
+HParseResult *h_missing_parse(HAllocator* mm__, const HParser* parser, HInputStream* stream) {
+  /* Always fail */
+
+  return NULL;
+}
+
+void h_missing_free(HParser *parser) {
+  /* No-op */
+}
+
+HParserBackendVTable h__missing_backend_vtable = {
+  .compile = h_missing_compile, /* TODO */
+  .parse = h_missing_parse, /* TODO */
+  .free = h_missing_free, /* TODO */
+};
diff --git a/src/backends/missing.h b/src/backends/missing.h
new file mode 100644
index 00000000..4efe5f35
--- /dev/null
+++ b/src/backends/missing.h
@@ -0,0 +1,7 @@
+#ifndef HAMMER_BACKENDS_MISSING__H
+#define HAMMER_BACKENDS_MISSING__H
+
+#include "../hammer.h"
+#include "../internal.h"
+
+#endif /* !defined(HAMMER_BACKENDS_MISSING__H) */
diff --git a/src/hammer.c b/src/hammer.c
index 2a7d5bc5..6b881554 100644
--- a/src/hammer.c
+++ b/src/hammer.c
@@ -31,7 +31,23 @@ static HParserBackendVTable *backends[PB_MAX + 1] = {
   &h__llk_backend_vtable,
   &h__lalr_backend_vtable,
   &h__glr_backend_vtable,
+  /*
+   * Brittleness warning!
+   *
+   * We're using an enum as an index into this array (don't blame me...)
+   * so it's important that this array have the same size and order as
+   * the corresponding enum values in HParserBackend of src/hammer.h.
+   * Since callers use those enums as numeric constants to select a
+   * backend, dropping/reordering them breaks binary compatibility.
+   * If anyone adds any more optional backends in the future, don't
+   * #ifdef out those enum values in hammer.h, and do provide the
+   * 'missing' stub backend as an alternative here.
+   */
+#ifdef HAMMER_LLVM_BACKEND
   &h__llvm_backend_vtable,
+#else
+  &h__missing_backend_vtable,
+#endif
 };
 
 
diff --git a/src/hammer.h b/src/hammer.h
index 821924fa..b86e4ae0 100644
--- a/src/hammer.h
+++ b/src/hammer.h
@@ -46,6 +46,10 @@ typedef enum HParserBackend_ {
   PB_LLk,
   PB_LALR,
   PB_GLR,
+  /*
+   * PB_LLVM stays even if no LLVM backend compiled in, since these constants
+   * are exposed to callers.
+   */
   PB_LLVM,
   PB_MAX = PB_LLVM
 } HParserBackend;
diff --git a/src/internal.h b/src/internal.h
index 24199e29..d0224598 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -26,10 +26,12 @@
 #include <assert.h>
 #include <limits.h>
 #include <string.h>
+#ifdef HAMMER_LLVM_BACKEND
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wpedantic"
 #include <llvm-c/Core.h>
 #pragma GCC diagnostic pop
+#endif
 #include "hammer.h"
 #include "platform.h"
 
@@ -394,7 +396,10 @@ extern HParserBackendVTable h__packrat_backend_vtable;
 extern HParserBackendVTable h__llk_backend_vtable;
 extern HParserBackendVTable h__lalr_backend_vtable;
 extern HParserBackendVTable h__glr_backend_vtable;
+extern HParserBackendVTable h__missing_backend_vtable;
+#ifdef HAMMER_LLVM_BACKEND
 extern HParserBackendVTable h__llvm_backend_vtable;
+#endif
 // }}}
 
 // TODO(thequux): Set symbol visibility for these functions so that they aren't exported.
@@ -492,7 +497,9 @@ struct HParserVtable_ {
   bool (*isValidCF)(void *env);
   bool (*compile_to_rvm)(HRVMProg *prog, void* env); // FIXME: forgot what the bool return value was supposed to mean.
   void (*desugar)(HAllocator *mm__, HCFStack *stk__, void *env);
+#ifdef HAMMER_LLVM_BACKEND
   bool (*llvm)(HAllocator *mm__, LLVMBuilderRef builder, LLVMValueRef func, LLVMModuleRef mod, void *env);
+#endif
   bool higher; // false if primitive
 };
 
diff --git a/src/parsers/bits.c b/src/parsers/bits.c
index b9096201..d8c90dda 100644
--- a/src/parsers/bits.c
+++ b/src/parsers/bits.c
@@ -1,10 +1,12 @@
 #include <assert.h>
+#ifdef HAMMER_LLVM_BACKEND
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wpedantic"
 #include <llvm-c/Core.h>
 #pragma GCC diagnostic pop
-#include "parser_internal.h"
 #include "../backends/llvm/llvm.h"
+#endif
+#include "parser_internal.h"
 
 struct bits_env {
   uint8_t length;
@@ -22,6 +24,8 @@ static HParseResult* parse_bits(void* env, HParseState *state) {
   return make_result(state->arena, result);
 }
 
+#ifdef HAMMER_LLVM_BACKEND
+
 static bool bits_llvm(HAllocator *mm__,
                       LLVMBuilderRef builder, LLVMValueRef func, LLVMModuleRef mod,
                       void* env) {
@@ -94,6 +98,8 @@ static bool bits_llvm(HAllocator *mm__,
   return true;
 }
 
+#endif
+
 static HParsedToken *reshape_bits(const HParseResult *p, void* signedp_p) {
   // signedp == NULL iff unsigned
   bool signedp = (signedp_p != NULL);
@@ -179,7 +185,9 @@ static const HParserVtable bits_vt = {
   .isValidCF = h_true,
   .desugar = desugar_bits,
   .compile_to_rvm = bits_ctrvm,
+#ifdef HAMMER_LLVM_BACKEND
   .llvm = bits_llvm,
+#endif
   .higher = false,
 };
 
diff --git a/src/parsers/ch.c b/src/parsers/ch.c
index 08ffebd8..63067ba9 100644
--- a/src/parsers/ch.c
+++ b/src/parsers/ch.c
@@ -1,11 +1,13 @@
 #include <stdint.h>
 #include <assert.h>
+#ifdef HAMMER_LLVM_BACKEND
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wpedantic"
 #include <llvm-c/Core.h>
 #pragma GCC diagnostic pop
-#include "parser_internal.h"
 #include "../backends/llvm/llvm.h"
+#endif
+#include "parser_internal.h"
 
 static HParseResult* parse_ch(void* env, HParseState *state) {
   uint8_t c = (uint8_t)(uintptr_t)(env);
@@ -46,6 +48,8 @@ static bool ch_ctrvm(HRVMProg *prog, void* env) {
   return true;
 }
 
+#ifdef HAMMER_LLVM_BACKEND
+
 static bool ch_llvm(HAllocator *mm__, LLVMBuilderRef builder, LLVMValueRef func, LLVMModuleRef mod, void* env) {
   // Build a new LLVM function to parse a character
 
@@ -110,13 +114,17 @@ static bool ch_llvm(HAllocator *mm__, LLVMBuilderRef builder, LLVMValueRef func,
   return true;
 }
 
+#endif /* defined(HAMMER_LLVM_BACKEND) */
+
 static const HParserVtable ch_vt = {
   .parse = parse_ch,
   .isValidRegular = h_true,
   .isValidCF = h_true,
   .desugar = desugar_ch,
   .compile_to_rvm = ch_ctrvm,
+#ifdef HAMMER_LLVM_BACKEND
   .llvm = ch_llvm,
+#endif
   .higher = false,
 };
 
diff --git a/src/parsers/charset.c b/src/parsers/charset.c
index 56ac7b04..741adcd8 100644
--- a/src/parsers/charset.c
+++ b/src/parsers/charset.c
@@ -1,12 +1,14 @@
 #include <assert.h>
 #include <string.h>
 #include "../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 "parser_internal.h"
 #include "../backends/llvm/llvm.h"
+#endif /* defined(HAMMER_LLVM_BACKEND) */
+#include "parser_internal.h"
 
 static HParseResult* parse_charset(void *env, HParseState *state) {
   uint8_t in = h_read_bits(&state->input_stream, 8, false);
@@ -75,6 +77,8 @@ static bool cs_ctrvm(HRVMProg *prog, void *env) {
   return true;
 }
 
+#ifdef HAMMER_LLVM_BACKEND
+
 static bool cs_llvm(HAllocator *mm__, LLVMBuilderRef builder, LLVMValueRef func,
                     LLVMModuleRef mod, void* env) {
   /*
@@ -144,13 +148,17 @@ static bool cs_llvm(HAllocator *mm__, LLVMBuilderRef builder, LLVMValueRef func,
   return true;
 }
 
+#endif /* defined(HAMMER_LLVM_BACKEND) */
+
 static const HParserVtable charset_vt = {
   .parse = parse_charset,
   .isValidRegular = h_true,
   .isValidCF = h_true,
   .desugar = desugar_charset,
   .compile_to_rvm = cs_ctrvm,
+#ifdef HAMMER_LLVM_BACKEND
   .llvm = cs_llvm,
+#endif
   .higher = false,
 };
 
diff --git a/src/t_parser.c b/src/t_parser.c
index e32f9230..767e0893 100644
--- a/src/t_parser.c
+++ b/src/t_parser.c
@@ -1024,8 +1024,10 @@ void register_parser_tests(void) {
   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);
 
+#ifdef HAMMER_LLVM_BACKEND
   g_test_add_data_func("/core/parser/llvm/ch", GINT_TO_POINTER(PB_LLVM), test_ch);
   g_test_add_data_func("/core/parser/llvm/ch_range", GINT_TO_POINTER(PB_LLVM), test_ch_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);
+#endif /* defined(HAMMER_LLVM_BACKEND) */
 }
-- 
GitLab