diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 01a4e9f7b..57c8ddc87 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -47,32 +47,69 @@ void apply_prefix(IdString prefix, IdString &id) id = stringf("$techmap%s.%s", prefix, id); } -TwineRef apply_prefix_ref(IdString prefix, IdString id, RTLIL::Design *design) +// Prefixes a template object's name with an instance's "." (public) or +// "$techmap." (private) prefix, for one cell's worth of instantiation. +// A name like "\a.b.c" is stored as nested Suffix nodes +// Suffix{Suffix{"\a.", "b."}, "c"}; recursing the Suffix chain re-prefixes only +// the innermost leaf ("\a." -> "\u.a.") and reuses the rest, so "b.", "c" stay +// shared instead of materialising "a.b.c" as one fresh tail per object. +// Reads the template name from TwinePool src and writes TwinePool dst. +struct PrefixApplier { - std::string ids = id.str(); - std::string shared, tail; - if (!ids.empty() && ids[0] == '\\') { - shared = prefix.str() + "."; - tail = ids.substr(1); - } else { - shared = "$techmap" + prefix.str() + "."; - tail = std::move(ids); - } - TwineRef pref = design->twines.add(std::move(shared)); - return design->twines.add(Twine{Twine::Suffix{pref, std::move(tail)}}); -} + RTLIL::Design *dst; + RTLIL::Design *src; + TwineRef cell_name; + TwineRef pub_prefix; + TwineRef priv_prefix = Twine::Null; + dict memo; -void apply_prefix(IdString prefix, RTLIL::SigSpec &sig, RTLIL::Module *module) -{ - vector chunks = sig; - for (auto &chunk : chunks) - if (chunk.wire != nullptr) { - TwineRef wire_ref = apply_prefix_ref(prefix, chunk.wire->name, module->design); - log_assert(module->wire(wire_ref) != nullptr); - chunk.wire = module->wire(wire_ref); + PrefixApplier(RTLIL::Design *dst, TwineRef prefix, RTLIL::Design *src) + : dst(dst), src(src), cell_name(prefix) + { + pub_prefix = dst->twines.add(Twine{Twine::Suffix{prefix, "."}}); + } + + // "$techmap." can't reuse the cell name's nodes (a tail is appended, + // not prepended), so it is the one prefix we materialise -- lazily, since + // many templates have no private wires. + TwineRef techmap_prefix() + { + if (priv_prefix == Twine::Null) + priv_prefix = dst->twines.add("$techmap" + dst->twines.str(cell_name) + "."); + return priv_prefix; + } + + TwineRef name(TwineRef obj_ref) + { + if (auto it = memo.find(obj_ref); it != memo.end()) + return it->second; + + const Twine &node = src->twines[obj_ref]; + TwineRef result; + if (node.is_suffix()) { + const Twine::Suffix &sfx = node.suffix(); + TwineRef prefix = name(twine_tag(sfx.prefix, obj_ref.is_public())); + result = dst->twines.add(Twine{Twine::Suffix{prefix, sfx.tail}}); + } else { + TwineRef prefix = obj_ref.is_public() ? pub_prefix : techmap_prefix(); + result = dst->twines.add(Twine{Twine::Suffix{prefix, node.leaf()}}); } - sig = chunks; -} + memo[obj_ref] = result; + return result; + } + + void apply(RTLIL::SigSpec &sig, RTLIL::Module *module) + { + vector chunks = sig; + for (auto &chunk : chunks) + if (chunk.wire != nullptr) { + TwineRef wire_ref = name(chunk.wire->name.ref()); + log_assert(module->wire(wire_ref) != nullptr); + chunk.wire = module->wire(wire_ref); + } + sig = chunks; + } +}; struct TechmapWorker { @@ -185,6 +222,8 @@ struct TechmapWorker break; } + PrefixApplier ap(module->design, cell->name.ref(), tpl->design); + dict memory_renames; for (auto &it : tpl->memories) { @@ -222,7 +261,7 @@ struct TechmapWorker autopurge_tpl_bits.insert(bit); } } - TwineRef w_ref = apply_prefix_ref(cell->name, tpl_w->name, module->design); + TwineRef w_ref = ap.name(tpl_w->name.ref()); RTLIL::Wire *w = module->wire(w_ref); if (w != nullptr) { temp_renamed_wires[w] = w->name.ref(); @@ -280,18 +319,18 @@ struct TechmapWorker if (w->port_output && !w->port_input) { c.first = it.second; c.second = RTLIL::SigSpec(w); - apply_prefix(cell->name, c.second, module); + ap.apply(c.second, module); extra_connect.first = c.second; extra_connect.second = c.first; } else if (!w->port_output && w->port_input) { c.first = RTLIL::SigSpec(w); c.second = it.second; - apply_prefix(cell->name, c.first, module); + ap.apply(c.first, module); extra_connect.first = c.first; extra_connect.second = c.second; } else { SigSpec sig_tpl = w, sig_tpl_pf = w, sig_mod = it.second; - apply_prefix(cell->name, sig_tpl_pf, module); + ap.apply(sig_tpl_pf, module); for (int i = 0; i < GetSize(sig_tpl) && i < GetSize(sig_mod); i++) { if (tpl_written_bits.count(sig_tpl[i])) { c.first.append(sig_mod[i]); @@ -350,7 +389,7 @@ struct TechmapWorker else if (const char *p = strstr(tpl_cell->name.str().c_str(), "_TECHMAP_REPLACE_.")) c_ref = module->design->twines.add(stringf("%s%s", orig_cell_name, p + strlen("_TECHMAP_REPLACE_"))); else - c_ref = apply_prefix_ref(cell->name, tpl_cell->name, module->design); + c_ref = ap.name(tpl_cell->name.ref()); RTLIL::Cell *c = module->addCell(c_ref, tpl_cell); design->select(module, c); @@ -378,7 +417,7 @@ struct TechmapWorker autopurge_ports.push_back(conn.first); } else { RTLIL::SigSpec new_conn = conn.second; - apply_prefix(cell->name, new_conn, module); + ap.apply(new_conn, module); port_signal_map.apply(new_conn); c->setPort(conn.first, std::move(new_conn)); } @@ -410,8 +449,8 @@ struct TechmapWorker for (auto &it : tpl->connections()) { RTLIL::SigSig c = it; - apply_prefix(cell->name.str(), c.first, module); - apply_prefix(cell->name.str(), c.second, module); + ap.apply(c.first, module); + ap.apply(c.second, module); port_signal_map.apply(c.first); port_signal_map.apply(c.second); module->connect(c);