From 71e6e31795315348370027bdd933a9c835fc1d04 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 23 Jun 2026 10:53:35 +0200 Subject: [PATCH] ast, flatten, hierarchy: canonically split hierarchical references into twines --- frontends/ast/ast.cc | 16 ++++++++++++++++ frontends/ast/ast.h | 3 +++ frontends/ast/genrtlil.cc | 16 ++++++++-------- passes/hierarchy/flatten.cc | 17 +++++------------ passes/hierarchy/hierarchy.cc | 10 ++++++---- 5 files changed, 38 insertions(+), 24 deletions(-) diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 1bb79a2ce..89f517fc2 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -1104,6 +1104,22 @@ std::string AstNode::loc_string() const return stringf("%s:%d.%d-%d.%d", location.begin.filename->c_str(), location.begin.line, location.begin.column, location.end.line, location.end.column); } +static TwineRef build_hier_content(TwinePool &pool, std::string_view content) +{ + size_t dot = content.rfind('.'); + if (dot == std::string_view::npos) + return pool.add(Twine{std::string{content}}).tag(true); + TwineRef prefix = build_hier_content(pool, content.substr(0, dot)); + return pool.add(Twine{Twine::Suffix{prefix, std::string{content.substr(dot)}}}); +} + +TwineRef AST::intern_hier_name(RTLIL::Design *design, std::string_view escaped) +{ + if (escaped.size() > 1 && escaped[0] == '\\') + return build_hier_content(design->twines, escaped.substr(1)); + return design->twines.add(std::string{escaped}); +} + void AST::set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast) { if (!current_module || !current_module->design) diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 100376125..038b25a29 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -429,6 +429,9 @@ namespace AST AstNode * find_modport(AstNode *intf, std::string name); void explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule, std::string intfname, AstNode *modport); + // Intern Verilog hierarchical reference "a.b.c" as a Suffix chain "a" ".b" ".c" + TwineRef intern_hier_name(RTLIL::Design *design, std::string_view escaped); + // Helper for setting the src attribute. void set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast); diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 95d63472d..e7496c41e 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -178,7 +178,7 @@ static void check_unique_id(RTLIL::Module *module, RTLIL::IdString id, to_add_kind, id.c_str(), existing_kind, location_str.c_str()); }; - TwineRef id_tw = module->design->twines.find(id.str()); + TwineRef id_tw = intern_hier_name(module->design, id.str()); if (const RTLIL::Wire *wire = module->wire(id_tw)) already_exists(wire, "signal"); if (const RTLIL::Cell *cell = module->cell(id_tw)) @@ -1478,7 +1478,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) // signals. RTLIL::IdString id = str; check_unique_id(current_module, id, this, "interface port"); - RTLIL::Wire *wire = current_module->addWire(current_module->design->twines.add(std::string{id.str()}), 1); + RTLIL::Wire *wire = current_module->addWire(intern_hier_name(current_module->design, id.str()), 1); set_src_attr(wire, this); wire->start_offset = 0; wire->port_id = port_id; @@ -1518,7 +1518,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) RTLIL::Const val = children[0]->bitsAsConst(); RTLIL::IdString id = str; check_unique_id(current_module, id, this, "pwire"); - RTLIL::Wire *wire = current_module->addWire(current_module->design->twines.add(std::string{id.str()}), GetSize(val)); + RTLIL::Wire *wire = current_module->addWire(intern_hier_name(current_module->design, id.str()), GetSize(val)); current_module->connect(wire, val); wire->is_signed = children[0]->is_signed; @@ -1543,7 +1543,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) RTLIL::IdString id = str; check_unique_id(current_module, id, this, "signal"); - RTLIL::Wire *wire = current_module->addWire(current_module->design->twines.add(std::string{id.str()}), range_left - range_right + 1); + RTLIL::Wire *wire = current_module->addWire(intern_hier_name(current_module->design, id.str()), range_left - range_right + 1); set_src_attr(wire, this); wire->start_offset = range_right; wire->port_id = port_id; @@ -1574,7 +1574,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) input_error("Memory `%s' with non-constant width or size!\n", str); check_unique_id(current_module, RTLIL::IdString(str), this, "memory"); - RTLIL::Memory *memory = current_module->addMemory(current_module->design->twines.add(std::string{str})); + RTLIL::Memory *memory = current_module->addMemory(intern_hier_name(current_module->design, str)); set_src_attr(memory, this); memory->width = children[0]->range_left - children[0]->range_right + 1; if (children[1]->range_right < children[1]->range_left) { @@ -1629,10 +1629,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) log_assert(id2ast != nullptr); - TwineRef str_ref = current_module->design->twines.find(str); + TwineRef str_ref = intern_hier_name(current_module->design, str); if (id2ast->type == AST_AUTOWIRE && current_module->wire(str_ref) == nullptr) { - RTLIL::Wire *wire = current_module->addWire(current_module->design->twines.add(std::string{str})); + RTLIL::Wire *wire = current_module->addWire(str_ref); str_ref = wire->name.ref(); set_src_attr(wire, this); @@ -2192,7 +2192,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) RTLIL::IdString id = str; check_unique_id(current_module, id, this, "cell"); - RTLIL::Cell *cell = current_module->addCell(current_module->design->twines.add(std::string{id.str()}), Twine::Null); + RTLIL::Cell *cell = current_module->addCell(intern_hier_name(current_module->design, id.str()), Twine::Null); set_src_attr(cell, this); for (auto it = children.begin(); it != children.end(); it++) { diff --git a/passes/hierarchy/flatten.cc b/passes/hierarchy/flatten.cc index 2a9659c14..efe4029d4 100644 --- a/passes/hierarchy/flatten.cc +++ b/passes/hierarchy/flatten.cc @@ -69,15 +69,8 @@ std::string concat_name(RTLIL::Cell *cell, std::string_view object_name_view, co return prefix + tail; } -// Build the flattened name of a template object, given the instance's already -// interned public/private prefix leaves. A name like "\a.b.c.w" is stored as -// nested Suffix nodes Suffix{Suffix{Suffix{"\a.", "b."}, "c."}, "w"}. When the -// template was itself flattened earlier its names are already such Suffixes, so -// flattening instance "u" re-prefixes only the innermost leaf ("\a." -> "\u.a.") -// and reuses the rest, yielding "\u.a.b.c.w" while keeping "b.", "c.", "w" -// shared -- rather than materialising "a.b.c.w" as one fresh tail per object. TwineRef remap_flattened_name(RTLIL::Design *design, TwineRef obj_ref, - TwineRef pub_prefix_ref, TwineRef priv_prefix_ref, dict &memo) + TwineRef pub_prefix_ref, TwineRef priv_prefix_ref, const std::string &separator, dict &memo) { if (auto it = memo.find(obj_ref); it != memo.end()) return it->second; @@ -87,13 +80,13 @@ TwineRef remap_flattened_name(RTLIL::Design *design, TwineRef obj_ref, if (node.is_suffix()) { const Twine::Suffix &sfx = node.suffix(); TwineRef prefix = remap_flattened_name(design, twine_tag(sfx.prefix, obj_ref.is_public()), - pub_prefix_ref, priv_prefix_ref, memo); + pub_prefix_ref, priv_prefix_ref, separator, memo); result = design->twines.add(Twine{Twine::Suffix{prefix, sfx.tail}}); } else { std::string escaped = design->twines.str(obj_ref); std::string_view obj = escaped; if (!obj.empty() && obj[0] == '\\') { - result = design->twines.add(Twine{Twine::Suffix{pub_prefix_ref, std::string(obj.substr(1))}}); + result = design->twines.add(Twine{Twine::Suffix{pub_prefix_ref, separator + std::string(obj.substr(1))}}); } else { constexpr std::string_view flatten_prefix = "$flatten"; if (obj.substr(0, flatten_prefix.size()) == flatten_prefix) @@ -171,11 +164,11 @@ struct FlattenWorker { // Copy the contents of the flattened cell - TwineRef pub_prefix_ref = design->twines.add(cell->name.str() + separator); + TwineRef pub_prefix_ref = cell->name.ref(); TwineRef priv_prefix_ref = design->twines.add("$flatten" + cell->name.str() + separator); dict remap_memo; auto make_name = [&](TwineRef obj_ref) -> TwineRef { - return module->uniquify(remap_flattened_name(design, obj_ref, pub_prefix_ref, priv_prefix_ref, remap_memo)); + return module->uniquify(remap_flattened_name(design, obj_ref, pub_prefix_ref, priv_prefix_ref, separator, remap_memo)); }; dict memory_map; diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index a2ddda1c4..656e27340 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -20,6 +20,7 @@ #include "kernel/yosys.h" #include "frontends/verific/verific.h" +#include "frontends/ast/ast.h" #include #include #include @@ -282,10 +283,11 @@ struct IFExpander // Go over all wires in interface, and add replacements to lists. std::string conn_name_str(design.twines.str(conn_name)); for (auto mod_wire : mod_replace_ports->wires()) { - std::string signal_name1 = conn_name_str + "." + design.twines.unescaped_str(mod_wire->name.ref()); - std::string signal_name2 = interface_name.str() + "." + design.twines.unescaped_str(mod_wire->name.ref()); - connections_to_add.push_back(design.twines.add(std::string{signal_name1})); - TwineRef signal_name2_ref = TwineSearch(&design.twines).find(signal_name2); + std::string member = design.twines.unescaped_str(mod_wire->name.ref()); + std::string signal_name1 = conn_name_str + "." + member; + std::string signal_name2 = interface_name.str() + "." + member; + connections_to_add.push_back(AST::intern_hier_name(&design, signal_name1)); + TwineRef signal_name2_ref = AST::intern_hier_name(&design, signal_name2); if(module.wire(signal_name2_ref) == nullptr) { log_error("Could not find signal '%s' in '%s'\n", signal_name2.c_str(), design.twines.str(module.meta_->name).data());