Skip to content

Commit

Permalink
Generalize the computed-gotos code generation for C/C++ backend
Browse files Browse the repository at this point in the history
Previously the code-generation did similar table generation across
the normal states, accept states and condtional variables.
This refactor introduces some utility functions that provides the same
logic across the different tables.
  • Loading branch information
caffe3 authored and skvadrik committed Feb 27, 2025
1 parent f505631 commit afabf6e
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 56 deletions.
2 changes: 2 additions & 0 deletions src/codegen/output.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ class Scratchbuf {
Scratchbuf& u64(uint64_t u) { os << u; return *this; }
Scratchbuf& str(const std::string& s) { os << s; return *this; }
Scratchbuf& cstr(const char* s) { os << s; return *this; }
Scratchbuf& label(const std::string& s) { os << s; return *this; }
Scratchbuf& label(uint32_t u) { os << u; return *this; }
Scratchbuf& exact_uint(size_t width);
const char* flush();

Expand Down
99 changes: 43 additions & 56 deletions src/codegen/pass2_generate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,34 @@ static CodeList* gen_goswif(
: gen_goif(output, dfa, go->goif, from);
}

template<typename label_t>
static const char* gen_gocp_entry(Scratchbuf& buf, bool relative, const std::string& prefix,
const label_t base_label, const label_t label) {
if (relative) {
// TODO: port to syntax file and replace hardcoded `int` with `code:type_yytarget`
buf.cstr("(int)(").cstr("(char*)").cstr("&&").str(prefix)
.label(label).cstr(" - (char*)").cstr("&&")
.str(prefix).label(base_label).cstr(")");
} else {
buf.cstr("&&").str(prefix).label(label);
}
return buf.flush();
}

template<typename label_t>
static const char* gen_gocp_goto(Scratchbuf& buf, bool relative, const std::string& prefix,
const label_t base_label, const std::string& table, const std::string& entry) {
buf.cstr("*");
if (relative) {
buf.cstr("((char *)&&").str(prefix).label(base_label).cstr(" + ");
}
buf.str(table).cstr("[").str(entry).cstr("]");
if (relative) {
buf.cstr(")");
}
return buf.flush();
}

static CodeList* gen_gocp_table(Output& output, const CodeGoCpTable* go, uint32_t min_index) {
const opt_t* opts = output.block().opts;
OutAllocator& alc = output.allocator;
Expand All @@ -762,15 +790,8 @@ static CodeList* gen_gocp_table(Output& output, const CodeGoCpTable* go, uint32_
const char** elems = alc.alloct<const char*>(CodeGoCpTable::TABLE_SIZE);

for (uint32_t i = 0; i < CodeGoCpTable::TABLE_SIZE; ++i) {
if (opts->computed_gotos_relative) {
// TODO: port to syntax file and replace hardcoded `int` with `code:type_yytarget`
buf.cstr("(int)(").cstr("(char*)").cstr("&&").str(opts->label_prefix)
.u32(go->table[i]->label->index).cstr(" - (char*)").cstr("&&")
.str(opts->label_prefix).u32(min_index).cstr(")");
} else {
buf.cstr("&&").str(opts->label_prefix).u32(go->table[i]->label->index);
}
elems[i] = buf.flush();
elems[i] = gen_gocp_entry(buf, opts->computed_gotos_relative, opts->label_prefix,
min_index, go->table[i]->label->index);
}

const char* name = opts->var_computed_gotos_table.c_str();
Expand Down Expand Up @@ -799,16 +820,9 @@ static CodeList* gen_gocp(Output& output, const Adfa& dfa, const CodeGoCp* go, c
CodeList* stmts = code_list(alc);
CodeList* if_else = gen_gocp_table(output, go->table, min_index);

buf.cstr("*");
if (opts->computed_gotos_relative) {
buf.cstr("((char *)&&").str(opts->label_prefix).u32(min_index).cstr(" + ");
}
buf.str(opts->var_computed_gotos_table).cstr("[").str(opts->var_char).cstr("]");
if (opts->computed_gotos_relative) {
buf.cstr(")");
}

append(if_else, code_goto(alc, buf.flush()));
const char* goto_address = gen_gocp_goto(buf, opts->computed_gotos_relative, opts->label_prefix,
min_index, opts->var_computed_gotos_table, opts->var_char);
append(if_else, code_goto(alc, goto_address));

if (go->hgo != nullptr) {
const char* cond =
Expand Down Expand Up @@ -954,15 +968,8 @@ static void emit_accept(
const char** elems = alc.alloct<const char*>(nacc);

for (uint32_t i = 0; i < nacc; ++i) {
if (opts->computed_gotos_relative) {
// TODO: port to syntax file and replace hardcoded `int` with `code:type_yytarget`
buf.cstr("(int)(").cstr("(char*)").cstr("&&").str(opts->label_prefix)
.u32(acc[i].state->label->index).cstr(" - (char*)").cstr("&&")
.str(opts->label_prefix).u32(min_index).cstr(")");
} else {
buf.cstr("&&").str(opts->label_prefix).u32(acc[i].state->label->index);
}
elems[i] = buf.flush();
elems[i] = gen_gocp_entry(buf, opts->computed_gotos_relative,
opts->label_prefix, min_index, acc[i].state->label->index);
}

const char* name = opts->var_computed_gotos_table.c_str();
Expand All @@ -971,15 +978,9 @@ static void emit_accept(
// In rec/func mode the table can be local, as it's used in the same function.
append(block, code_array(alc, name, type, elems, nacc, /*local*/ true));

buf.cstr("*");
if (opts->computed_gotos_relative) {
buf.cstr("((char *)&&").str(opts->label_prefix).u32(min_index).cstr(" + ");
}
buf.str(opts->var_computed_gotos_table).cstr("[").cstr(var).cstr("]");
if (opts->computed_gotos_relative) {
buf.cstr(")");
}
append(block, code_goto(alc, buf.flush()));
const char* goto_address = gen_gocp_goto(buf, opts->computed_gotos_relative,
opts->label_prefix, min_index, opts->var_computed_gotos_table, var);
append(block, code_goto(alc, goto_address));

append(stmts, code_block(alc, block, CodeBlock::Kind::WRAPPED));
return;
Expand Down Expand Up @@ -1618,16 +1619,9 @@ static CodeList* gen_cond_goto(Output& output) {
const char* getcond = opts->gen_code_yygetcond(buf, callback);

if (opts->computed_gotos) {
buf.cstr("*");
if (opts->computed_gotos_relative) {
buf.cstr("((char *)&&").str(opts->cond_label_prefix).str(conds.front().name).cstr(" + ");
}
buf.str(opts->var_cond_table).cstr("[").cstr(getcond).cstr("]");
if (opts->computed_gotos_relative) {
buf.cstr(")");
}

append(stmts, code_goto(alc, buf.flush()));
const char* goto_address = gen_gocp_goto(buf, opts->computed_gotos_relative,
opts->cond_label_prefix, conds.front().name, opts->var_cond_table, getcond);
append(stmts, code_goto(alc, goto_address));
} else if (opts->nested_ifs) {
warn_cond_ord &= ncond > 1;
append(stmts, gen_cond_goto_binary(output, getcond, 0, ncond - 1));
Expand Down Expand Up @@ -1668,15 +1662,8 @@ static CodeList* gen_cond_table(Output& output) {
const char** elems = alc.alloct<const char*>(conds.size());

for (uint32_t i = 0; i < conds.size(); ++i) {
if (opts->computed_gotos_relative) {
// TODO: port to syntax file and replace hardcoded `int` with `code:type_yytarget`
buf.cstr("(int)(").cstr("(char*)").cstr("&&").str(opts->cond_label_prefix)
.str(conds[i].name).cstr(" - (char*)").str(opts->cond_label_prefix)
.str(conds.front().name).cstr(")");
} else {
buf.cstr("&&").str(opts->cond_label_prefix).str(conds[i].name);
}
elems[i] = buf.flush();
elems[i] = gen_gocp_entry(buf, opts->computed_gotos_relative, opts->cond_label_prefix,
conds.front().name, conds[i].name);
}

const char* name = opts->var_cond_table.c_str();
Expand Down

0 comments on commit afabf6e

Please sign in to comment.