Skip to content

Commit

Permalink
cxxrtl: minimize stack space consumed by debug_info().
Browse files Browse the repository at this point in the history
This commit uses parameter packs to sink `debug_item()` construction
into the `debug_info()`-specific `add()` overload. This makes the stack
space use sub-linear in typical case rather than linear (which is still
the worst case). Oddly, the stack slots that get allocated now are all
for the `0` literal for `lsb_offset`. This could be fixed by allocating
numbers statically but the existing reduction in stack use of ~98% for
a representative example (Minerva SoC) should be enough.
  • Loading branch information
whitequark committed May 8, 2024
1 parent 80798da commit 6e003e1
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 26 deletions.
55 changes: 31 additions & 24 deletions backends/cxxrtl/cxxrtl_backend.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2473,37 +2473,41 @@ struct CxxrtlWorker {
if (has_driven_sync + has_driven_comb + has_undriven > 1)
count_mixed_driver++;

f << indent << "items->add(path, " << escape_cxx_string(get_hdl_name(wire));
f << ", debug_item(" << mangle(wire) << ", " << wire->start_offset;
bool first = true;
for (auto flag : flags) {
if (first) {
first = false;
f << ", ";
} else {
f << "|";
f << indent << "items->add(path, " << escape_cxx_string(get_hdl_name(wire)) << ", ";
dump_debug_attrs(wire);
f << ", " << mangle(wire);
if (wire->start_offset != 0 || !flags.empty()) {
f << ", " << wire->start_offset;
bool first = true;
for (auto flag : flags) {
if (first) {
first = false;
f << ", ";
} else {
f << "|";
}
f << "debug_item::" << flag;
}
f << "debug_item::" << flag;
}
f << "), ";
dump_debug_attrs(wire);
f << ");\n";
count_member_wires++;
break;
}
case WireType::ALIAS: {
// Alias of a member wire
const RTLIL::Wire *aliasee = debug_wire_type.sig_subst.as_wire();
f << indent << "items->add(path, " << escape_cxx_string(get_hdl_name(wire));
f << ", debug_item(";
f << indent << "items->add(path, " << escape_cxx_string(get_hdl_name(wire)) << ", ";
dump_debug_attrs(aliasee);
f << ", ";
// If the aliasee is an outline, then the alias must be an outline, too; otherwise downstream
// tooling has no way to find out about the outline.
if (debug_wire_types[aliasee].is_outline())
f << "debug_eval_outline";
else
f << "debug_alias()";
f << ", " << mangle(aliasee) << ", " << wire->start_offset << "), ";
dump_debug_attrs(aliasee);
f << ", " << mangle(aliasee);
if (wire->start_offset != 0)
f << ", " << wire->start_offset;
f << ");\n";
count_alias_wires++;
break;
Expand All @@ -2513,18 +2517,22 @@ struct CxxrtlWorker {
f << indent << "static const value<" << wire->width << "> const_" << mangle(wire) << " = ";
dump_const(debug_wire_type.sig_subst.as_const());
f << ";\n";
f << indent << "items->add(path, " << escape_cxx_string(get_hdl_name(wire));
f << ", debug_item(const_" << mangle(wire) << ", " << wire->start_offset << "), ";
f << indent << "items->add(path, " << escape_cxx_string(get_hdl_name(wire)) << ", ";
dump_debug_attrs(wire);
f << ", const_" << mangle(wire);
if (wire->start_offset != 0)
f << ", " << wire->start_offset;
f << ");\n";
count_const_wires++;
break;
}
case WireType::OUTLINE: {
// Localized or inlined, but rematerializable wire
f << indent << "items->add(path, " << escape_cxx_string(get_hdl_name(wire));
f << ", debug_item(debug_eval_outline, " << mangle(wire) << ", " << wire->start_offset << "), ";
f << indent << "items->add(path, " << escape_cxx_string(get_hdl_name(wire)) << ", ";
dump_debug_attrs(wire);
f << ", debug_eval_outline, " << mangle(wire);
if (wire->start_offset != 0)
f << ", " << wire->start_offset;
f << ");\n";
count_inline_wires++;
break;
Expand All @@ -2540,15 +2548,14 @@ struct CxxrtlWorker {
for (auto &mem : mod_memories[module]) {
if (!mem.memid.isPublic())
continue;
f << indent << "items->add(path, " << escape_cxx_string(mem.packed ? get_hdl_name(mem.cell) : get_hdl_name(mem.mem));
f << ", debug_item(" << mangle(&mem) << ", ";
f << mem.start_offset << "), ";
f << indent << "items->add(path, " << escape_cxx_string(mem.packed ? get_hdl_name(mem.cell) : get_hdl_name(mem.mem)) << ", ";
if (mem.packed) {
dump_debug_attrs(mem.cell);
} else {
dump_debug_attrs(mem.mem);
}
f << ");\n";
f << ", " << mangle(&mem) << ", ";
f << mem.start_offset << ");\n";
}
}
dec_indent();
Expand Down
5 changes: 3 additions & 2 deletions backends/cxxrtl/runtime/cxxrtl/cxxrtl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1467,8 +1467,9 @@ struct debug_items {
}

// This overload exists to reduce excessive stack slot allocation in `CXXRTL_EXTREMELY_COLD void debug_info()`.
void add(const std::string &base_path, const char *path, debug_item &&item, const char *serialized_item_attrs) {
add(base_path + path, std::move(item), metadata::deserialize(serialized_item_attrs));
template<class... T>
void add(const std::string &base_path, const char *path, const char *serialized_item_attrs, T&&... args) {
add(base_path + path, debug_item(std::forward<T>(args)...), metadata::deserialize(serialized_item_attrs));
}

size_t count(const std::string &path) const {
Expand Down

0 comments on commit 6e003e1

Please sign in to comment.