mirror of
https://github.com/YosysHQ/yosys.git
synced 2026-10-06 01:53:53 +02:00
twine: split Twine into in-memory TwineNode that doesn't support autoidx variants and temporary TwineSpec that does
This commit is contained in:
@@ -45,6 +45,7 @@ option(YOSYS_ENABLE_UNIT_TESTS "Enable unit tests" ON)
|
||||
option(YOSYS_ENABLE_COVERAGE "Enable code coverage" OFF)
|
||||
option(YOSYS_ENABLE_PROFILING "Enable instruction profiling" OFF)
|
||||
option(YOSYS_ENABLE_FUNCTIONAL_TESTS "Enable running functional tests" OFF)
|
||||
option(YOSYS_ENABLE_TWINE_PROVENANCE "Twine provenance for debugging. Worsens performance" OFF)
|
||||
|
||||
set(YOSYS_PROGRAM_PREFIX "" CACHE STRING "Name prefix for programs, libraries, and data")
|
||||
set(YOSYS_COMPONENTS "everything" CACHE STRING "List of components to build (use pass names)")
|
||||
@@ -323,6 +324,7 @@ condition(YOSYS_ENABLE_SLANG NOT YOSYS_WITHOUT_SLANG)
|
||||
add_feature_info(have_glob YOSYS_ENABLE_GLOB "Glob expansion in filenames")
|
||||
add_feature_info(have_spawn YOSYS_ENABLE_SPAWN "Passes that invoke external tools")
|
||||
add_feature_info(have_threads YOSYS_ENABLE_THREADS "Multithreaded netlist operations")
|
||||
add_feature_info(twine_provenance YOSYS_ENABLE_TWINE_PROVENANCE "Twine provenance for debugging. Worsens performance")
|
||||
add_feature_info(have_plugins YOSYS_ENABLE_PLUGINS "Dynamically loadable binary plugins")
|
||||
add_feature_info(with_abc YOSYS_ENABLE_ABC "Production-quality logic synthesis flow")
|
||||
add_feature_info(with_zlib YOSYS_ENABLE_ZLIB "Transparent Gzip decompression and FST file format support")
|
||||
|
||||
@@ -142,21 +142,26 @@ void RTLIL_BACKEND::dump_twines(std::ostream &f, const RTLIL::Design *design, co
|
||||
for (IdString id = used_id; id != IdString::Null && closed.insert(id).second; ) {
|
||||
ids.push_back(id);
|
||||
const TwineNode &n = design->twines[id];
|
||||
id = n.is_suffix() ? n.suffix().prefix.untag() : IdString();
|
||||
id = n.is_suffix() ? n.prefix() : IdString();
|
||||
}
|
||||
std::sort(ids.begin(), ids.end());
|
||||
|
||||
f << stringf("twines\n");
|
||||
for (IdString id : ids) {
|
||||
const TwineNode &n = design->twines[id];
|
||||
if (n.is_leaf()) {
|
||||
switch (n.kind()) {
|
||||
case TwineNode::Kind::Leaf:
|
||||
f << stringf(" leaf %zu ", id.raw());
|
||||
dump_const(f, RTLIL::Const(n.leaf()));
|
||||
dump_const(f, RTLIL::Const(std::string(n.text())));
|
||||
f << stringf("\n");
|
||||
} else if (n.is_suffix()) {
|
||||
f << stringf(" suffix %zu %zu ", id.raw(), n.suffix().prefix.raw());
|
||||
dump_const(f, RTLIL::Const(n.suffix().tail));
|
||||
break;
|
||||
case TwineNode::Kind::Suffix:
|
||||
f << stringf(" suffix %zu %zu ", id.raw(), n.prefix().raw());
|
||||
dump_const(f, RTLIL::Const(std::string(n.text())));
|
||||
f << stringf("\n");
|
||||
break;
|
||||
case TwineNode::Kind::Dead:
|
||||
break;
|
||||
}
|
||||
}
|
||||
f << stringf("end\n");
|
||||
|
||||
@@ -2514,7 +2514,7 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
|
||||
}
|
||||
f << stringf(");\n");
|
||||
if (!systemverilog && !module->processes.empty()) {
|
||||
initial_id = Twine(NEW_ID).content_str();
|
||||
initial_id = TwineSpec(NEW_ID).content_str();
|
||||
f << indent + " " << "reg " << id(initial_id) << " = 0;\n";
|
||||
}
|
||||
|
||||
|
||||
+14
-1
@@ -1117,7 +1117,7 @@ static IdString build_hier_content(TwinePool &pool, std::string_view content)
|
||||
if (dot == std::string_view::npos)
|
||||
return pool.add(std::string{content}).tag(true);
|
||||
IdString prefix = build_hier_content(pool, content.substr(0, dot));
|
||||
return pool.add(Twine::Suffix{prefix, std::string{content.substr(dot)}});
|
||||
return pool.add(TwineSpec::Suffix{prefix, std::string{content.substr(dot)}});
|
||||
}
|
||||
|
||||
IdString AST::intern_hier_name(RTLIL::Design *design, std::string_view escaped)
|
||||
@@ -1127,6 +1127,19 @@ IdString AST::intern_hier_name(RTLIL::Design *design, std::string_view escaped)
|
||||
return design->twines.add(std::string{escaped});
|
||||
}
|
||||
|
||||
IdString AST::intern_src_loc(RTLIL::Design *design, const AstSrcLocType &location)
|
||||
{
|
||||
return design->twines.add(stringf("$%s:%d",
|
||||
RTLIL::encode_filename(*location.begin.filename), location.begin.line));
|
||||
}
|
||||
|
||||
IdString AST::intern_src_name(RTLIL::Design *design, const AstSrcLocType &location,
|
||||
std::string_view kind, int idx)
|
||||
{
|
||||
return design->twines.add(TwineSpec::Suffix{intern_src_loc(design, location),
|
||||
stringf("%s$%d", kind, idx)});
|
||||
}
|
||||
|
||||
void AST::set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast)
|
||||
{
|
||||
obj->attributes[ID::src] = ast->loc_string();
|
||||
|
||||
@@ -437,6 +437,10 @@ namespace AST
|
||||
|
||||
IdString intern_hier_name(RTLIL::Design *design, std::string_view escaped);
|
||||
|
||||
IdString intern_src_loc(RTLIL::Design *design, const AstSrcLocType &location);
|
||||
IdString intern_src_name(RTLIL::Design *design, const AstSrcLocType &location,
|
||||
std::string_view kind, int idx);
|
||||
|
||||
// Helper for setting the src attribute.
|
||||
void set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast);
|
||||
|
||||
|
||||
+32
-28
@@ -44,11 +44,12 @@ using namespace AST_INTERNAL;
|
||||
// helper function for creating RTLIL code for unary operations
|
||||
static RTLIL::SigSpec uniop2rtlil(AstNode *that, IdString type, int result_width, const RTLIL::SigSpec &arg, bool gen_attributes = true)
|
||||
{
|
||||
IdString name = current_module->design->twines.add(stringf("%s$%s:%d$%d", current_module->design->twines.str(type).c_str(), RTLIL::encode_filename(*that->location.begin.filename), that->location.begin.line, autoidx++));
|
||||
IdString name = intern_src_name(current_module->design, that->location,
|
||||
current_module->design->twines.str(type), autoidx++);
|
||||
RTLIL::Cell *cell = current_module->addCell(name, type);
|
||||
set_src_attr(cell, that);
|
||||
|
||||
RTLIL::Wire *wire = current_module->addWire(Twine::Suffix{cell->name, "_Y"}, result_width);
|
||||
RTLIL::Wire *wire = current_module->addWire(TwineSpec::Suffix{cell->name, "_Y"}, result_width);
|
||||
set_src_attr(wire, that);
|
||||
wire->is_signed = that->is_signed;
|
||||
|
||||
@@ -76,7 +77,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s
|
||||
return;
|
||||
}
|
||||
|
||||
IdString name = current_module->design->twines.add(stringf("$extend$%s:%d$%d", RTLIL::encode_filename(*that->location.begin.filename), that->location.begin.line, autoidx++));
|
||||
IdString name = intern_src_name(current_module->design, that->location, "$extend", autoidx++);
|
||||
RTLIL::Cell *cell = current_module->addCell(name, ID($pos));
|
||||
set_src_attr(cell, that);
|
||||
|
||||
@@ -103,11 +104,12 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s
|
||||
// helper function for creating RTLIL code for binary operations
|
||||
static RTLIL::SigSpec binop2rtlil(AstNode *that, IdString type, int result_width, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
|
||||
{
|
||||
IdString name = current_module->design->twines.add(stringf("%s$%s:%d$%d", current_module->design->twines.str(type).c_str(), RTLIL::encode_filename(*that->location.begin.filename), that->location.begin.line, autoidx++));
|
||||
IdString name = intern_src_name(current_module->design, that->location,
|
||||
current_module->design->twines.str(type), autoidx++);
|
||||
RTLIL::Cell *cell = current_module->addCell(name, type);
|
||||
set_src_attr(cell, that);
|
||||
|
||||
RTLIL::Wire *wire = current_module->addWire(Twine::Suffix{cell->name, "_Y"}, result_width);
|
||||
RTLIL::Wire *wire = current_module->addWire(TwineSpec::Suffix{cell->name, "_Y"}, result_width);
|
||||
set_src_attr(wire, that);
|
||||
wire->is_signed = that->is_signed;
|
||||
|
||||
@@ -136,10 +138,9 @@ static RTLIL::SigSpec mux2rtlil(AstNode *that, const RTLIL::SigSpec &cond, const
|
||||
{
|
||||
log_assert(cond.size() == 1);
|
||||
|
||||
std::stringstream sstr;
|
||||
sstr << "$ternary$" << RTLIL::encode_filename(*that->location.begin.filename) << ":" << that->location.begin.line << "$" << (autoidx++);
|
||||
IdString name = intern_src_name(current_module->design, that->location, "$ternary", autoidx++);
|
||||
|
||||
RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($mux));
|
||||
RTLIL::Cell *cell = current_module->addCell(name, ID($mux));
|
||||
set_src_attr(cell, that);
|
||||
|
||||
RTLIL::Wire *wire = current_module->addWire(cell->name.str() + "_Y", left.size());
|
||||
@@ -351,7 +352,7 @@ struct AST_INTERNAL::ProcessGenerator
|
||||
LookaheadRewriter la_rewriter(always.get());
|
||||
|
||||
// generate process and simple root case
|
||||
proc = current_module->addProcess(stringf("$proc$%s:%d$%d", RTLIL::encode_filename(*always->location.begin.filename), always->location.begin.line, autoidx++));
|
||||
proc = current_module->addProcess(intern_src_name(current_module->design, always->location, "$proc", autoidx++));
|
||||
set_src_attr(proc, always.get());
|
||||
for (auto &attr : always->attributes) {
|
||||
if (attr.second->type != AST_CONSTANT)
|
||||
@@ -797,10 +798,9 @@ struct AST_INTERNAL::ProcessGenerator
|
||||
case AST_TCALL:
|
||||
if (ast->str == "$display" || ast->str == "$displayb" || ast->str == "$displayh" || ast->str == "$displayo" ||
|
||||
ast->str == "$write" || ast->str == "$writeb" || ast->str == "$writeh" || ast->str == "$writeo") {
|
||||
std::stringstream sstr;
|
||||
sstr << ast->str << "$" << ast->location.begin.filename << ":" << ast->location.begin.line << "$" << (autoidx++);
|
||||
IdString name = intern_src_name(current_module->design, ast->location, ast->str, autoidx++);
|
||||
|
||||
Wire *en = current_module->addWire(sstr.str() + "_EN", 1);
|
||||
Wire *en = current_module->addWire(TwineSpec::Suffix{name, "_EN"}, 1);
|
||||
set_src_attr(en, ast);
|
||||
proc->root_case.actions.push_back({en, SigSpec(false)});
|
||||
current_case->actions.push_back({en, SigSpec(true)});
|
||||
@@ -818,7 +818,7 @@ struct AST_INTERNAL::ProcessGenerator
|
||||
}
|
||||
RTLIL::Const polarity = polarity_builder.build();
|
||||
|
||||
RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($print));
|
||||
RTLIL::Cell *cell = current_module->addCell(name, ID($print));
|
||||
set_src_attr(cell, ast);
|
||||
cell->setParam(ID::TRG_WIDTH, triggers.size());
|
||||
cell->setParam(ID::TRG_ENABLE, (always->type == AST_INITIAL) || !triggers.empty());
|
||||
@@ -886,18 +886,19 @@ struct AST_INTERNAL::ProcessGenerator
|
||||
if (ast->type == AST_FAIR) { flavor = "fair"; desc = "assume (eventually)"; }
|
||||
if (ast->type == AST_COVER) { flavor = "cover"; desc = "cover ()"; }
|
||||
|
||||
std::string cellname;
|
||||
IdString cellname;
|
||||
if (ast->str.empty())
|
||||
cellname = stringf("$%s$%s:%d$%d", flavor, RTLIL::encode_filename(*ast->location.begin.filename), ast->location.begin.line, autoidx++);
|
||||
cellname = intern_src_name(current_module->design, ast->location,
|
||||
stringf("$%s", flavor), autoidx++);
|
||||
else
|
||||
cellname = ast->str;
|
||||
check_unique_id(current_module, cellname, ast, "procedural assertion");
|
||||
cellname = current_module->design->twines.add(std::string{ast->str});
|
||||
check_unique_id(current_module, current_module->design->twines.str(cellname), ast, "procedural assertion");
|
||||
|
||||
RTLIL::SigSpec check = ast->children[0]->genWidthRTLIL(-1, false, &subst_rvalue_map.stdmap());
|
||||
if (GetSize(check) != 1)
|
||||
check = current_module->ReduceBool(NEW_ID, check);
|
||||
|
||||
Wire *en = current_module->addWire(cellname + "_EN", 1);
|
||||
Wire *en = current_module->addWire(TwineSpec::Suffix{cellname, "_EN"}, 1);
|
||||
set_src_attr(en, ast);
|
||||
proc->root_case.actions.push_back({en, SigSpec(false)});
|
||||
current_case->actions.push_back({en, SigSpec(true)});
|
||||
@@ -1957,10 +1958,11 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
||||
// generate $memrd cells for memory read ports
|
||||
case AST_MEMRD:
|
||||
{
|
||||
std::stringstream sstr;
|
||||
sstr << "$memrd$" << str << "$" << RTLIL::encode_filename(*location.begin.filename) << ":" << location.begin.line << "$" << (autoidx++);
|
||||
IdString name = current_module->design->twines.add(TwineSpec::Suffix{
|
||||
intern_src_name(current_module->design, location, "$memrd", autoidx++),
|
||||
stringf("$%s", str)});
|
||||
|
||||
RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($memrd));
|
||||
RTLIL::Cell *cell = current_module->addCell(name, ID($memrd));
|
||||
set_src_attr(cell, this);
|
||||
|
||||
IdString mem_tw = current_module->design->twines.find(str);
|
||||
@@ -1996,12 +1998,13 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
||||
// generate $meminit cells
|
||||
case AST_MEMINIT:
|
||||
{
|
||||
std::stringstream sstr;
|
||||
sstr << "$meminit$" << str << "$" << RTLIL::encode_filename(*location.begin.filename) << ":" << location.begin.line << "$" << (autoidx++);
|
||||
IdString name = current_module->design->twines.add(TwineSpec::Suffix{
|
||||
intern_src_name(current_module->design, location, "$meminit", autoidx++),
|
||||
stringf("$%s", str)});
|
||||
|
||||
SigSpec en_sig = children[2]->genRTLIL();
|
||||
|
||||
RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($meminit_v2));
|
||||
RTLIL::Cell *cell = current_module->addCell(name, ID($meminit_v2));
|
||||
set_src_attr(cell, this);
|
||||
|
||||
int mem_width, mem_size, addr_bits;
|
||||
@@ -2041,12 +2044,13 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
||||
if (type == AST_FAIR) { flavor = "fair"; desc = "assume property (eventually)"; }
|
||||
if (type == AST_COVER) { flavor = "cover"; desc = "cover property ()"; }
|
||||
|
||||
std::string cellname;
|
||||
IdString cellname;
|
||||
if (str.empty())
|
||||
cellname = stringf("$%s$%s:%d$%d", flavor, RTLIL::encode_filename(*location.begin.filename), location.begin.line, autoidx++);
|
||||
cellname = intern_src_name(current_module->design, location,
|
||||
stringf("$%s", flavor), autoidx++);
|
||||
else
|
||||
cellname = str;
|
||||
check_unique_id(current_module, cellname, this, "procedural assertion");
|
||||
cellname = current_module->design->twines.add(std::string{str});
|
||||
check_unique_id(current_module, current_module->design->twines.str(cellname), this, "procedural assertion");
|
||||
|
||||
RTLIL::SigSpec check = children[0]->genRTLIL();
|
||||
if (GetSize(check) != 1)
|
||||
|
||||
@@ -530,9 +530,9 @@ struct RTLILFrontendWorker {
|
||||
const TwineDesc &desc = twine_descs.at(id);
|
||||
IdString found;
|
||||
if (desc.kind == TwineDesc::Leaf)
|
||||
found = design->twines.find(Twine{Twine::Leaf{desc.text}});
|
||||
found = design->twines.find(TwineSpec{TwineSpec::Leaf{desc.text}});
|
||||
else
|
||||
found = design->twines.find(Twine{Twine::Suffix{
|
||||
found = design->twines.find(TwineSpec{TwineSpec::Suffix{
|
||||
IdString(desc.parent), desc.text}});
|
||||
if (found == IdString::Null || found.untag().raw() != id)
|
||||
return false;
|
||||
@@ -563,10 +563,10 @@ struct RTLILFrontendWorker {
|
||||
IdString ref;
|
||||
switch (desc.kind) {
|
||||
case TwineDesc::Leaf:
|
||||
ref = design->twines.add(Twine::Leaf{desc.text});
|
||||
ref = design->twines.add(TwineSpec::Leaf{desc.text});
|
||||
break;
|
||||
case TwineDesc::Suffix:
|
||||
ref = design->twines.add(Twine::Suffix{
|
||||
ref = design->twines.add(TwineSpec::Suffix{
|
||||
materialize_file_twine(desc.parent),
|
||||
desc.text});
|
||||
break;
|
||||
|
||||
+1
-1
@@ -182,7 +182,7 @@ struct FfData : FfTypeData {
|
||||
pol_set = false;
|
||||
}
|
||||
|
||||
FfData(Module *module, FfInitVals *initvals, Twine &&name)
|
||||
FfData(Module *module, FfInitVals *initvals, TwineSpec &&name)
|
||||
: FfData(module, initvals, module->design->twines.add(std::move(name))) {}
|
||||
|
||||
FfData(FfInitVals *initvals, Cell *cell_);
|
||||
|
||||
+14
-5
@@ -8,8 +8,8 @@
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* Implements TwinePool shallow deduplicating backing storage
|
||||
/**
|
||||
* Implements shallow deduplicating backing storage
|
||||
*/
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
@@ -21,6 +21,7 @@ struct HashConsNodeHash {
|
||||
const Derived* pool = nullptr;
|
||||
|
||||
size_t operator()(const Node& n) const noexcept { return Derived::hash_node(n); }
|
||||
size_t operator()(const typename Node::Key& k) const noexcept { return Derived::hash_key(k); }
|
||||
size_t operator()(Ref ref) const noexcept { return Derived::hash_node((*pool)[ref]); }
|
||||
};
|
||||
|
||||
@@ -44,9 +45,11 @@ struct HashConsPool {
|
||||
struct NodeEq {
|
||||
using is_transparent = void;
|
||||
const Derived* pool = nullptr;
|
||||
bool operator()(Ref a, Ref b) const noexcept { return (*pool)[a].data == (*pool)[b].data; }
|
||||
bool operator()(Ref a, const Node& b) const noexcept { return (*pool)[a].data == b.data; }
|
||||
bool operator()(const Node& a, Ref b) const noexcept { return a.data == (*pool)[b].data; }
|
||||
bool operator()(Ref a, Ref b) const noexcept { return (*pool)[a] == (*pool)[b]; }
|
||||
bool operator()(Ref a, const Node& b) const noexcept { return (*pool)[a] == b; }
|
||||
bool operator()(const Node& a, Ref b) const noexcept { return a == (*pool)[b]; }
|
||||
bool operator()(Ref a, const typename Node::Key& b) const noexcept { return (*pool)[a] == b; }
|
||||
bool operator()(const typename Node::Key& a, Ref b) const noexcept { return (*pool)[b] == a; }
|
||||
};
|
||||
|
||||
using Index = std::unordered_set<Ref, NodeHash, NodeEq>;
|
||||
@@ -184,6 +187,12 @@ public:
|
||||
return Ref();
|
||||
}
|
||||
|
||||
Ref find_key(const typename Node::Key& k) const {
|
||||
if (auto it = index.find(k); it != index.end())
|
||||
return *it;
|
||||
return Ref();
|
||||
}
|
||||
|
||||
Ref add_inner(Node t) {
|
||||
Derived::canonicalize(t);
|
||||
|
||||
|
||||
+1
-1
@@ -174,7 +174,7 @@ struct hash_ops {
|
||||
return hash_ops<u_type>::hash_into((u_type) a, h);
|
||||
} else if constexpr (std::is_pointer_v<T>) {
|
||||
return hash_ops<uintptr_t>::hash_into((uintptr_t) a, h);
|
||||
} else if constexpr (std::is_same_v<T, std::string>) {
|
||||
} else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, std::string_view>) {
|
||||
int size = a.size();
|
||||
int i = 0;
|
||||
while (i + 8 < size) {
|
||||
|
||||
+1
-1
@@ -223,7 +223,7 @@ struct Mem : RTLIL::AttrObject {
|
||||
void emulate_read_first(FfInitVals *initvals);
|
||||
|
||||
Mem(Module *module, IdString memid, int width, int start_offset, int size) : module(module), memid(module->design, memid), packed(false), mem(nullptr), cell(nullptr), width(width), start_offset(start_offset), size(size) {}
|
||||
Mem(Module *module, Twine &&memid, int width, int start_offset, int size)
|
||||
Mem(Module *module, TwineSpec &&memid, int width, int start_offset, int size)
|
||||
: Mem(module, module->design->twines.add(std::move(memid)), width, start_offset, size) {}
|
||||
};
|
||||
|
||||
|
||||
+1
-1
@@ -2955,7 +2955,7 @@ IdString RTLIL::Module::uniquify(IdString name, int &index)
|
||||
}
|
||||
|
||||
while (1) {
|
||||
IdString new_name = (design->twines.add(Twine::Suffix{name, stringf("_%d", index)})).tag(name.isPublic());
|
||||
IdString new_name = (design->twines.add(TwineSpec::Suffix{name, stringf("_%d", index)})).tag(name.isPublic());
|
||||
if (count_id(new_name) == 0)
|
||||
return new_name;
|
||||
index++;
|
||||
|
||||
+13
-9
@@ -1270,18 +1270,22 @@ struct define_map_t;
|
||||
|
||||
template<typename N>
|
||||
inline constexpr bool is_unpooled_name_v =
|
||||
std::is_same_v<std::decay_t<N>, Twine> || std::is_same_v<std::decay_t<N>, Twine::Leaf> ||
|
||||
std::is_same_v<std::decay_t<N>, Twine::Suffix> || std::is_same_v<std::decay_t<N>, Twine::AutoSuffix> ||
|
||||
std::is_same_v<std::decay_t<N>, TwineSpec> || std::is_same_v<std::decay_t<N>, TwineSpec::Leaf> ||
|
||||
std::is_same_v<std::decay_t<N>, TwineSpec::Suffix> || std::is_same_v<std::decay_t<N>, TwineSpec::AutoSuffix> ||
|
||||
std::is_same_v<std::decay_t<N>, std::string> ||
|
||||
std::is_same_v<std::decay_t<N>, const char*> || std::is_same_v<std::decay_t<N>, char*>;
|
||||
|
||||
#define YS_UNPOOLED_NAME(N) std::enable_if_t<is_unpooled_name_v<N>, int> = 0
|
||||
|
||||
// Forwarders from various string-representing types into a canonical IdString method
|
||||
|
||||
// Forwards _func(name, arg1...)
|
||||
#define YS_NAME_FWD_POOL(_func, _pool) \
|
||||
template<typename N, typename... Rest, YS_UNPOOLED_NAME(N)> \
|
||||
decltype(auto) _func(N name, Rest&&... rest) \
|
||||
{ return _func(_pool.add(std::move(name)), std::forward<Rest>(rest)...); }
|
||||
|
||||
// Forwards _func(arg0, name, arg2...)
|
||||
#define YS_NAME_FWD_2ND_POOL(_func, _pool) \
|
||||
template<typename T, typename N, YS_UNPOOLED_NAME(N)> \
|
||||
decltype(auto) _func(T &&first, N name) \
|
||||
@@ -1475,7 +1479,7 @@ struct RTLIL::Module : public RTLIL::NamedObject
|
||||
friend struct RTLIL::Cell;
|
||||
friend struct RTLIL::Design;
|
||||
|
||||
[[no_unique_address]] RTLIL::ModuleNameMasq name;
|
||||
YS_NO_UNIQUE_ADDRESS RTLIL::ModuleNameMasq name;
|
||||
|
||||
Hasher::hash_t hashidx_;
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }
|
||||
@@ -1897,7 +1901,7 @@ public:
|
||||
|
||||
struct RTLIL::Wire : public RTLIL::NamedObject
|
||||
{
|
||||
[[no_unique_address]] RTLIL::WireNameMasq name;
|
||||
YS_NO_UNIQUE_ADDRESS RTLIL::WireNameMasq name;
|
||||
|
||||
Hasher::hash_t hashidx_;
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }
|
||||
@@ -1965,7 +1969,7 @@ struct RTLIL::Memory : public RTLIL::NamedObject
|
||||
|
||||
RTLIL::Design *design() const { return module ? module->design : nullptr; }
|
||||
|
||||
[[no_unique_address]] RTLIL::MemoryNameMasq name;
|
||||
YS_NO_UNIQUE_ADDRESS RTLIL::MemoryNameMasq name;
|
||||
|
||||
int width, start_offset, size;
|
||||
#ifdef YOSYS_ENABLE_PYTHON
|
||||
@@ -1989,7 +1993,7 @@ private:
|
||||
|
||||
bool bufnorm_handle_setPort(IdString portname, RTLIL::SigSpec &signal, dict<IdString, RTLIL::SigSpec>::iterator conn_it);
|
||||
public:
|
||||
[[no_unique_address]] RTLIL::CellNameMasq name;
|
||||
YS_NO_UNIQUE_ADDRESS RTLIL::CellNameMasq name;
|
||||
|
||||
Hasher::hash_t hashidx_;
|
||||
[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }
|
||||
@@ -2010,7 +2014,7 @@ public:
|
||||
RTLIL::Design *design() const { return module ? module->design : nullptr; }
|
||||
|
||||
IdString type_impl;
|
||||
[[no_unique_address]] RTLIL::CellTypeMasq type;
|
||||
YS_NO_UNIQUE_ADDRESS RTLIL::CellTypeMasq type;
|
||||
dict<RTLIL::IdString, RTLIL::SigSpec> connections_;
|
||||
dict<RTLIL::IdString, RTLIL::Const> parameters;
|
||||
|
||||
@@ -2130,7 +2134,7 @@ public:
|
||||
|
||||
RTLIL::Design *design() const { return module ? module->design : nullptr; }
|
||||
|
||||
[[no_unique_address]] RTLIL::ProcessNameMasq name;
|
||||
YS_NO_UNIQUE_ADDRESS RTLIL::ProcessNameMasq name;
|
||||
|
||||
template<typename T> void rewrite_sigspecs(T &functor);
|
||||
template<typename T> void rewrite_sigspecs2(T &functor);
|
||||
@@ -2178,7 +2182,7 @@ inline Hasher RTLIL::SigBit::hash_top() const {
|
||||
Hasher h;
|
||||
if (wire) {
|
||||
IdString name = wire->name.ref();
|
||||
uint32_t n = (uint32_t)name.raw() ^ (uint32_t)(name.raw() >> 32);
|
||||
uint32_t n = (uint32_t)name.bits();
|
||||
h.force(hashlib::legacy::djb2_add(n, offset));
|
||||
return h;
|
||||
}
|
||||
|
||||
@@ -161,4 +161,23 @@ private:
|
||||
|
||||
}
|
||||
|
||||
namespace hashlib {
|
||||
template<typename T>
|
||||
struct masq_hash_ops {
|
||||
static inline bool cmp(const T &a, const T &b) { return a == b; }
|
||||
[[nodiscard]] static inline Hasher hash(const T &a) {
|
||||
return hash_ops<IdString>::hash(a.ref());
|
||||
}
|
||||
[[nodiscard]] static inline Hasher hash_into(const T &a, Hasher h) {
|
||||
return hash_ops<IdString>::hash_into(a.ref(), h);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Owner>
|
||||
struct hash_ops<RTLIL::ObjNameMasq<Owner>> : masq_hash_ops<RTLIL::ObjNameMasq<Owner>> {};
|
||||
template<> struct hash_ops<RTLIL::CellTypeMasq> : masq_hash_ops<RTLIL::CellTypeMasq> {};
|
||||
template<> struct hash_ops<RTLIL::ModuleNameMasq> : masq_hash_ops<RTLIL::ModuleNameMasq> {};
|
||||
template<> struct hash_ops<RTLIL::PooledName> : masq_hash_ops<RTLIL::PooledName> {};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+255
-137
@@ -10,9 +10,8 @@ void StaticTwines::init() {
|
||||
return;
|
||||
log_assert(nodes_.empty());
|
||||
nodes_.reserve(count);
|
||||
#define X(_id) nodes_.push_back(Twine::Leaf{#_id});
|
||||
#include "kernel/constids.inc"
|
||||
#undef X
|
||||
for (const char *name : ID::static_names)
|
||||
nodes_.emplace_back(std::string_view(name));
|
||||
}
|
||||
|
||||
const TwineNode &StaticTwines::node(size_t idx) { return nodes_[idx]; }
|
||||
@@ -21,7 +20,7 @@ bool StaticTwines::ready() { return nodes_.size() == count; }
|
||||
int64_t twine_gc_ns;
|
||||
int twine_gc_count;
|
||||
|
||||
Hasher IdString::hash_into(Hasher h) const { h.hash64(raw()); return h; }
|
||||
Hasher IdString::hash_into(Hasher h) const { h.hash64(eq_key()); return h; }
|
||||
|
||||
std::string IdString::handle_token() const {
|
||||
return stringf("%s@%zu", isPublic() ? "$pub" : "$priv", untag().raw());
|
||||
@@ -53,27 +52,85 @@ std::string ID::unescaped_str(IdString ref) {
|
||||
return static_names[idx.raw()];
|
||||
}
|
||||
|
||||
Twine::Twine(Leaf v) : data(std::move(v)) {}
|
||||
Twine::Twine(Suffix v) : data(std::move(v)) {}
|
||||
Twine::Twine(AutoSuffix v) : data(std::move(v)) {}
|
||||
TwineSpec::TwineSpec(Leaf v) : data(std::move(v)) {}
|
||||
TwineSpec::TwineSpec(Suffix v) : data(std::move(v)) {}
|
||||
TwineSpec::TwineSpec(AutoSuffix v) : data(std::move(v)) {}
|
||||
|
||||
bool Twine::is_leaf() const { return std::holds_alternative<Leaf>(data); }
|
||||
bool Twine::is_suffix() const { return std::holds_alternative<Suffix>(data); }
|
||||
bool TwineSpec::holds_leaf() const { return std::holds_alternative<Leaf>(data); }
|
||||
bool TwineSpec::holds_suffix() const { return std::holds_alternative<Suffix>(data); }
|
||||
|
||||
TwineNode::TwineNode(Twine::Leaf v) : data(std::move(v)) {}
|
||||
TwineNode::TwineNode(Twine::Suffix v) : data(std::move(v)) {}
|
||||
void SmallString::store(std::string_view content)
|
||||
{
|
||||
log_assert(content.size() <= MAX_LEN);
|
||||
release();
|
||||
len_ = content.size();
|
||||
if (len_ > INLINE_CAP) {
|
||||
ptr_ = new char[len_];
|
||||
memcpy(ptr_, content.data(), len_);
|
||||
} else {
|
||||
memcpy(inl_, content.data(), len_);
|
||||
}
|
||||
}
|
||||
|
||||
bool TwineNode::is_dead() const { return std::holds_alternative<std::monostate>(data); }
|
||||
bool TwineNode::is_leaf() const { return std::holds_alternative<Twine::Leaf>(data); }
|
||||
bool TwineNode::is_suffix() const { return std::holds_alternative<Twine::Suffix>(data); }
|
||||
const std::string &TwineNode::leaf() const { return std::get<Twine::Leaf>(data).s; }
|
||||
const Twine::Suffix &TwineNode::suffix() const { return std::get<Twine::Suffix>(data); }
|
||||
void SmallString::release()
|
||||
{
|
||||
if (len_ > INLINE_CAP)
|
||||
delete[] ptr_;
|
||||
len_ = 0;
|
||||
}
|
||||
|
||||
std::string Twine::content_str() const {
|
||||
SmallString::SmallString(std::string_view content) { store(content); }
|
||||
|
||||
SmallString::SmallString(const SmallString &other) { store(other.view()); }
|
||||
|
||||
SmallString::SmallString(SmallString &&other) noexcept : len_(other.len_)
|
||||
{
|
||||
memcpy(inl_, other.inl_, INLINE_CAP);
|
||||
other.len_ = 0;
|
||||
}
|
||||
|
||||
SmallString &SmallString::operator=(const SmallString &other)
|
||||
{
|
||||
if (this != &other)
|
||||
store(other.view());
|
||||
return *this;
|
||||
}
|
||||
|
||||
SmallString &SmallString::operator=(SmallString &&other) noexcept
|
||||
{
|
||||
if (this == &other)
|
||||
return *this;
|
||||
release();
|
||||
memcpy(inl_, other.inl_, INLINE_CAP);
|
||||
len_ = other.len_;
|
||||
other.len_ = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SmallString::~SmallString() { release(); }
|
||||
|
||||
TwineNode::TwineNode(TwineNode &&other) noexcept
|
||||
: text_(std::move(other.text_)), prefix_(other.prefix_)
|
||||
{
|
||||
other.prefix_ = DEAD;
|
||||
}
|
||||
|
||||
TwineNode &TwineNode::operator=(TwineNode &&other) noexcept
|
||||
{
|
||||
if (this == &other)
|
||||
return *this;
|
||||
text_ = std::move(other.text_);
|
||||
prefix_ = other.prefix_;
|
||||
other.prefix_ = DEAD;
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string TwineSpec::content_str() const {
|
||||
if (auto *leaf = std::get_if<Leaf>(&data))
|
||||
return leaf->s;
|
||||
log_assert(!holds_suffix());
|
||||
auto &autosfx = std::get<AutoSuffix>(data);
|
||||
return std::string(autosfx.prefix) + autosfx.tail;
|
||||
return *autosfx.prefix + autosfx.tail;
|
||||
}
|
||||
|
||||
std::pair<std::string, bool> twine_unescape(std::string s) {
|
||||
@@ -84,16 +141,26 @@ std::pair<std::string, bool> twine_unescape(std::string s) {
|
||||
}
|
||||
|
||||
TwinePool::TwinePool() : serial_(next_serial()) {}
|
||||
TwinePool::TwinePool(const TwinePool& other) : HashConsPool(other), serial_(next_serial()) {}
|
||||
TwinePool::TwinePool(TwinePool&& other) : HashConsPool(std::move(other)), serial_(next_serial()) {}
|
||||
TwinePool::TwinePool(const TwinePool& other)
|
||||
: HashConsPool(other), auto_prefixes(other.auto_prefixes), serial_(next_serial()) {}
|
||||
TwinePool::TwinePool(TwinePool&& other)
|
||||
: HashConsPool(std::move(other)), auto_prefixes(std::move(other.auto_prefixes)), serial_(next_serial()) {}
|
||||
|
||||
TwinePool& TwinePool::operator=(const TwinePool& other) {
|
||||
if (this == &other)
|
||||
return *this;
|
||||
HashConsPool::operator=(other);
|
||||
auto_prefixes = other.auto_prefixes;
|
||||
serial_ = next_serial();
|
||||
return *this;
|
||||
}
|
||||
|
||||
TwinePool& TwinePool::operator=(TwinePool&& other) {
|
||||
if (this == &other)
|
||||
return *this;
|
||||
HashConsPool::operator=(std::move(other));
|
||||
auto_prefixes = std::move(other.auto_prefixes);
|
||||
serial_ = next_serial();
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -110,9 +177,8 @@ IdString TwinePool::stamp(IdString ref) const {
|
||||
}
|
||||
|
||||
void TwinePool::check_owned(IdString ref) const {
|
||||
#ifndef NDEBUG
|
||||
log_assert(owns(ref));
|
||||
#endif
|
||||
if constexpr (IdString::MAX_SERIAL != 0)
|
||||
log_assert(owns(ref));
|
||||
}
|
||||
|
||||
const TwineNode& TwinePool::operator[](IdString ref) const {
|
||||
@@ -123,15 +189,15 @@ const TwineNode& TwinePool::operator[](IdString ref) const {
|
||||
const TwineNode& TwinePool::static_node(size_t idx) { return StaticTwines::node(idx); }
|
||||
void TwinePool::check_ready() { log_assert(StaticTwines::ready()); }
|
||||
|
||||
void TwinePool::canonicalize(TwineNode& t) {
|
||||
if (auto *sfx = std::get_if<Twine::Suffix>(&t.data))
|
||||
sfx->prefix = sfx->prefix.untag().stamped(0);
|
||||
}
|
||||
void TwinePool::canonicalize(TwineNode&) {}
|
||||
|
||||
size_t TwinePool::next_serial() {
|
||||
static size_t counter = 0;
|
||||
size_t serial = ++counter;
|
||||
return serial > IdString::MAX_SERIAL ? (serial % IdString::MAX_SERIAL) + 1 : serial;
|
||||
if constexpr (IdString::MAX_SERIAL == 0)
|
||||
return serial;
|
||||
else
|
||||
return serial > IdString::MAX_SERIAL ? (serial % IdString::MAX_SERIAL) + 1 : serial;
|
||||
}
|
||||
|
||||
IdString TwinePool::add_inner(TwineNode t) {
|
||||
@@ -142,35 +208,32 @@ IdString TwinePool::add_inner(TwineNode t) {
|
||||
}
|
||||
|
||||
size_t TwinePool::hash_node(const TwineNode& t) {
|
||||
return hash_key(t.key());
|
||||
}
|
||||
|
||||
size_t TwinePool::hash_key(const TwineNode::Key& k) {
|
||||
Hasher h;
|
||||
|
||||
std::visit([&h](const auto& val) {
|
||||
using T = std::decay_t<decltype(val)>;
|
||||
if constexpr (std::is_same_v<T, Twine::Leaf>) {
|
||||
h.eat(val.s);
|
||||
} else if constexpr (std::is_same_v<T, Twine::Suffix>) {
|
||||
h.eat(val.prefix);
|
||||
h.eat(val.tail);
|
||||
}
|
||||
}, t.data);
|
||||
|
||||
if (k.prefix < TwineNode::DEAD)
|
||||
h.eat(IdString(k.prefix));
|
||||
h.eat(k.text);
|
||||
return h.yield();
|
||||
}
|
||||
|
||||
void TwinePool::dump(IdString ref, std::ostream& os) const {
|
||||
const TwineNode& twine = (*this)[ref];
|
||||
std::visit([&](const auto& val) {
|
||||
using T = std::decay_t<decltype(val)>;
|
||||
if constexpr (std::is_same_v<T, std::monostate>) {
|
||||
os << "Dead()";
|
||||
} else if constexpr (std::is_same_v<T, Twine::Leaf>) {
|
||||
os << "Leaf(\"" << val.s << "\")";
|
||||
} else if constexpr (std::is_same_v<T, Twine::Suffix>) {
|
||||
os << "Suffix(prefix: ";
|
||||
dump(val.prefix, os);
|
||||
os << ", tail: \"" << val.tail << "\")";
|
||||
}
|
||||
}, twine.data);
|
||||
switch (twine.kind()) {
|
||||
case TwineNode::Kind::Dead:
|
||||
os << "Dead()";
|
||||
break;
|
||||
case TwineNode::Kind::Leaf:
|
||||
os << "Leaf(\"" << twine.text() << "\")";
|
||||
break;
|
||||
case TwineNode::Kind::Suffix:
|
||||
os << "Suffix(prefix: ";
|
||||
dump(twine.prefix(), os);
|
||||
os << ", tail: \"" << twine.text() << "\")";
|
||||
break;
|
||||
}
|
||||
if (ref.isPublic())
|
||||
os << " pub";
|
||||
}
|
||||
@@ -180,16 +243,17 @@ void TwinePool::print(IdString ref, std::ostream& os) const {
|
||||
return;
|
||||
if (ref.isPublic())
|
||||
os << '\\';
|
||||
std::visit([&](const auto& val) {
|
||||
using T = std::decay_t<decltype(val)>;
|
||||
if constexpr (std::is_same_v<T, std::monostate>) {
|
||||
} else if constexpr (std::is_same_v<T, Twine::Leaf>) {
|
||||
os << val.s;
|
||||
} else if constexpr (std::is_same_v<T, Twine::Suffix>) {
|
||||
print(val.prefix, os);
|
||||
os << val.tail;
|
||||
}
|
||||
}, (*this)[ref].data);
|
||||
const TwineNode& twine = (*this)[ref];
|
||||
switch (twine.kind()) {
|
||||
case TwineNode::Kind::Dead:
|
||||
break;
|
||||
case TwineNode::Kind::Suffix:
|
||||
print(twine.prefix(), os);
|
||||
[[fallthrough]];
|
||||
case TwineNode::Kind::Leaf:
|
||||
os << twine.text();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void TwinePool::append_str(IdString ref, std::string& out) const {
|
||||
@@ -197,16 +261,17 @@ void TwinePool::append_str(IdString ref, std::string& out) const {
|
||||
return;
|
||||
if (ref.isPublic())
|
||||
out += '\\';
|
||||
std::visit([&](const auto& val) {
|
||||
using T = std::decay_t<decltype(val)>;
|
||||
if constexpr (std::is_same_v<T, std::monostate>) {
|
||||
} else if constexpr (std::is_same_v<T, Twine::Leaf>) {
|
||||
out += val.s;
|
||||
} else if constexpr (std::is_same_v<T, Twine::Suffix>) {
|
||||
append_str(val.prefix, out);
|
||||
out += val.tail;
|
||||
}
|
||||
}, (*this)[ref].data);
|
||||
const TwineNode& twine = (*this)[ref];
|
||||
switch (twine.kind()) {
|
||||
case TwineNode::Kind::Dead:
|
||||
break;
|
||||
case TwineNode::Kind::Suffix:
|
||||
append_str(twine.prefix(), out);
|
||||
[[fallthrough]];
|
||||
case TwineNode::Kind::Leaf:
|
||||
out += twine.text();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::string TwinePool::str(IdString ref) const {
|
||||
@@ -219,36 +284,67 @@ std::string TwinePool::unescaped_str(IdString ref) const {
|
||||
return str(ref.untag());
|
||||
}
|
||||
|
||||
IdString TwinePool::find_content(uint32_t prefix, std::string_view text) const {
|
||||
return HashConsPool::find_key(TwineNode::Key{prefix, text});
|
||||
}
|
||||
|
||||
IdString TwinePool::intern(uint32_t prefix, std::string_view text) {
|
||||
IdString ref = HashConsPool::find_key(TwineNode::Key{prefix, text});
|
||||
if (ref != IdString::Null)
|
||||
return ref;
|
||||
return add_inner(TwineNode{prefix, text});
|
||||
}
|
||||
|
||||
IdString TwinePool::find(const std::string &name) const {
|
||||
bool is_public = !name.empty() && name[0] == '\\';
|
||||
return stamp(find(Twine::Leaf{is_public ? name.substr(1) : name}).tag(is_public));
|
||||
std::string_view content = name;
|
||||
if (is_public)
|
||||
content.remove_prefix(1);
|
||||
return stamp(find_content(TwineNode::NO_PREFIX, content).tag(is_public));
|
||||
}
|
||||
|
||||
IdString TwinePool::find(Twine t) const {
|
||||
if (auto *ap = std::get_if<Twine::AutoSuffix>(&t.data)) {
|
||||
IdString prefix = HashConsPool::find(Twine::Leaf{std::string(ap->prefix)});
|
||||
IdString TwinePool::find(TwineSpec t) const {
|
||||
if (auto *ap = std::get_if<TwineSpec::AutoSuffix>(&t.data)) {
|
||||
IdString prefix = find_content(TwineNode::NO_PREFIX, *ap->prefix);
|
||||
if (prefix == IdString::Null)
|
||||
return IdString::Null;
|
||||
t = Twine::Suffix{prefix, std::move(ap->tail)};
|
||||
return stamp(find_content((uint32_t)prefix.untag().raw(), ap->tail).tag(prefix.isPublic()));
|
||||
}
|
||||
bool is_public = inherits_publicity(t);
|
||||
return stamp(HashConsPool::find(to_node(std::move(t))).tag(is_public));
|
||||
if (auto *leaf = std::get_if<TwineSpec::Leaf>(&t.data))
|
||||
return stamp(find_content(TwineNode::NO_PREFIX, leaf->s));
|
||||
const TwineSpec::Suffix &sfx = std::get<TwineSpec::Suffix>(t.data);
|
||||
return stamp(find_content((uint32_t)sfx.prefix.untag().raw(), sfx.tail).tag(sfx.prefix.isPublic()));
|
||||
}
|
||||
|
||||
IdString TwinePool::add(Twine t) {
|
||||
if (auto *ap = std::get_if<Twine::AutoSuffix>(&t.data)) {
|
||||
IdString prefix = add_inner(Twine::Leaf{std::string(ap->prefix)});
|
||||
t = Twine::Suffix{prefix, std::move(ap->tail)};
|
||||
IdString TwinePool::add(TwineSpec t) {
|
||||
if (auto *ap = std::get_if<TwineSpec::AutoSuffix>(&t.data)) {
|
||||
IdString prefix = auto_prefix(ap->prefix);
|
||||
return stamp(intern((uint32_t)prefix.untag().raw(), ap->tail).tag(prefix.isPublic()));
|
||||
}
|
||||
bool is_public = inherits_publicity(t);
|
||||
return stamp(add_inner(to_node(std::move(t))).tag(is_public));
|
||||
if (auto *leaf = std::get_if<TwineSpec::Leaf>(&t.data))
|
||||
return stamp(intern(TwineNode::NO_PREFIX, leaf->s));
|
||||
const TwineSpec::Suffix &sfx = std::get<TwineSpec::Suffix>(t.data);
|
||||
return stamp(intern((uint32_t)sfx.prefix.untag().raw(), sfx.tail).tag(sfx.prefix.isPublic()));
|
||||
}
|
||||
|
||||
IdString TwinePool::auto_prefix(const std::string *prefix) {
|
||||
auto it = auto_prefixes.find(prefix);
|
||||
if (it != auto_prefixes.end())
|
||||
return it->second;
|
||||
IdString ref = intern(TwineNode::NO_PREFIX, *prefix);
|
||||
auto_prefixes[prefix] = ref;
|
||||
return ref;
|
||||
}
|
||||
|
||||
IdString TwinePool::add(IdString prefix, std::string_view tail) {
|
||||
return stamp(intern((uint32_t)prefix.untag().raw(), tail).tag(prefix.isPublic()));
|
||||
}
|
||||
|
||||
IdString TwinePool::add(std::string s) {
|
||||
if (s.empty())
|
||||
return IdString::Null;
|
||||
auto [content, is_public] = twine_unescape(std::move(s));
|
||||
return stamp(add_inner(Twine::Leaf{std::move(content)}).tag(is_public));
|
||||
return stamp(intern(TwineNode::NO_PREFIX, content).tag(is_public));
|
||||
}
|
||||
|
||||
IdString TwinePool::copy_from(const TwinePool& src, IdString ref) {
|
||||
@@ -260,10 +356,16 @@ IdString TwinePool::copy_from(const TwinePool& src, IdString ref) {
|
||||
if (ID::is_static(untagged))
|
||||
return ref;
|
||||
const TwineNode& t = src[untagged];
|
||||
if (t.is_leaf())
|
||||
return (add(Twine::Leaf{t.leaf()})).tag(is_public);
|
||||
if (t.is_suffix())
|
||||
return (add(Twine::Suffix{copy_from(src, t.suffix().prefix), t.suffix().tail})).tag(is_public);
|
||||
switch (t.kind()) {
|
||||
case TwineNode::Kind::Leaf:
|
||||
return stamp(intern(TwineNode::NO_PREFIX, t.text()).tag(is_public));
|
||||
case TwineNode::Kind::Suffix: {
|
||||
IdString prefix = copy_from(src, t.prefix());
|
||||
return stamp(intern((uint32_t)prefix.untag().raw(), t.text()).tag(is_public));
|
||||
}
|
||||
case TwineNode::Kind::Dead:
|
||||
break;
|
||||
}
|
||||
return IdString::Null;
|
||||
}
|
||||
|
||||
@@ -276,32 +378,47 @@ IdString TwinePool::find_from(const TwinePool& src, IdString ref) const {
|
||||
if (ID::is_static(untagged))
|
||||
return ref;
|
||||
const TwineNode& t = src[untagged];
|
||||
if (t.is_leaf())
|
||||
return find(Twine::Leaf{t.leaf()}).tag(is_public);
|
||||
if (t.is_suffix()) {
|
||||
IdString prefix = find_from(src, t.suffix().prefix);
|
||||
switch (t.kind()) {
|
||||
case TwineNode::Kind::Leaf:
|
||||
return stamp(find_content(TwineNode::NO_PREFIX, t.text()).tag(is_public));
|
||||
case TwineNode::Kind::Suffix: {
|
||||
IdString prefix = find_from(src, t.prefix());
|
||||
if (prefix == IdString::Null)
|
||||
return IdString::Null;
|
||||
return find(Twine::Suffix{prefix, t.suffix().tail}).tag(is_public);
|
||||
return stamp(find_content((uint32_t)prefix.untag().raw(), t.text()).tag(is_public));
|
||||
}
|
||||
case TwineNode::Kind::Dead:
|
||||
break;
|
||||
}
|
||||
return IdString::Null;
|
||||
}
|
||||
|
||||
std::string TwinePool::ref_token(IdString ref) const {
|
||||
return "#" + std::to_string((uint64_t)stamp(ref).bits());
|
||||
return "#" + std::to_string((uint64_t)serial_) + ":"
|
||||
+ std::to_string((uint64_t)stamp(ref).bits());
|
||||
}
|
||||
|
||||
IdString TwinePool::ref_from_token(std::string_view token) const {
|
||||
if (token.size() < 2 || token[0] != '#')
|
||||
return IdString::Null;
|
||||
size_t value = 0;
|
||||
for (char c : token.substr(1)) {
|
||||
if (c < '0' || c > '9')
|
||||
size_t sep = token.find(':');
|
||||
if (sep == std::string_view::npos)
|
||||
return IdString::Null;
|
||||
size_t fields[2] = {0, 0};
|
||||
std::string_view parts[2] = {token.substr(1, sep - 1), token.substr(sep + 1)};
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (parts[i].empty())
|
||||
return IdString::Null;
|
||||
value = value * 10 + (c - '0');
|
||||
for (char c : parts[i]) {
|
||||
if (c < '0' || c > '9')
|
||||
return IdString::Null;
|
||||
fields[i] = fields[i] * 10 + (c - '0');
|
||||
}
|
||||
}
|
||||
IdString ref(value);
|
||||
if (ref == IdString::Null || (!ID::is_static(ref) && ref.serial() != serial_))
|
||||
if (fields[0] != serial_)
|
||||
return IdString::Null;
|
||||
IdString ref(fields[1]);
|
||||
if (ref == IdString::Null)
|
||||
return IdString::Null;
|
||||
return is_live(ref) ? ref : IdString::Null;
|
||||
}
|
||||
@@ -317,18 +434,7 @@ void TwinePool::dump(std::ostream& os) const {
|
||||
os << "--------------------------------\n";
|
||||
}
|
||||
|
||||
bool TwinePool::inherits_publicity(const Twine &t) {
|
||||
auto *sfx = std::get_if<Twine::Suffix>(&t.data);
|
||||
return sfx != nullptr && sfx->prefix.isPublic();
|
||||
}
|
||||
|
||||
TwineNode TwinePool::to_node(Twine t) {
|
||||
if (auto *leaf = std::get_if<Twine::Leaf>(&t.data))
|
||||
return TwineNode{std::move(*leaf)};
|
||||
return TwineNode{std::move(std::get<Twine::Suffix>(t.data))};
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* TwineSegments holds a sequence of string_views refering to the strings
|
||||
* an IdString is composed of. It's used for lightweight comparisons.
|
||||
* The sequences is implemented in a "small vector" style,
|
||||
@@ -358,13 +464,17 @@ TwineSegments::TwineSegments(const TwinePool &pool, IdString ref)
|
||||
return;
|
||||
for (IdString cur = ref.untag(); ;) {
|
||||
const TwineNode &t = pool[cur];
|
||||
if (t.is_suffix()) {
|
||||
push(t.suffix().tail);
|
||||
cur = t.suffix().prefix.untag();
|
||||
switch (t.kind()) {
|
||||
case TwineNode::Kind::Suffix:
|
||||
push(t.text());
|
||||
cur = t.prefix();
|
||||
continue;
|
||||
case TwineNode::Kind::Leaf:
|
||||
push(t.text());
|
||||
break;
|
||||
case TwineNode::Kind::Dead:
|
||||
break;
|
||||
}
|
||||
if (t.is_leaf())
|
||||
push(t.leaf());
|
||||
break;
|
||||
}
|
||||
if (ref.isPublic())
|
||||
@@ -458,6 +568,13 @@ bool TwinePool::content_equal(IdString a, IdString b) const
|
||||
return compare_segments(sa, sb) == 0;
|
||||
}
|
||||
|
||||
IdString TwinePool::prefix_of(IdString ref) const {
|
||||
const TwineNode &t = (*this)[ref];
|
||||
if (!t.is_suffix())
|
||||
return IdString::Null;
|
||||
return stamp(t.prefix().tag(ref.isPublic()));
|
||||
}
|
||||
|
||||
int TwinePool::compare_by_name(IdString a, IdString b) const
|
||||
{
|
||||
if (a == b)
|
||||
@@ -471,9 +588,9 @@ int TwinePool::compare_by_name(IdString a, IdString b) const
|
||||
const TwineNode &ta = (*this)[a.untag()];
|
||||
const TwineNode &tb = (*this)[b.untag()];
|
||||
if (ta.is_leaf() && tb.is_leaf())
|
||||
return ta.leaf().compare(tb.leaf());
|
||||
if (ta.is_suffix() && tb.is_suffix() && ta.suffix().prefix == tb.suffix().prefix)
|
||||
return ta.suffix().tail.compare(tb.suffix().tail);
|
||||
return ta.text().compare(tb.text());
|
||||
if (ta.is_suffix() && tb.is_suffix() && ta.prefix() == tb.prefix())
|
||||
return ta.text().compare(tb.text());
|
||||
}
|
||||
|
||||
TwineSegments sa(*this, a), sb(*this, b);
|
||||
@@ -500,13 +617,15 @@ void DeepTwineHash::combine(Stream& s, IdString t) const {
|
||||
if (t == IdString::Null)
|
||||
return;
|
||||
const TwineNode& n = (*pool)[t];
|
||||
if (n.is_dead()) return;
|
||||
|
||||
if (n.is_leaf()) {
|
||||
s.push(n.leaf());
|
||||
} else if (n.is_suffix()) {
|
||||
combine(s, n.suffix().prefix);
|
||||
s.push(n.suffix().tail);
|
||||
switch (n.kind()) {
|
||||
case TwineNode::Kind::Dead:
|
||||
break;
|
||||
case TwineNode::Kind::Suffix:
|
||||
combine(s, n.prefix());
|
||||
[[fallthrough]];
|
||||
case TwineNode::Kind::Leaf:
|
||||
s.push(n.text());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -526,16 +645,15 @@ bool DeepTwineEq::consume(IdString t, std::string_view& sv) const noexcept {
|
||||
if (t == IdString::Null)
|
||||
return true;
|
||||
const TwineNode& n = (*pool)[t];
|
||||
if (n.is_dead()) return true;
|
||||
|
||||
if (n.is_leaf()) {
|
||||
if (!sv.starts_with(n.leaf())) return false;
|
||||
sv.remove_prefix(n.leaf().size());
|
||||
switch (n.kind()) {
|
||||
case TwineNode::Kind::Dead:
|
||||
return true;
|
||||
} else if (n.is_suffix()) {
|
||||
if (!consume(n.suffix().prefix, sv)) return false;
|
||||
if (!sv.starts_with(n.suffix().tail)) return false;
|
||||
sv.remove_prefix(n.suffix().tail.size());
|
||||
case TwineNode::Kind::Suffix:
|
||||
if (!consume(n.prefix(), sv)) return false;
|
||||
[[fallthrough]];
|
||||
case TwineNode::Kind::Leaf:
|
||||
if (!sv.starts_with(n.text())) return false;
|
||||
sv.remove_prefix(n.text().size());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
+168
-55
@@ -5,8 +5,11 @@
|
||||
#include "kernel/yosys_common.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <bit>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <deque>
|
||||
#include <limits>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
@@ -16,27 +19,43 @@
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
struct Twine;
|
||||
struct TwineSpec;
|
||||
struct TwinePool;
|
||||
struct IdString;
|
||||
|
||||
// An IdString now references a Twine in a per-Design TwinePool.
|
||||
// Twines are designed to deduplicate prefixes if appropriately constructed.
|
||||
// Statically, compile-time allocated indices defined in kernel/constids.inc
|
||||
// are handled with a global read-only pool.
|
||||
// A general IdString can't be constructed, converted to a string, or printed
|
||||
// without a pointer to the pool.
|
||||
// Two IdStrings that resolve to the same string won't generally compare
|
||||
// equal with operator== but alternate mechanisms are provided for cases
|
||||
// where that is absolutely necessary but it should be avoided for performance,
|
||||
// see DeepTwine and TwineSearch.
|
||||
// Twines are deduplicated within a TwinePool in a "shallow" way, similar to FRAIGing.
|
||||
// Lookup from a string to IdString is expensive and provided by TwineSearch.
|
||||
// Instead of backslash escaping, identifier "publicity" is implemented
|
||||
// with a publicity bit on the IdString reference integer.
|
||||
// TwinePool is backed by an std::deque and a free list
|
||||
// and provides stable indices outside of garbage collection.
|
||||
// "Content" refers to the untagged backing.
|
||||
/**
|
||||
* A twine is a data structure designed to deduplicate prefixes.
|
||||
* The key idea is that a twine is a suffix node or a leaf node.
|
||||
* A leaf node holds a string,
|
||||
* while a suffix node appends a string to a twine.
|
||||
*
|
||||
* Twines are used here to implement IdString, the Yosys interned
|
||||
* string type. They're extended to the needs of Yosys, specifically
|
||||
* with efficient static NEW_ID prefixes,
|
||||
* and IdString holding a special bit marking the publicity of a name.
|
||||
* When public, a backslash is prepended when printing an IdString.
|
||||
*
|
||||
* An IdString references a TwineNode in a per-Design TwinePool
|
||||
* by indexing into it. It is constructed by interning a TwineSpec
|
||||
* into a TwinePool.
|
||||
*
|
||||
* A general IdString can't be constructed, converted to a string, or printed
|
||||
* without a pointer to the TwinePool.
|
||||
* Compile-time allocated indices defined in kernel/constids.inc
|
||||
* live in a global read-only pool, so they're an exception to that.
|
||||
*
|
||||
* Two IdStrings that resolve to the same string won't generally compare
|
||||
* equal with operator== so that comparisons are cheap,
|
||||
* but alternate mechanisms are provided for cases
|
||||
* where that is absolutely necessary but it should be avoided for performance,
|
||||
* like DeepTwine and TwineSearch.
|
||||
* Twines are deduplicated within a TwinePool in a "shallow" way, similar to FRAIGing.
|
||||
* Lookup from a string to IdString is expensive and provided by TwineSearch.
|
||||
*
|
||||
* TwinePool is backed by an std::deque and a free list
|
||||
* and provides stable indices outside of garbage collection.
|
||||
* "Content" refers to the untagged backing.
|
||||
*/
|
||||
|
||||
struct NullIdString {
|
||||
constexpr operator IdString() const;
|
||||
@@ -45,13 +64,20 @@ struct NullIdString {
|
||||
|
||||
struct IdString {
|
||||
private:
|
||||
size_t value;
|
||||
#ifdef YOSYS_ENABLE_TWINE_PROVENANCE
|
||||
using bits_t = uint64_t;
|
||||
#else
|
||||
using bits_t = uint32_t;
|
||||
#endif
|
||||
bits_t value;
|
||||
|
||||
static constexpr size_t TWINE_PUBLIC_BIT = 1ULL << 63;
|
||||
static constexpr size_t TWINE_NULL_VAL = ~size_t{0};
|
||||
static constexpr int TWINE_SERIAL_SHIFT = 32;
|
||||
static constexpr size_t TWINE_INDEX_MASK = (size_t{1} << TWINE_SERIAL_SHIFT) - 1;
|
||||
static constexpr size_t TWINE_SERIAL_MASK = ~(TWINE_INDEX_MASK | TWINE_PUBLIC_BIT);
|
||||
static constexpr int TWINE_WIDTH = std::numeric_limits<bits_t>::digits;
|
||||
static constexpr int TWINE_PUBLIC_SHIFT = TWINE_WIDTH - 1;
|
||||
static constexpr bits_t TWINE_PUBLIC_BIT = bits_t{1} << TWINE_PUBLIC_SHIFT;
|
||||
static constexpr bits_t TWINE_NULL_VAL = ~bits_t{0};
|
||||
static constexpr int TWINE_SERIAL_SHIFT = TWINE_WIDTH == 64 ? 32 : TWINE_PUBLIC_SHIFT;
|
||||
static constexpr bits_t TWINE_INDEX_MASK = (bits_t{1} << TWINE_SERIAL_SHIFT) - 1;
|
||||
static constexpr bits_t TWINE_SERIAL_MASK = bits_t(~(TWINE_INDEX_MASK | TWINE_PUBLIC_BIT));
|
||||
|
||||
public:
|
||||
static constexpr NullIdString Null{};
|
||||
@@ -66,25 +92,27 @@ public:
|
||||
// raw() with the pool serial kept
|
||||
constexpr size_t bits() const { return value; }
|
||||
|
||||
constexpr size_t order_key() const { return std::rotl((bits_t) eq_key(), 1); }
|
||||
|
||||
constexpr size_t serial() const {
|
||||
return value == TWINE_NULL_VAL ? 0 : ((value & TWINE_SERIAL_MASK) >> TWINE_SERIAL_SHIFT);
|
||||
}
|
||||
|
||||
constexpr IdString stamped(size_t pool_serial) const {
|
||||
return value == TWINE_NULL_VAL ? *this
|
||||
: IdString((value & ~TWINE_SERIAL_MASK) | (pool_serial << TWINE_SERIAL_SHIFT));
|
||||
: IdString((value & ~TWINE_SERIAL_MASK)
|
||||
| (bits_t(pool_serial << TWINE_SERIAL_SHIFT) & TWINE_SERIAL_MASK));
|
||||
}
|
||||
|
||||
constexpr IdString() : value(TWINE_NULL_VAL) {}
|
||||
explicit constexpr IdString(size_t val) : value(val) {}
|
||||
explicit constexpr IdString(size_t val) : value((bits_t) val) {}
|
||||
|
||||
constexpr bool operator==(const IdString &rhs) const { return raw() == rhs.raw(); }
|
||||
constexpr bool operator!=(const IdString &rhs) const { return raw() != rhs.raw(); }
|
||||
constexpr size_t eq_key() const { return value & ~TWINE_SERIAL_MASK; }
|
||||
|
||||
constexpr bool operator==(const IdString &rhs) const { return eq_key() == rhs.eq_key(); }
|
||||
constexpr bool operator!=(const IdString &rhs) const { return eq_key() != rhs.eq_key(); }
|
||||
constexpr std::strong_ordering operator<=>(const IdString &rhs) const {
|
||||
size_t a = raw(), b = rhs.raw();
|
||||
if (auto cmp = (a & ~TWINE_PUBLIC_BIT) <=> (b & ~TWINE_PUBLIC_BIT); cmp != 0)
|
||||
return cmp;
|
||||
return (a & TWINE_PUBLIC_BIT) <=> (b & TWINE_PUBLIC_BIT);
|
||||
return order_key() <=> rhs.order_key();
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
@@ -121,6 +149,22 @@ public:
|
||||
constexpr NullIdString::operator IdString() const { return IdString(); }
|
||||
constexpr bool NullIdString::operator==(IdString ref) const { return ref.empty(); }
|
||||
|
||||
namespace hashlib {
|
||||
template<>
|
||||
struct hash_ops<IdString> {
|
||||
static inline bool cmp(IdString a, IdString b) { return a == b; }
|
||||
[[nodiscard]] static inline Hasher hash(IdString id) {
|
||||
Hasher h;
|
||||
h.force((Hasher::hash_t) id.bits());
|
||||
return h;
|
||||
}
|
||||
[[nodiscard]] static inline Hasher hash_into(IdString id, Hasher h) {
|
||||
h.hash64(id.eq_key());
|
||||
return h;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
enum : short {
|
||||
// STATIC_TWINE_BEGIN = 0,
|
||||
@@ -173,9 +217,9 @@ template<size_t Raw> inline constexpr IdString constid = IdString(Raw);
|
||||
|
||||
#define ID(id) (YOSYS_NAMESPACE_PREFIX constid<YOSYS_NAMESPACE_PREFIX ID::lookup(#id).raw()>)
|
||||
|
||||
// Twine is the object that lives in the TwinePool,
|
||||
// while IdString points to a Twine and carries publicity information
|
||||
struct Twine {
|
||||
// TwineSpec is the object that lives in the TwinePool,
|
||||
// while IdString points to a TwineSpec and carries publicity information
|
||||
struct TwineSpec {
|
||||
// deduplicates shared prefixes
|
||||
struct Suffix {
|
||||
IdString prefix;
|
||||
@@ -186,7 +230,7 @@ struct Twine {
|
||||
// transient suffix constructed with NEW_ID and NEW_ID_SUFFIX
|
||||
// turned into a regular Suffix when added to a TwinePool
|
||||
struct AutoSuffix {
|
||||
std::string_view prefix;
|
||||
const std::string *prefix;
|
||||
std::string tail;
|
||||
auto operator<=>(const AutoSuffix&) const = default;
|
||||
};
|
||||
@@ -199,30 +243,88 @@ struct Twine {
|
||||
|
||||
std::variant<Leaf, Suffix, AutoSuffix> data;
|
||||
|
||||
Twine(Leaf v);
|
||||
Twine(Suffix v);
|
||||
Twine(AutoSuffix v);
|
||||
TwineSpec(Leaf v);
|
||||
TwineSpec(Suffix v);
|
||||
TwineSpec(AutoSuffix v);
|
||||
|
||||
bool is_leaf() const;
|
||||
bool is_suffix() const;
|
||||
bool holds_leaf() const;
|
||||
bool holds_suffix() const;
|
||||
// Only for the pool-free variants, Leaf and AutoSuffix
|
||||
std::string content_str() const;
|
||||
};
|
||||
|
||||
struct SmallString {
|
||||
static constexpr uint32_t INLINE_CAP = 8;
|
||||
static constexpr size_t MAX_LEN = std::numeric_limits<uint32_t>::max();
|
||||
|
||||
SmallString() = default;
|
||||
explicit SmallString(std::string_view content);
|
||||
SmallString(const SmallString &other);
|
||||
SmallString(SmallString &&other) noexcept;
|
||||
SmallString &operator=(const SmallString &other);
|
||||
SmallString &operator=(SmallString &&other) noexcept;
|
||||
~SmallString();
|
||||
|
||||
std::string_view view() const { return {len_ <= INLINE_CAP ? inl_ : ptr_, len_}; }
|
||||
|
||||
private:
|
||||
void store(std::string_view content);
|
||||
void release();
|
||||
|
||||
union {
|
||||
char inl_[INLINE_CAP];
|
||||
char *ptr_;
|
||||
};
|
||||
uint32_t len_ = 0;
|
||||
};
|
||||
|
||||
// TwineNode is the in-memory version of TwineSpec
|
||||
struct TwineNode {
|
||||
std::variant<std::monostate, Twine::Leaf, Twine::Suffix> data;
|
||||
static constexpr uint32_t NO_PREFIX = ~uint32_t{0};
|
||||
static constexpr uint32_t DEAD = NO_PREFIX - 1;
|
||||
|
||||
struct Key {
|
||||
uint32_t prefix;
|
||||
std::string_view text;
|
||||
};
|
||||
|
||||
TwineNode() = default;
|
||||
TwineNode(Twine::Leaf v);
|
||||
TwineNode(Twine::Suffix v);
|
||||
explicit TwineNode(std::string_view content) : text_(content), prefix_(NO_PREFIX) {}
|
||||
TwineNode(uint32_t prefix, std::string_view tail) : text_(tail), prefix_(prefix) {}
|
||||
TwineNode(const TwineNode &other) = default;
|
||||
TwineNode(TwineNode &&other) noexcept;
|
||||
TwineNode &operator=(const TwineNode &other) = default;
|
||||
TwineNode &operator=(TwineNode &&other) noexcept;
|
||||
~TwineNode() = default;
|
||||
|
||||
bool is_dead() const;
|
||||
bool is_leaf() const;
|
||||
bool is_suffix() const;
|
||||
const std::string &leaf() const;
|
||||
const Twine::Suffix &suffix() const;
|
||||
enum class Kind { Dead, Leaf, Suffix };
|
||||
|
||||
constexpr bool is_dead() const { return prefix_ == DEAD; }
|
||||
constexpr bool is_leaf() const { return prefix_ == NO_PREFIX; }
|
||||
constexpr bool is_suffix() const { return prefix_ < DEAD; }
|
||||
|
||||
constexpr Kind kind() const {
|
||||
return prefix_ == DEAD ? Kind::Dead
|
||||
: prefix_ == NO_PREFIX ? Kind::Leaf
|
||||
: Kind::Suffix;
|
||||
}
|
||||
|
||||
std::string_view text() const { return text_.view(); }
|
||||
IdString prefix() const { return IdString(prefix_); }
|
||||
Key key() const { return {prefix_, text()}; }
|
||||
|
||||
bool operator==(const TwineNode &other) const
|
||||
{ return prefix_ == other.prefix_ && text() == other.text(); }
|
||||
bool operator==(const Key &other) const
|
||||
{ return prefix_ == other.prefix && text() == other.text; }
|
||||
|
||||
private:
|
||||
YS_NO_UNIQUE_ADDRESS SmallString text_;
|
||||
uint32_t prefix_ = DEAD;
|
||||
};
|
||||
|
||||
static_assert(sizeof(TwineNode) == 16);
|
||||
|
||||
struct StaticTwines {
|
||||
static constexpr size_t count = STATIC_TWINE_END;
|
||||
|
||||
@@ -260,11 +362,19 @@ struct TwinePool : HashConsPool<TwinePool, TwineNode, IdString> {
|
||||
static void check_ready();
|
||||
static void canonicalize(TwineNode& t);
|
||||
static size_t hash_node(const TwineNode& t);
|
||||
static size_t hash_key(const TwineNode::Key& k);
|
||||
|
||||
template<typename F>
|
||||
static void for_each_child(const TwineNode& t, F&& f) {
|
||||
if (t.is_suffix())
|
||||
f(t.suffix().prefix);
|
||||
f(t.prefix());
|
||||
}
|
||||
|
||||
template<typename Roots>
|
||||
size_t gc(Roots& roots) {
|
||||
for (auto &it : auto_prefixes)
|
||||
roots.insert(it.second);
|
||||
return HashConsPool::gc(roots);
|
||||
}
|
||||
|
||||
void dump(IdString ref, std::ostream& os = std::cout) const;
|
||||
@@ -282,12 +392,15 @@ struct TwinePool : HashConsPool<TwinePool, TwineNode, IdString> {
|
||||
bool name_equal(IdString ref, std::string_view name) const;
|
||||
bool content_equal(IdString a, IdString b) const;
|
||||
int compare_by_name(IdString a, IdString b) const;
|
||||
IdString prefix_of(IdString ref) const;
|
||||
|
||||
// Only finds leaves. For compatibility only
|
||||
IdString find(const std::string &name) const;
|
||||
IdString find(Twine t) const;
|
||||
IdString find(TwineSpec t) const;
|
||||
// Doesn't infer publicity
|
||||
IdString add(Twine t);
|
||||
IdString add(TwineSpec t);
|
||||
IdString add(IdString prefix, std::string_view tail);
|
||||
IdString auto_prefix(const std::string *prefix);
|
||||
// Infers publicity from first character
|
||||
IdString add(std::string s);
|
||||
IdString copy_from(const TwinePool& src, IdString ref);
|
||||
@@ -303,11 +416,11 @@ struct TwinePool : HashConsPool<TwinePool, TwineNode, IdString> {
|
||||
|
||||
private:
|
||||
IdString add_inner(TwineNode t);
|
||||
IdString intern(uint32_t prefix, std::string_view text);
|
||||
IdString find_content(uint32_t prefix, std::string_view text) const;
|
||||
static size_t next_serial();
|
||||
dict<const std::string *, IdString> auto_prefixes;
|
||||
size_t serial_;
|
||||
|
||||
static bool inherits_publicity(const Twine &t);
|
||||
static TwineNode to_node(Twine t);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
+10
-4
@@ -123,6 +123,12 @@
|
||||
# define YS_MAYBE_UNUSED
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# define YS_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]]
|
||||
#else
|
||||
# define YS_NO_UNIQUE_ADDRESS [[no_unique_address]]
|
||||
#endif
|
||||
|
||||
#if __cplusplus >= 202002L
|
||||
# define YS_FALLTHROUGH [[fallthrough]];
|
||||
#else
|
||||
@@ -309,14 +315,14 @@ extern bool yosys_write_versions;
|
||||
const std::string *create_id_prefix(std::string_view file, int line, std::string_view func);
|
||||
|
||||
#define NEW_ID \
|
||||
YOSYS_NAMESPACE_PREFIX Twine{YOSYS_NAMESPACE_PREFIX Twine::AutoSuffix{[](std::string_view func) -> std::string_view { \
|
||||
YOSYS_NAMESPACE_PREFIX TwineSpec{YOSYS_NAMESPACE_PREFIX TwineSpec::AutoSuffix{[](std::string_view func) -> const std::string * { \
|
||||
static std::unique_ptr<const std::string> prefix(YOSYS_NAMESPACE_PREFIX create_id_prefix(__FILE__, __LINE__, func)); \
|
||||
return *prefix; \
|
||||
return prefix.get(); \
|
||||
}(__FUNCTION__), std::to_string(YOSYS_NAMESPACE_PREFIX autoidx++)}}
|
||||
#define NEW_ID_SUFFIX(suffix) \
|
||||
YOSYS_NAMESPACE_PREFIX Twine{YOSYS_NAMESPACE_PREFIX Twine::AutoSuffix{[](std::string_view func) -> std::string_view { \
|
||||
YOSYS_NAMESPACE_PREFIX TwineSpec{YOSYS_NAMESPACE_PREFIX TwineSpec::AutoSuffix{[](std::string_view func) -> const std::string * { \
|
||||
static std::unique_ptr<const std::string> prefix(YOSYS_NAMESPACE_PREFIX create_id_prefix(__FILE__, __LINE__, func)); \
|
||||
return *prefix; \
|
||||
return prefix.get(); \
|
||||
}(__FUNCTION__), std::string(suffix) + "$" + std::to_string(YOSYS_NAMESPACE_PREFIX autoidx++)}}
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
@@ -18,5 +18,6 @@
|
||||
#cmakedefine YOSYS_ENABLE_TCL
|
||||
#cmakedefine YOSYS_ENABLE_PYTHON
|
||||
#cmakedefine YOSYS_ENABLE_VERIFIC
|
||||
#cmakedefine YOSYS_ENABLE_TWINE_PROVENANCE
|
||||
|
||||
#endif
|
||||
|
||||
@@ -297,7 +297,7 @@ struct DesignPass : public Pass {
|
||||
if (done.count(cell->type) == 0)
|
||||
{
|
||||
IdString trg_ref = copy_to_design->twines.add(
|
||||
Twine::Suffix{as_name_ref, "." + cell->type.unescape()});
|
||||
TwineSpec::Suffix{as_name_ref, "." + cell->type.unescape()});
|
||||
|
||||
log("Importing %s as %s.\n", fmod, PooledName(copy_to_design, trg_ref).unescape());
|
||||
|
||||
|
||||
@@ -834,7 +834,7 @@ struct DftTagWorker {
|
||||
}
|
||||
|
||||
|
||||
SigSpec autoAnd(Twine &&name, const SigSpec &sig_a, const SigSpec &sig_b)
|
||||
SigSpec autoAnd(TwineSpec &&name, const SigSpec &sig_a, const SigSpec &sig_b)
|
||||
{
|
||||
log_assert(GetSize(sig_a) == GetSize(sig_b));
|
||||
if (sig_a.is_fully_zero() || sig_b.is_fully_ones() || sig_a == sig_b)
|
||||
@@ -845,7 +845,7 @@ struct DftTagWorker {
|
||||
return module->And(std::move(name), sig_a, sig_b);
|
||||
}
|
||||
|
||||
SigSpec autoOr(Twine &&name, const SigSpec &sig_a, const SigSpec &sig_b)
|
||||
SigSpec autoOr(TwineSpec &&name, const SigSpec &sig_a, const SigSpec &sig_b)
|
||||
{
|
||||
log_assert(GetSize(sig_a) == GetSize(sig_b));
|
||||
if (sig_a.is_fully_ones() || sig_b.is_fully_zero() || sig_a == sig_b)
|
||||
@@ -856,7 +856,7 @@ struct DftTagWorker {
|
||||
return module->Or(std::move(name), sig_a, sig_b);
|
||||
}
|
||||
|
||||
SigSpec autoXor(Twine &&name, const SigSpec &sig_a, const SigSpec &sig_b)
|
||||
SigSpec autoXor(TwineSpec &&name, const SigSpec &sig_a, const SigSpec &sig_b)
|
||||
{
|
||||
log_assert(GetSize(sig_a) == GetSize(sig_b));
|
||||
if (sig_a == sig_b)
|
||||
@@ -872,7 +872,7 @@ struct DftTagWorker {
|
||||
return module->Xor(std::move(name), sig_a, sig_b);
|
||||
}
|
||||
|
||||
SigSpec autoXnor(Twine &&name, const SigSpec &sig_a, const SigSpec &sig_b)
|
||||
SigSpec autoXnor(TwineSpec &&name, const SigSpec &sig_a, const SigSpec &sig_b)
|
||||
{
|
||||
log_assert(GetSize(sig_a) == GetSize(sig_b));
|
||||
if (sig_a == sig_b)
|
||||
@@ -888,7 +888,7 @@ struct DftTagWorker {
|
||||
return module->Xnor(std::move(name), sig_a, sig_b);
|
||||
}
|
||||
|
||||
SigSpec autoNot(Twine &&name, const SigSpec &sig_a)
|
||||
SigSpec autoNot(TwineSpec &&name, const SigSpec &sig_a)
|
||||
{
|
||||
if (sig_a.is_fully_const()) {
|
||||
auto const_val = sig_a.as_const();
|
||||
@@ -901,7 +901,7 @@ struct DftTagWorker {
|
||||
return module->Not(std::move(name), sig_a);
|
||||
}
|
||||
|
||||
SigSpec autoEq(Twine &&name, const SigSpec &sig_a, const SigSpec &sig_b)
|
||||
SigSpec autoEq(TwineSpec &&name, const SigSpec &sig_a, const SigSpec &sig_b)
|
||||
{
|
||||
log_assert(GetSize(sig_a) == GetSize(sig_b));
|
||||
if (sig_a == sig_b)
|
||||
@@ -919,7 +919,7 @@ struct DftTagWorker {
|
||||
return module->Eq(std::move(name), sig_a, sig_b);
|
||||
}
|
||||
|
||||
SigSpec autoGe(Twine &&name, const SigSpec &sig_a, const SigSpec &sig_b)
|
||||
SigSpec autoGe(TwineSpec &&name, const SigSpec &sig_a, const SigSpec &sig_b)
|
||||
{
|
||||
log_assert(GetSize(sig_a) == GetSize(sig_b));
|
||||
if (sig_a == sig_b || sig_a.is_fully_ones())
|
||||
@@ -930,7 +930,7 @@ struct DftTagWorker {
|
||||
return module->Ge(std::move(name), sig_a, sig_b);
|
||||
}
|
||||
|
||||
SigSpec autoReduceAnd(Twine &&name, const SigSpec &sig_a)
|
||||
SigSpec autoReduceAnd(TwineSpec &&name, const SigSpec &sig_a)
|
||||
{
|
||||
if (GetSize(sig_a) == 0)
|
||||
return State::S1;
|
||||
@@ -945,7 +945,7 @@ struct DftTagWorker {
|
||||
return module->ReduceAnd(std::move(name), sig_a);
|
||||
}
|
||||
|
||||
SigSpec autoReduceOr(Twine &&name, const SigSpec &sig_a)
|
||||
SigSpec autoReduceOr(TwineSpec &&name, const SigSpec &sig_a)
|
||||
{
|
||||
if (GetSize(sig_a) == 0)
|
||||
return State::S0;
|
||||
|
||||
@@ -72,21 +72,21 @@ IdString remap_flattened_name(RTLIL::Design *design, IdString obj_ref,
|
||||
return it->second;
|
||||
|
||||
const TwineNode &node = design->twines[obj_ref];
|
||||
IdString parent = design->twines.prefix_of(obj_ref);
|
||||
IdString result;
|
||||
if (node.is_suffix()) {
|
||||
const Twine::Suffix &sfx = node.suffix();
|
||||
IdString prefix = remap_flattened_name(design, sfx.prefix.tag(obj_ref.isPublic()),
|
||||
if (parent != IdString::Null) {
|
||||
IdString prefix = remap_flattened_name(design, parent,
|
||||
pub_prefix_ref, priv_prefix_ref, separator, memo);
|
||||
result = design->twines.add(Twine::Suffix{prefix, sfx.tail});
|
||||
result = design->twines.add(TwineSpec::Suffix{prefix, std::string(node.text())});
|
||||
} else {
|
||||
std::string_view obj = node.leaf();
|
||||
std::string_view obj = node.text();
|
||||
if (obj_ref.isPublic()) {
|
||||
result = design->twines.add(Twine::Suffix{pub_prefix_ref, separator + std::string(obj)});
|
||||
result = design->twines.add(TwineSpec::Suffix{pub_prefix_ref, separator + std::string(obj)});
|
||||
} else {
|
||||
constexpr std::string_view flatten_prefix = "$flatten";
|
||||
if (obj.substr(0, flatten_prefix.size()) == flatten_prefix)
|
||||
obj.remove_prefix(flatten_prefix.size());
|
||||
result = design->twines.add(Twine::Suffix{priv_prefix_ref, std::string(obj)});
|
||||
result = design->twines.add(TwineSpec::Suffix{priv_prefix_ref, std::string(obj)});
|
||||
}
|
||||
}
|
||||
memo[obj_ref] = result;
|
||||
|
||||
@@ -49,7 +49,7 @@ inline IdString ref_from_token(RTLIL::Design *design, const std::string &tok)
|
||||
|
||||
inline IdString indexed_name(RTLIL::Design *design, IdString base, int index)
|
||||
{
|
||||
return design->twines.add(Twine::Suffix{base.untag(), stringf("[%d]", index)})
|
||||
return design->twines.add(TwineSpec::Suffix{base.untag(), stringf("[%d]", index)})
|
||||
.tag(base.isPublic());
|
||||
}
|
||||
|
||||
|
||||
@@ -201,7 +201,7 @@ struct BoothPassWorker {
|
||||
log_assert(sig_a.size() == sig_y.size());
|
||||
|
||||
for (int i = 0; i < sig_a.size(); i++)
|
||||
mod->addFa(Twine::Suffix{name, stringf("[%d]", i)}, sig_a[i], sig_b[i],
|
||||
mod->addFa(TwineSpec::Suffix{name, stringf("[%d]", i)}, sig_a[i], sig_b[i],
|
||||
sig_c[i], sig_x[i], sig_y[i]);
|
||||
}
|
||||
|
||||
|
||||
+10
-10
@@ -59,7 +59,7 @@ struct PrefixApplier
|
||||
PrefixApplier(RTLIL::Design *dst, IdString prefix, RTLIL::Design *src)
|
||||
: dst(dst), src(src), cell_name(prefix)
|
||||
{
|
||||
pub_prefix = dst->twines.add(Twine::Suffix{prefix, "."});
|
||||
pub_prefix = dst->twines.add(TwineSpec::Suffix{prefix, "."});
|
||||
}
|
||||
|
||||
IdString techmap_prefix()
|
||||
@@ -75,14 +75,14 @@ struct PrefixApplier
|
||||
return it->second;
|
||||
|
||||
const TwineNode &node = src->twines[obj_ref];
|
||||
IdString parent = src->twines.prefix_of(obj_ref);
|
||||
IdString result;
|
||||
if (node.is_suffix()) {
|
||||
const Twine::Suffix &sfx = node.suffix();
|
||||
IdString prefix = name(sfx.prefix.tag(obj_ref.isPublic()));
|
||||
result = dst->twines.add(Twine::Suffix{prefix, sfx.tail});
|
||||
if (parent != IdString::Null) {
|
||||
IdString prefix = name(parent);
|
||||
result = dst->twines.add(prefix, node.text());
|
||||
} else {
|
||||
IdString prefix = obj_ref.isPublic() ? pub_prefix : techmap_prefix();
|
||||
result = dst->twines.add(Twine::Suffix{prefix, node.leaf()});
|
||||
result = dst->twines.add(prefix, node.text());
|
||||
}
|
||||
memo[obj_ref] = result;
|
||||
return result;
|
||||
@@ -103,7 +103,7 @@ struct PrefixApplier
|
||||
|
||||
static RTLIL::Wire *map_port(RTLIL::Module *tpl, RTLIL::Design *src, IdString name)
|
||||
{
|
||||
return tpl->wire(tpl->design->twines.find(src->twines.str(name)));
|
||||
return tpl->wire(tpl->design->twines.find_from(src->twines, name));
|
||||
}
|
||||
|
||||
struct TechmapWorker
|
||||
@@ -165,7 +165,7 @@ struct TechmapWorker
|
||||
return result;
|
||||
|
||||
for (auto w : module->wires()) {
|
||||
if (w->name.str()[0] == '$')
|
||||
if (!w->name.isPublic())
|
||||
continue;
|
||||
|
||||
if (w->name.contains("_TECHMAP_") && !w->name.contains("_TECHMAP_REPLACE_")) {
|
||||
@@ -239,7 +239,7 @@ struct TechmapWorker
|
||||
IdString posportref = module->design->twines.add(std::string{stringf("$%d", tpl_w->port_id)});
|
||||
positional_ports.emplace(posportref, tpl_w->name);
|
||||
|
||||
IdString tpl_portname = module->design->twines.find(tpl_w->name.str());
|
||||
IdString tpl_portname = module->design->twines.find_from(tpl->design->twines, tpl_w->name);
|
||||
if (tpl_w->get_bool_attribute(ID::techmap_autopurge) &&
|
||||
(!cell->hasPort(tpl_portname) || !GetSize(cell->getPort(tpl_portname))) &&
|
||||
(!cell->hasPort(posportref) || !GetSize(cell->getPort(posportref))))
|
||||
@@ -300,7 +300,7 @@ struct TechmapWorker
|
||||
else
|
||||
w = map_port(tpl, design, portname);
|
||||
if (w == nullptr || w->port_id == 0) {
|
||||
if (design->twines.str(portname).starts_with("$"))
|
||||
if (!portname.isPublic())
|
||||
log_error("Can't map port `%s' of cell `%s' to template `%s'!\n", PooledName(design, portname).unescape(), cell->name.unescape(), tpl->name.unescape());
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ yosys_gtest(kernel
|
||||
rtlilHelpers.h
|
||||
rtlilStringTest.cc
|
||||
rtlilTest.cc
|
||||
sigbitPerfTest.cc
|
||||
sigspecExtractTest.cc
|
||||
sigspecRemove2Test.cc
|
||||
threadingTest.cc
|
||||
|
||||
@@ -46,7 +46,7 @@ TEST(NameMasqTest, SuffixQueries)
|
||||
Design design;
|
||||
Module *mod = design.addModule(std::string("\\zz_top"));
|
||||
IdString prefix = design.twines.add(std::string("\\zz_bus"));
|
||||
IdString suffixed = design.twines.add(Twine{Twine::Suffix{prefix, "_hi"}});
|
||||
IdString suffixed = design.twines.add(TwineSpec{TwineSpec::Suffix{prefix, "_hi"}});
|
||||
Wire *w = mod->addWire(suffixed, 1);
|
||||
|
||||
EXPECT_EQ(w->name.escaped(), "\\zz_bus_hi");
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include "kernel/rtlil.h"
|
||||
#include "kernel/sigtools.h"
|
||||
#include "kernel/yosys.h"
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
namespace {
|
||||
|
||||
int env_int(const char *name, int fallback)
|
||||
{
|
||||
const char *value = getenv(name);
|
||||
if (value == nullptr || *value == 0)
|
||||
return fallback;
|
||||
return atoi(value);
|
||||
}
|
||||
|
||||
size_t peak_rss_bytes()
|
||||
{
|
||||
struct rusage ru;
|
||||
if (getrusage(RUSAGE_SELF, &ru) != 0)
|
||||
return 0;
|
||||
return (size_t)ru.ru_maxrss * 1024;
|
||||
}
|
||||
|
||||
double ms(std::chrono::steady_clock::duration d)
|
||||
{
|
||||
return std::chrono::duration<double, std::milli>(d).count();
|
||||
}
|
||||
|
||||
uint32_t next_rand(uint32_t &state)
|
||||
{
|
||||
state = state * 1664525u + 1013904223u;
|
||||
return state >> 8;
|
||||
}
|
||||
|
||||
std::string padded(const char *stem, int index, int extra_chars)
|
||||
{
|
||||
std::string name = stringf("\\%s_%d", stem, index);
|
||||
name += std::string(extra_chars, 'n');
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TEST(SigBitPerf, hash_and_sigmap_stress)
|
||||
{
|
||||
int wire_count = env_int("YOSYS_SIGBIT_PERF_WIRES", 4000);
|
||||
int wire_width = env_int("YOSYS_SIGBIT_PERF_WIDTH", 16);
|
||||
int alias_every = env_int("YOSYS_SIGBIT_PERF_ALIAS", 4);
|
||||
int probe_rounds = env_int("YOSYS_SIGBIT_PERF_ROUNDS", 20);
|
||||
int name_padding = env_int("YOSYS_SIGBIT_PERF_NAMEPAD", 24);
|
||||
|
||||
ASSERT_GE(wire_count, 2);
|
||||
ASSERT_GE(wire_width, 1);
|
||||
ASSERT_GE(alias_every, 2);
|
||||
ASSERT_GE(probe_rounds, 1);
|
||||
|
||||
RTLIL::Design *design = new RTLIL::Design;
|
||||
RTLIL::Module *module = design->addModule(padded("sigbit_perf_module", 0, name_padding));
|
||||
|
||||
std::vector<RTLIL::Wire *> wires;
|
||||
wires.reserve(wire_count);
|
||||
for (int i = 0; i < wire_count; i++)
|
||||
wires.push_back(module->addWire(padded("sigbit_perf_wire", i, name_padding), wire_width));
|
||||
|
||||
int aliased = 0;
|
||||
for (int i = alias_every; i < wire_count; i += alias_every) {
|
||||
module->connect(RTLIL::SigSpec(wires[i]), RTLIL::SigSpec(wires[i - 1]));
|
||||
aliased++;
|
||||
}
|
||||
|
||||
std::vector<RTLIL::SigBit> bits;
|
||||
bits.reserve((size_t)wire_count * wire_width);
|
||||
for (RTLIL::Wire *wire : wires)
|
||||
for (int i = 0; i < wire_width; i++)
|
||||
bits.push_back(RTLIL::SigBit(wire, i));
|
||||
|
||||
uint32_t rng = 12345;
|
||||
std::vector<RTLIL::SigBit> probes = bits;
|
||||
for (size_t i = probes.size(); i > 1; i--)
|
||||
std::swap(probes[i - 1], probes[next_rand(rng) % i]);
|
||||
|
||||
size_t rss_before = peak_rss_bytes();
|
||||
|
||||
auto t0 = std::chrono::steady_clock::now();
|
||||
SigMap sigmap(module);
|
||||
auto t1 = std::chrono::steady_clock::now();
|
||||
|
||||
size_t sigmap_checksum = 0;
|
||||
for (int round = 0; round < probe_rounds; round++)
|
||||
for (const RTLIL::SigBit &bit : probes)
|
||||
sigmap_checksum += sigmap(bit).offset;
|
||||
auto t2 = std::chrono::steady_clock::now();
|
||||
|
||||
pool<RTLIL::SigBit> seen;
|
||||
for (int round = 0; round < probe_rounds; round++) {
|
||||
seen.clear();
|
||||
for (const RTLIL::SigBit &bit : probes)
|
||||
seen.insert(bit);
|
||||
}
|
||||
auto t3 = std::chrono::steady_clock::now();
|
||||
|
||||
size_t hits = 0;
|
||||
for (int round = 0; round < probe_rounds; round++)
|
||||
for (const RTLIL::SigBit &bit : probes)
|
||||
hits += seen.count(bit);
|
||||
auto t4 = std::chrono::steady_clock::now();
|
||||
|
||||
dict<RTLIL::SigBit, int> owner;
|
||||
for (int round = 0; round < probe_rounds; round++) {
|
||||
owner.clear();
|
||||
int n = 0;
|
||||
for (const RTLIL::SigBit &bit : probes)
|
||||
owner[bit] = n++;
|
||||
}
|
||||
auto t5 = std::chrono::steady_clock::now();
|
||||
|
||||
size_t dict_checksum = 0;
|
||||
for (int round = 0; round < probe_rounds; round++)
|
||||
for (const RTLIL::SigBit &bit : probes)
|
||||
dict_checksum += owner.at(bit);
|
||||
auto t6 = std::chrono::steady_clock::now();
|
||||
|
||||
size_t bit_count = probes.size();
|
||||
size_t ops = bit_count * (size_t)probe_rounds;
|
||||
|
||||
EXPECT_EQ(seen.size(), bit_count);
|
||||
EXPECT_EQ(owner.size(), bit_count);
|
||||
EXPECT_EQ(hits, ops);
|
||||
|
||||
printf("[ PERF ] wires=%d width=%d alias_every=%d aliased=%d namepad=%d rounds=%d\n",
|
||||
wire_count, wire_width, alias_every, aliased, name_padding, probe_rounds);
|
||||
printf("[ PERF ] bits=%zu ops_per_phase=%zu checksums=%zu,%zu\n",
|
||||
bit_count, ops, sigmap_checksum, dict_checksum);
|
||||
printf("[ PERF ] sigmap_build_ms=%.1f sigmap_lookup_ns=%.2f\n",
|
||||
ms(t1 - t0), 1e6 * ms(t2 - t1) / (double)ops);
|
||||
printf("[ PERF ] pool_insert_ns=%.2f pool_lookup_ns=%.2f\n",
|
||||
1e6 * ms(t3 - t2) / (double)ops, 1e6 * ms(t4 - t3) / (double)ops);
|
||||
printf("[ PERF ] dict_insert_ns=%.2f dict_lookup_ns=%.2f\n",
|
||||
1e6 * ms(t5 - t4) / (double)ops, 1e6 * ms(t6 - t5) / (double)ops);
|
||||
printf("[ PERF ] total_ms=%.1f peak_rss_mb=%.1f rss_before_mb=%.1f\n",
|
||||
ms(t6 - t0), peak_rss_bytes() / 1048576.0, rss_before / 1048576.0);
|
||||
fflush(stdout);
|
||||
|
||||
delete design;
|
||||
}
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
@@ -18,7 +18,7 @@ TEST(TwineHashTest, Fragmentation)
|
||||
|
||||
IdString flat = pool.add(std::string("$abcdefghij"));
|
||||
IdString base = pool.add(std::string("$abcde"));
|
||||
IdString split = pool.add(Twine::Suffix{base, "fghij"});
|
||||
IdString split = pool.add(TwineSpec::Suffix{base, "fghij"});
|
||||
|
||||
EXPECT_EQ(hash(flat.untag()), hash(split.untag()));
|
||||
EXPECT_EQ(hash(flat.untag()), hash(std::string_view("$abcdefghij")));
|
||||
@@ -35,7 +35,7 @@ TEST(TwineHashTest, SplitPoints)
|
||||
|
||||
for (size_t cut = 1; cut < content.size(); cut++) {
|
||||
IdString base = pool.add(content.substr(0, cut));
|
||||
IdString split = pool.add(Twine::Suffix{base, content.substr(cut)});
|
||||
IdString split = pool.add(TwineSpec::Suffix{base, content.substr(cut)});
|
||||
EXPECT_EQ(hash(split.untag()), want) << "split after " << cut;
|
||||
}
|
||||
}
|
||||
@@ -63,7 +63,7 @@ TEST(TwineHashTest, BenchmarkIntern)
|
||||
std::vector<IdString> refs;
|
||||
refs.reserve(kNames);
|
||||
for (int i = 0; i < kNames; i++)
|
||||
refs.push_back(pool.add(Twine::Suffix{prefix, stringf("$%d", i)}));
|
||||
refs.push_back(pool.add(TwineSpec::Suffix{prefix, stringf("$%d", i)}));
|
||||
auto t1 = std::chrono::steady_clock::now();
|
||||
|
||||
TwineSearch search(&pool);
|
||||
|
||||
@@ -47,8 +47,8 @@ TEST(TwinePublicityTest, SuffixPublicity)
|
||||
IdString pub = pool.add(std::string("\\base"));
|
||||
IdString priv = pool.add(std::string("$base"));
|
||||
|
||||
IdString pub_sfx = pool.add(Twine{Twine::Suffix{pub, "_1"}});
|
||||
IdString priv_sfx = pool.add(Twine{Twine::Suffix{priv, "_1"}});
|
||||
IdString pub_sfx = pool.add(TwineSpec{TwineSpec::Suffix{pub, "_1"}});
|
||||
IdString priv_sfx = pool.add(TwineSpec{TwineSpec::Suffix{priv, "_1"}});
|
||||
|
||||
EXPECT_TRUE(pub_sfx.isPublic());
|
||||
EXPECT_FALSE(priv_sfx.isPublic());
|
||||
@@ -82,9 +82,9 @@ TEST(TwinePublicityTest, LookupTag)
|
||||
TEST(TwinePublicityTest, SearchUnifies)
|
||||
{
|
||||
TwinePool pool;
|
||||
IdString flat = pool.add(Twine::Leaf{"$abc"});
|
||||
IdString head = pool.add(Twine::Leaf{"$a"});
|
||||
IdString split = pool.add(Twine::Suffix{head, "bc"});
|
||||
IdString flat = pool.add(TwineSpec::Leaf{"$abc"});
|
||||
IdString head = pool.add(TwineSpec::Leaf{"$a"});
|
||||
IdString split = pool.add(TwineSpec::Suffix{head, "bc"});
|
||||
|
||||
ASSERT_NE(flat, split);
|
||||
ASSERT_EQ(pool.str(flat), pool.str(split));
|
||||
@@ -100,7 +100,7 @@ TEST(TwinePublicityTest, SearchUnifies)
|
||||
TEST(TwinePublicityTest, SearchPublicity)
|
||||
{
|
||||
TwinePool pool;
|
||||
IdString priv = pool.add(Twine::Leaf{"sig"});
|
||||
IdString priv = pool.add(TwineSpec::Leaf{"sig"});
|
||||
IdString pub = pool.add(std::string("\\sig"));
|
||||
|
||||
ASSERT_EQ(priv, pub.untag());
|
||||
|
||||
@@ -15,7 +15,7 @@ std::vector<IdString> bench_refs(TwinePool &twines, int count)
|
||||
std::vector<IdString> refs;
|
||||
refs.reserve(count);
|
||||
for (int i = 0; i < count; i++)
|
||||
refs.push_back(twines.add(Twine::Suffix{prefix, stringf("$%08d", (count - i) * 7919 % count)}));
|
||||
refs.push_back(twines.add(TwineSpec::Suffix{prefix, stringf("$%08d", (count - i) * 7919 % count)}));
|
||||
return refs;
|
||||
}
|
||||
|
||||
@@ -69,14 +69,14 @@ TEST(TwineSortTest, GeneralWalk)
|
||||
|
||||
IdString deep = a;
|
||||
for (int i = 0; i < 12; i++) {
|
||||
deep = twines.add(Twine::Suffix{deep, stringf(".lvl%d", i)});
|
||||
deep = twines.add(TwineSpec::Suffix{deep, stringf(".lvl%d", i)});
|
||||
refs.push_back(deep);
|
||||
refs.push_back(deep.tag(true));
|
||||
}
|
||||
|
||||
IdString other = twines.add(std::string("$alpha."));
|
||||
for (int i = 0; i < 12; i++) {
|
||||
other = twines.add(Twine::Suffix{other, stringf("lvl%d.", i)});
|
||||
other = twines.add(TwineSpec::Suffix{other, stringf("lvl%d.", i)});
|
||||
refs.push_back(other);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,4 +28,4 @@ hierarchy -top top
|
||||
rename -seed 2 -scramble-name c:bar
|
||||
select -assert-none c:bar
|
||||
select -assert-count 1 c:$_*_
|
||||
select -assert-none c:$_*_ w:* foo/c:$add$<inlined>:2$1 %% %n
|
||||
select -assert-none c:$_*_ w:* foo/c:$<inlined>:2$add$1 %% %n
|
||||
|
||||
@@ -27,7 +27,7 @@ select -assert-count 1 w:$e
|
||||
# Colliding with keyword
|
||||
select -assert-count 1 w:wire
|
||||
# Don't touch internal names
|
||||
select -assert-count 1 w:$add$<inlined>:*$1_Y
|
||||
select -assert-count 1 w:$<inlined>:*$add$*_Y
|
||||
|
||||
rename -unescape
|
||||
|
||||
@@ -38,7 +38,7 @@ select -assert-count 1 w:d_
|
||||
select -assert-count 1 w:d__1
|
||||
select -assert-count 1 w:_e
|
||||
select -assert-count 1 w:wire_
|
||||
select -assert-count 1 w:$add$<inlined>:*$1_Y
|
||||
select -assert-count 1 w:$<inlined>:*$add$*_Y
|
||||
|
||||
# Ports are updated during rename
|
||||
design -reset
|
||||
|
||||
Reference in New Issue
Block a user