diff --git a/src/libfsm/print/llvm.c b/src/libfsm/print/llvm.c index 2d896aa1c..a2728dafd 100644 --- a/src/libfsm/print/llvm.c +++ b/src/libfsm/print/llvm.c @@ -109,12 +109,6 @@ print_decl(FILE *f, const char *name, unsigned n) fprintf(f, "\t%%%s%u = ", name, n); } -static void -print_ret(FILE *f, long l) -{ - fprintf(f, "\tret i32 %ld\n", l); -} - static void vprint_label(FILE *f, bool decl, const char *fmt, va_list ap) { @@ -528,23 +522,72 @@ fsm_print_llvmfrag(FILE *f, const struct dfavm_assembler_ir *a, print_jump(f, a->linked); - print_label(f, true, "fail"); - print_ret(f, -1); - + /* + * We're jumping to ret*: labels, and having each jump + * to a single stop: with a phi instruction. + * + * This looks like: + * + * stop: + * %ret = phi i32 + * [u0x1, %ret0], ; "abc" + * [u0x2, %ret1], ; "xyz" + * [u0x3, %ret2], ; "abc", "xyz" + * [-1, %fail] + * ret i32 %ret + * fail: + * br label %stop + * ret0: + * br label %stop + * ret1: + * br label %stop + * ret2: + * br label %stop + * + * And we jump to stop: via the ret*: labels rather than + * to a phi node directly. This helps for two reasons: + * + * - We don't need to track every location in the DFA + * that can stop. In other words, many basic blocks + * jump to the same ret*: label. + * + * - The number of basic blocks grows quadratically + * (as DFA grow quadratically), but the set of endids + * remains constant. So the phi list is small. + * + * llvm doesn't find this optimisation for us. + */ + print_label(f, true, "stop"); + fprintf(f, "\t%%ret = phi i32\n"); for (size_t i = 0; i < retlist.count; i++) { + fprintf(f, "\t "); + if (opt->endleaf != NULL) { - print_label(f, true, "ret%zu", i); if (-1 == opt->endleaf(f, retlist.a[i].ids, retlist.a[i].count, - opt->endleaf_opaque)) + &i)) // XXX: passing &i rather than opt->endleaf_opaque is a hack { return -1; } } else { - print_label(f, true, "ret%zu", i); - print_ret(f, retlist.a[i].ir_state - ir->states); + fprintf(f, "[%td, %%ret%zu],\n", + retlist.a[i].ir_state - ir->states, i); } } + fprintf(f, "\t%s[-1, %%fail]\n", " "); + fprintf(f, "\tret i32 %%ret\n"); + + print_label(f, true, "fail"); + fprintf(f, "\tbr "); + print_label(f, false, "stop"); + fprintf(f, "\n"); + + for (size_t i = 0; i < retlist.count; i++) { + print_label(f, true, "ret%zu", i); + fprintf(f, "\tbr "); + print_label(f, false, "stop"); + fprintf(f, "\n"); + } } struct frame frame = { 0, 0, 0 }; diff --git a/src/re/main.c b/src/re/main.c index a7c8bc803..c29108ab9 100644 --- a/src/re/main.c +++ b/src/re/main.c @@ -503,10 +503,11 @@ endleaf_llvm(FILE *f, unsigned n; size_t i; - assert(endleaf_opaque == NULL); + /* hack for llvm codegen only */ + const size_t *ret = endleaf_opaque; + assert(ret != NULL); (void) f; - (void) endleaf_opaque; n = 0; @@ -516,7 +517,7 @@ endleaf_llvm(FILE *f, } } - fprintf(f, "\tret i32 u%#x", (unsigned) n); + fprintf(f, "[u%#x, %%ret%zu],", (unsigned) n, *ret); fprintf(f, " ; ");