twines: LeafIdString

This commit is contained in:
Emil J. Tywoniak
2026-10-02 18:42:01 +02:00
parent 080e46417a
commit e3dde40848
2 changed files with 66 additions and 10 deletions
+23 -4
View File
@@ -176,6 +176,10 @@ IdString TwinePool::stamp(IdString ref) const {
return ref.stamped(serial_);
}
LeafIdString TwinePool::stamp(LeafIdString ref) const {
return LeafIdString(stamp(IdString(ref)));
}
void TwinePool::check_owned(IdString ref) const {
if constexpr (IdString::MAX_SERIAL != 0)
log_assert(owns(ref));
@@ -295,12 +299,12 @@ IdString TwinePool::intern(uint32_t prefix, std::string_view text) {
return add_inner(TwineNode{prefix, text});
}
IdString TwinePool::find(const std::string &name) const {
LeafIdString TwinePool::find(const std::string &name) const {
bool is_public = !name.empty() && name[0] == '\\';
std::string_view content = name;
if (is_public)
content.remove_prefix(1);
return stamp(find_content(TwineNode::NO_PREFIX, content).tag(is_public));
return stamp(LeafIdString(find_content(TwineNode::NO_PREFIX, content)).tag(is_public));
}
IdString TwinePool::find(TwineSpec t) const {
@@ -340,11 +344,17 @@ 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) {
LeafIdString TwinePool::add(std::string s) {
if (s.empty())
return IdString::Null;
auto [content, is_public] = twine_unescape(std::move(s));
return stamp(intern(TwineNode::NO_PREFIX, content).tag(is_public));
return stamp(LeafIdString(intern(TwineNode::NO_PREFIX, content)).tag(is_public));
}
LeafIdString TwinePool::flatten(IdString ref) {
if (ref == IdString::Null || ID::is_static(ref) || (*this)[ref].is_leaf())
return LeafIdString(stamp(ref));
return stamp(LeafIdString(intern(TwineNode::NO_PREFIX, unescaped_str(ref))).tag(ref.isPublic()));
}
IdString TwinePool::copy_from(const TwinePool& src, IdString ref) {
@@ -369,6 +379,11 @@ IdString TwinePool::copy_from(const TwinePool& src, IdString ref) {
return IdString::Null;
}
// Copying preserves structure, so leaves stay leaves
LeafIdString TwinePool::copy_from(const TwinePool& src, LeafIdString ref) {
return LeafIdString(copy_from(src, IdString(ref)));
}
IdString TwinePool::find_from(const TwinePool& src, IdString ref) const {
if (ref == IdString::Null)
return ref;
@@ -393,6 +408,10 @@ IdString TwinePool::find_from(const TwinePool& src, IdString ref) const {
return IdString::Null;
}
LeafIdString TwinePool::find_from(const TwinePool& src, LeafIdString ref) const {
return LeafIdString(find_from(src, IdString(ref)));
}
std::string TwinePool::ref_token(IdString ref) const {
return "#" + std::to_string((uint64_t)serial_) + ":"
+ std::to_string((uint64_t)stamp(ref).bits());
+43 -6
View File
@@ -150,6 +150,30 @@ public:
constexpr NullIdString::operator IdString() const { return IdString(); }
constexpr bool NullIdString::operator==(IdString ref) const { return ref.empty(); }
/**
* LeafIdString is an IdString that is statically known to be a leaf twine
* (or Null). Handles only compare equal when they're structurally equal,
* so a key that's looked up with static ids or strings interned with
* TwinePool::add(std::string), like attribute and parameter keys,
* has to be a leaf: a suffix twine spelling the same name wouldn't be found.
*
* Static ids are leaves. Otherwise, only the TwinePool methods that
* intern leaves construct one, so where a suffix would sneak in,
* the conversion has to be spelled out with TwinePool::flatten.
*/
struct LeafIdString : IdString {
constexpr LeafIdString() = default;
constexpr LeafIdString(NullIdString) {}
constexpr LeafIdString untag() const { return LeafIdString(IdString::untag()); }
constexpr LeafIdString tag(bool pub) const { return LeafIdString(IdString::tag(pub)); }
private:
explicit constexpr LeafIdString(IdString ref) : IdString(ref) {}
friend struct ID;
friend struct TwinePool;
};
namespace hashlib {
template<>
struct hash_ops<IdString> {
@@ -164,6 +188,8 @@ namespace hashlib {
return h;
}
};
template<>
struct hash_ops<LeafIdString> : hash_ops<IdString> {};
}
@@ -178,7 +204,7 @@ enum : short {
struct ID {
// Static ids are name handles: non-'$' constids were '\'-escaped publics,
// so their handles carry the publicity bit baked in at compile time.
#define X(N) static constexpr IdString N = IdString(IDX_##N).tag((#N)[0] != '$');
#define X(N) static constexpr LeafIdString N = LeafIdString(IdString(IDX_##N)).tag((#N)[0] != '$');
#include "kernel/constids.inc"
#undef X
@@ -188,7 +214,7 @@ struct ID {
#undef X
};
static constexpr IdString lookup(std::string_view name)
static constexpr LeafIdString lookup(std::string_view name)
{
int low = 0, high = STATIC_TWINE_END;
while (high - low >= 2) {
@@ -202,19 +228,26 @@ struct ID {
if (name != static_names[low])
throw "unknown twine id";
return IdString(low).tag(name[0] != '$');
return LeafIdString(IdString(low)).tag(name[0] != '$');
}
static constexpr bool is_static(IdString ref) {
return ref.untag().raw() < STATIC_TWINE_END;
}
// All static twines are leaves
static constexpr LeafIdString static_leaf(size_t raw) {
if (!is_static(IdString(raw)))
throw "not a static twine id";
return LeafIdString(IdString(raw));
}
// Static IdString can be constructed without a design pointer
static std::string str(IdString ref);
static std::string unescaped_str(IdString ref);
};
template<size_t Raw> inline constexpr IdString constid = IdString(Raw);
template<size_t Raw> inline constexpr LeafIdString constid = ID::static_leaf(Raw);
#define ID(id) (YOSYS_NAMESPACE_PREFIX constid<YOSYS_NAMESPACE_PREFIX ID::lookup(#id).raw()>)
@@ -354,6 +387,7 @@ struct TwinePool : HashConsPool<TwinePool, TwineNode, IdString> {
size_t serial() const;
bool owns(IdString ref) const;
IdString stamp(IdString ref) const;
LeafIdString stamp(LeafIdString ref) const;
void check_owned(IdString ref) const;
const TwineNode& operator[](IdString ref) const;
@@ -396,17 +430,20 @@ struct TwinePool : HashConsPool<TwinePool, TwineNode, IdString> {
IdString prefix_of(IdString ref) const;
// Only finds leaves. For compatibility only
IdString find(const std::string &name) const;
LeafIdString find(const std::string &name) const;
IdString find(TwineSpec t) const;
// Doesn't infer publicity
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);
LeafIdString add(std::string s);
LeafIdString flatten(IdString ref);
IdString copy_from(const TwinePool& src, IdString ref);
LeafIdString copy_from(const TwinePool& src, LeafIdString ref);
// Non-mutating counterpart of copy_from
IdString find_from(const TwinePool& src, IdString ref) const;
LeafIdString find_from(const TwinePool& src, LeafIdString ref) const;
// Opaque handle for files that never leave one run of yosys.
// Only valid until garbage collection reuses the slot.
std::string ref_token(IdString ref) const;