diff --git a/src/parsers/epsilon.c b/src/parsers/epsilon.c
index bb6e8beb31cca3ff09a565171b4e554e07f2ffad..4c5abc406a390b3fce592a6b041bca5518ebb0ae 100644
--- a/src/parsers/epsilon.c
+++ b/src/parsers/epsilon.c
@@ -1,3 +1,10 @@
+#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"
 
 static HParseResult* parse_epsilon(void* env, HParseState* state) {
@@ -12,12 +19,45 @@ static bool epsilon_ctrvm(HRVMProg *prog, void* env) {
   return true;
 }
 
+#ifdef HAMMER_LLVM_BACKEND
+
+static bool epsilon_llvm(HLLVMParserCompileContext *ctxt, void* env) {
+  if (!ctxt) return false;
+
+  LLVMBasicBlockRef epsilon_bb = LLVMAppendBasicBlock(ctxt->func, "epsilon");
+
+  /* Basic block: epsilon */
+  LLVMBuildBr(ctxt->builder, epsilon_bb);
+  LLVMPositionBuilderAtEnd(ctxt->builder, epsilon_bb);
+
+  /*
+   * For epsilon we make a null-token parse result like with end, but we
+   * do it unconditionally.
+   */
+  LLVMValueRef make_result_args[] = {
+    ctxt->arena,
+    LLVMConstNull(ctxt->llvm_parsedtokenptr)
+  };
+  LLVMValueRef result_ptr = LLVMBuildCall(ctxt->builder,
+    LLVMGetNamedFunction(ctxt->mod, "make_result"),
+    make_result_args, 2, "result_ptr");
+  /* Return it */
+  LLVMBuildRet(ctxt->builder, result_ptr);
+
+  return true;
+}
+
+#endif
+
 static const HParserVtable epsilon_vt = {
   .parse = parse_epsilon,
   .isValidRegular = h_true,
   .isValidCF = h_true,
   .desugar = desugar_epsilon,
   .compile_to_rvm = epsilon_ctrvm,
+#ifdef HAMMER_LLVM_BACKEND
+  .llvm = epsilon_llvm,
+#endif
   .higher = false,
 };