Skip to content

Commit 3b81c0f

Browse files
committed
Rewrite recursive generation of binary IFs for accept state into iteration.
1 parent 58b687e commit 3b81c0f

File tree

1 file changed

+46
-25
lines changed

1 file changed

+46
-25
lines changed

src/codegen/pass2_generate.cc

+46-25
Original file line numberDiff line numberDiff line change
@@ -930,30 +930,6 @@ static void gen_go(
930930
}
931931
}
932932

933-
static CodeList* emit_accept_binary(Output& output,
934-
const Adfa& dfa,
935-
const char* var,
936-
const uniq_vector_t<AcceptTrans>& acc,
937-
size_t l,
938-
size_t r) {
939-
OutAllocator& alc = output.allocator;
940-
Scratchbuf& o = output.scratchbuf;
941-
942-
CodeList* stmts = code_list(alc);
943-
if (l < r) {
944-
const size_t m = (l + r) >> 1;
945-
const char* cmp = output.block().binops[r == l + 1 ? OP_CMP_EQ : OP_CMP_LE];
946-
const char* if_cond = o.cstr(var).cstr(" ").cstr(cmp).cstr(" ").u64(m).flush();
947-
CodeList* if_then = emit_accept_binary(output, dfa, var, acc, l, m);
948-
CodeList* if_else = emit_accept_binary(output, dfa, var, acc, m + 1, r);
949-
append(stmts, code_if_then_else(alc, if_cond, if_then, if_else));
950-
} else {
951-
const CodeJump jump = {acc[l].state, acc[l].tags, false, false, false};
952-
gen_goto(output, dfa, stmts, nullptr, jump);
953-
}
954-
return stmts;
955-
}
956-
957933
static void emit_accept(
958934
Output& output, CodeList* stmts, const Adfa& dfa, const uniq_vector_t<AcceptTrans>& acc) {
959935
const opt_t* opts = output.block().opts;
@@ -1012,7 +988,52 @@ static void emit_accept(
1012988

1013989
// nested ifs
1014990
if (opts->nested_ifs || nacc == 2) {
1015-
append(stmts, emit_accept_binary(output, dfa, var, acc, 0, nacc - 1));
991+
// Stack: store left/right bounds and the intermediate result for left subarray.
992+
struct Bounds { uint32_t left, right; CodeList* code; };
993+
std::vector<Bounds> stack;
994+
stack.push_back({0, static_cast<uint32_t>(nacc) - 1, nullptr});
995+
996+
// Return value.
997+
CodeList* code = nullptr;
998+
999+
// Create another invalid pointer to distinguish 1st and 2nd visit.
1000+
CodeList* const nullptr2 = reinterpret_cast<CodeList*>(~0lu);
1001+
1002+
while (!stack.empty()) {
1003+
Bounds& x = stack.back();
1004+
uint32_t l = x.left;
1005+
uint32_t r = x.right;
1006+
1007+
if (l == r) {
1008+
// recursion terminates, generate code for transition
1009+
code = code_list(alc);
1010+
const CodeJump jump = {acc[l].state, acc[l].tags, false, false, false};
1011+
gen_goto(output, dfa, code, nullptr, jump);
1012+
stack.pop_back();
1013+
} else {
1014+
DCHECK(l < r);
1015+
const uint32_t m = (l + r) / 2;
1016+
1017+
if (x.code == nullptr) {
1018+
// 1st visit: recurse into the left part
1019+
x.code = nullptr2;
1020+
stack.push_back({l, m, nullptr});
1021+
} else if (x.code == nullptr2) {
1022+
// 2nd visit: save code for the left part, recurse into the right part
1023+
x.code = code;
1024+
stack.push_back({m + 1, r, nullptr});
1025+
} else {
1026+
// 3rd and final visit: combine code for left and right parts
1027+
const char* cmp = output.block().binops[r == l + 1 ? OP_CMP_EQ : OP_CMP_LE];
1028+
const char* cond = buf.cstr(var).cstr(" ").cstr(cmp).cstr(" ").u64(m).flush();
1029+
CodeList* result = code_list(alc);
1030+
append(result, code_if_then_else(alc, cond, x.code, code));
1031+
code = result;
1032+
stack.pop_back();
1033+
}
1034+
}
1035+
}
1036+
append(stmts, code);
10161037
return;
10171038
}
10181039

0 commit comments

Comments
 (0)