Internals: Standardize template argument names. No functional change.

This commit is contained in:
Wilson Snyder 2024-11-29 20:20:38 -05:00
parent 990ccd6763
commit 0c820c3068
28 changed files with 524 additions and 521 deletions

View File

@ -1604,26 +1604,26 @@ static inline IData VL_PACK_II(int obits, int lbits, const VlQueue<IData>& q) {
return ret; return ret;
} }
template <std::size_t T_Depth> template <std::size_t N_Depth>
static inline IData VL_PACK_II(int obits, int lbits, const VlUnpacked<CData, T_Depth>& q) { static inline IData VL_PACK_II(int obits, int lbits, const VlUnpacked<CData, N_Depth>& q) {
IData ret = 0; IData ret = 0;
for (size_t i = 0; i < T_Depth; ++i) for (size_t i = 0; i < N_Depth; ++i)
ret |= static_cast<IData>(q[T_Depth - 1 - i]) << (i * lbits); ret |= static_cast<IData>(q[N_Depth - 1 - i]) << (i * lbits);
return ret; return ret;
} }
template <std::size_t T_Depth> template <std::size_t N_Depth>
static inline IData VL_PACK_II(int obits, int lbits, const VlUnpacked<SData, T_Depth>& q) { static inline IData VL_PACK_II(int obits, int lbits, const VlUnpacked<SData, N_Depth>& q) {
IData ret = 0; IData ret = 0;
for (size_t i = 0; i < T_Depth; ++i) for (size_t i = 0; i < N_Depth; ++i)
ret |= static_cast<IData>(q[T_Depth - 1 - i]) << (i * lbits); ret |= static_cast<IData>(q[N_Depth - 1 - i]) << (i * lbits);
return ret; return ret;
} }
template <std::size_t T_Depth> template <std::size_t N_Depth>
static inline IData VL_PACK_II(int obits, int lbits, const VlUnpacked<IData, T_Depth>& q) { static inline IData VL_PACK_II(int obits, int lbits, const VlUnpacked<IData, N_Depth>& q) {
IData ret = 0; IData ret = 0;
for (size_t i = 0; i < T_Depth; ++i) ret |= q[T_Depth - 1 - i] << (i * lbits); for (size_t i = 0; i < N_Depth; ++i) ret |= q[N_Depth - 1 - i] << (i * lbits);
return ret; return ret;
} }
@ -1645,27 +1645,27 @@ static inline QData VL_PACK_QI(int obits, int lbits, const VlQueue<IData>& q) {
return ret; return ret;
} }
template <std::size_t T_Depth> template <std::size_t N_Depth>
static inline QData VL_PACK_QI(int obits, int lbits, const VlUnpacked<CData, T_Depth>& q) { static inline QData VL_PACK_QI(int obits, int lbits, const VlUnpacked<CData, N_Depth>& q) {
QData ret = 0; QData ret = 0;
for (size_t i = 0; i < T_Depth; ++i) for (size_t i = 0; i < N_Depth; ++i)
ret |= static_cast<QData>(q[T_Depth - 1 - i]) << (i * lbits); ret |= static_cast<QData>(q[N_Depth - 1 - i]) << (i * lbits);
return ret; return ret;
} }
template <std::size_t T_Depth> template <std::size_t N_Depth>
static inline QData VL_PACK_QI(int obits, int lbits, const VlUnpacked<SData, T_Depth>& q) { static inline QData VL_PACK_QI(int obits, int lbits, const VlUnpacked<SData, N_Depth>& q) {
QData ret = 0; QData ret = 0;
for (size_t i = 0; i < T_Depth; ++i) for (size_t i = 0; i < N_Depth; ++i)
ret |= static_cast<QData>(q[T_Depth - 1 - i]) << (i * lbits); ret |= static_cast<QData>(q[N_Depth - 1 - i]) << (i * lbits);
return ret; return ret;
} }
template <std::size_t T_Depth> template <std::size_t N_Depth>
static inline QData VL_PACK_QI(int obits, int lbits, const VlUnpacked<IData, T_Depth>& q) { static inline QData VL_PACK_QI(int obits, int lbits, const VlUnpacked<IData, N_Depth>& q) {
QData ret = 0; QData ret = 0;
for (size_t i = 0; i < T_Depth; ++i) for (size_t i = 0; i < N_Depth; ++i)
ret |= static_cast<QData>(q[T_Depth - 1 - i]) << (i * lbits); ret |= static_cast<QData>(q[N_Depth - 1 - i]) << (i * lbits);
return ret; return ret;
} }
@ -1675,10 +1675,10 @@ static inline QData VL_PACK_QQ(int obits, int lbits, const VlQueue<QData>& q) {
return ret; return ret;
} }
template <std::size_t T_Depth> template <std::size_t N_Depth>
static inline QData VL_PACK_QQ(int obits, int lbits, const VlUnpacked<QData, T_Depth>& q) { static inline QData VL_PACK_QQ(int obits, int lbits, const VlUnpacked<QData, N_Depth>& q) {
QData ret = 0; QData ret = 0;
for (size_t i = 0; i < T_Depth; ++i) ret |= q[T_Depth - 1 - i] << (i * lbits); for (size_t i = 0; i < N_Depth; ++i) ret |= q[N_Depth - 1 - i] << (i * lbits);
return ret; return ret;
} }
@ -1703,30 +1703,30 @@ static inline WDataOutP VL_PACK_WI(int obits, int lbits, WDataOutP owp, const Vl
return owp; return owp;
} }
template <std::size_t T_Depth> template <std::size_t N_Depth>
static inline WDataOutP VL_PACK_WI(int obits, int lbits, WDataOutP owp, static inline WDataOutP VL_PACK_WI(int obits, int lbits, WDataOutP owp,
const VlUnpacked<CData, T_Depth>& q) { const VlUnpacked<CData, N_Depth>& q) {
VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1); VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1);
for (size_t i = 0; i < T_Depth; ++i) for (size_t i = 0; i < N_Depth; ++i)
_vl_insert_WI(owp, q[T_Depth - 1 - i], i * lbits + lbits - 1, i * lbits); _vl_insert_WI(owp, q[N_Depth - 1 - i], i * lbits + lbits - 1, i * lbits);
return owp; return owp;
} }
template <std::size_t T_Depth> template <std::size_t N_Depth>
static inline WDataOutP VL_PACK_WI(int obits, int lbits, WDataOutP owp, static inline WDataOutP VL_PACK_WI(int obits, int lbits, WDataOutP owp,
const VlUnpacked<SData, T_Depth>& q) { const VlUnpacked<SData, N_Depth>& q) {
VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1); VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1);
for (size_t i = 0; i < T_Depth; ++i) for (size_t i = 0; i < N_Depth; ++i)
_vl_insert_WI(owp, q[T_Depth - 1 - i], i * lbits + lbits - 1, i * lbits); _vl_insert_WI(owp, q[N_Depth - 1 - i], i * lbits + lbits - 1, i * lbits);
return owp; return owp;
} }
template <std::size_t T_Depth> template <std::size_t N_Depth>
static inline WDataOutP VL_PACK_WI(int obits, int lbits, WDataOutP owp, static inline WDataOutP VL_PACK_WI(int obits, int lbits, WDataOutP owp,
const VlUnpacked<IData, T_Depth>& q) { const VlUnpacked<IData, N_Depth>& q) {
VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1); VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1);
for (size_t i = 0; i < T_Depth; ++i) for (size_t i = 0; i < N_Depth; ++i)
_vl_insert_WI(owp, q[T_Depth - 1 - i], i * lbits + lbits - 1, i * lbits); _vl_insert_WI(owp, q[N_Depth - 1 - i], i * lbits + lbits - 1, i * lbits);
return owp; return owp;
} }
@ -1737,30 +1737,30 @@ static inline WDataOutP VL_PACK_WQ(int obits, int lbits, WDataOutP owp, const Vl
return owp; return owp;
} }
template <std::size_t T_Depth> template <std::size_t N_Depth>
static inline WDataOutP VL_PACK_WQ(int obits, int lbits, WDataOutP owp, static inline WDataOutP VL_PACK_WQ(int obits, int lbits, WDataOutP owp,
const VlUnpacked<QData, T_Depth>& q) { const VlUnpacked<QData, N_Depth>& q) {
VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1); VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1);
for (size_t i = 0; i < T_Depth; ++i) for (size_t i = 0; i < N_Depth; ++i)
_vl_insert_WQ(owp, q[T_Depth - 1 - i], i * lbits + lbits - 1, i * lbits); _vl_insert_WQ(owp, q[N_Depth - 1 - i], i * lbits + lbits - 1, i * lbits);
return owp; return owp;
} }
template <std::size_t N> template <std::size_t N_Words>
static inline WDataOutP VL_PACK_WW(int obits, int lbits, WDataOutP owp, static inline WDataOutP VL_PACK_WW(int obits, int lbits, WDataOutP owp,
const VlQueue<VlWide<N>>& q) { const VlQueue<VlWide<N_Words>>& q) {
VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1); VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1);
for (size_t i = 0; i < q.size(); ++i) for (size_t i = 0; i < q.size(); ++i)
_vl_insert_WW(owp, q.at(i), i * lbits + lbits - 1, i * lbits); _vl_insert_WW(owp, q.at(i), i * lbits + lbits - 1, i * lbits);
return owp; return owp;
} }
template <std::size_t T_Depth, std::size_t N> template <std::size_t N_Depth, std::size_t N_Words>
static inline WDataOutP VL_PACK_WW(int obits, int lbits, WDataOutP owp, static inline WDataOutP VL_PACK_WW(int obits, int lbits, WDataOutP owp,
const VlUnpacked<VlWide<N>, T_Depth>& q) { const VlUnpacked<VlWide<N_Words>, N_Depth>& q) {
VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1); VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1);
for (size_t i = 0; i < T_Depth; ++i) for (size_t i = 0; i < N_Depth; ++i)
_vl_insert_WW(owp, q[T_Depth - 1 - i], i * lbits + lbits - 1, i * lbits); _vl_insert_WW(owp, q[N_Depth - 1 - i], i * lbits + lbits - 1, i * lbits);
return owp; return owp;
} }
@ -2288,8 +2288,8 @@ static inline void VL_UNPACK_QW(int lbits, int rbits, VlQueue<QData>& q, WDataIn
} }
} }
template <std::size_t N> template <std::size_t N_Words>
static inline void VL_UNPACK_WW(int lbits, int rbits, VlQueue<VlWide<N>>& q, WDataInP rwp) { static inline void VL_UNPACK_WW(int lbits, int rbits, VlQueue<VlWide<N_Words>>& q, WDataInP rwp) {
const int size = (rbits + lbits - 1) / lbits; const int size = (rbits + lbits - 1) / lbits;
q.renew(size); q.renew(size);
for (size_t i = 0; i < size; ++i) { for (size_t i = 0; i < size; ++i) {
@ -2297,85 +2297,85 @@ static inline void VL_UNPACK_WW(int lbits, int rbits, VlQueue<VlWide<N>>& q, WDa
} }
} }
template <std::size_t T_Depth> template <std::size_t N_Depth>
static inline void VL_UNPACK_II(int lbits, int rbits, VlUnpacked<CData, T_Depth>& q, IData from) { static inline void VL_UNPACK_II(int lbits, int rbits, VlUnpacked<CData, N_Depth>& q, IData from) {
const IData mask = VL_MASK_I(lbits); const IData mask = VL_MASK_I(lbits);
for (size_t i = 0; i < T_Depth; ++i) q[i] = (from >> ((T_Depth - 1 - i) * lbits)) & mask; for (size_t i = 0; i < N_Depth; ++i) q[i] = (from >> ((N_Depth - 1 - i) * lbits)) & mask;
} }
template <std::size_t T_Depth> template <std::size_t N_Depth>
static inline void VL_UNPACK_II(int lbits, int rbits, VlUnpacked<SData, T_Depth>& q, IData from) { static inline void VL_UNPACK_II(int lbits, int rbits, VlUnpacked<SData, N_Depth>& q, IData from) {
const IData mask = VL_MASK_I(lbits); const IData mask = VL_MASK_I(lbits);
for (size_t i = 0; i < T_Depth; ++i) q[i] = (from >> ((T_Depth - 1 - i) * lbits)) & mask; for (size_t i = 0; i < N_Depth; ++i) q[i] = (from >> ((N_Depth - 1 - i) * lbits)) & mask;
} }
template <std::size_t T_Depth> template <std::size_t N_Depth>
static inline void VL_UNPACK_II(int lbits, int rbits, VlUnpacked<IData, T_Depth>& q, IData from) { static inline void VL_UNPACK_II(int lbits, int rbits, VlUnpacked<IData, N_Depth>& q, IData from) {
const IData mask = VL_MASK_I(lbits); const IData mask = VL_MASK_I(lbits);
for (size_t i = 0; i < T_Depth; ++i) q[i] = (from >> ((T_Depth - 1 - i) * lbits)) & mask; for (size_t i = 0; i < N_Depth; ++i) q[i] = (from >> ((N_Depth - 1 - i) * lbits)) & mask;
} }
template <std::size_t T_Depth> template <std::size_t N_Depth>
static inline void VL_UNPACK_IQ(int lbits, int rbits, VlUnpacked<CData, T_Depth>& q, QData from) { static inline void VL_UNPACK_IQ(int lbits, int rbits, VlUnpacked<CData, N_Depth>& q, QData from) {
const IData mask = VL_MASK_I(lbits); const IData mask = VL_MASK_I(lbits);
for (size_t i = 0; i < T_Depth; ++i) q[i] = (from >> ((T_Depth - 1 - i) * lbits)) & mask; for (size_t i = 0; i < N_Depth; ++i) q[i] = (from >> ((N_Depth - 1 - i) * lbits)) & mask;
} }
template <std::size_t T_Depth> template <std::size_t N_Depth>
static inline void VL_UNPACK_IQ(int lbits, int rbits, VlUnpacked<SData, T_Depth>& q, QData from) { static inline void VL_UNPACK_IQ(int lbits, int rbits, VlUnpacked<SData, N_Depth>& q, QData from) {
const IData mask = VL_MASK_I(lbits); const IData mask = VL_MASK_I(lbits);
for (size_t i = 0; i < T_Depth; ++i) q[i] = (from >> ((T_Depth - 1 - i) * lbits)) & mask; for (size_t i = 0; i < N_Depth; ++i) q[i] = (from >> ((N_Depth - 1 - i) * lbits)) & mask;
} }
template <std::size_t T_Depth> template <std::size_t N_Depth>
static inline void VL_UNPACK_IQ(int lbits, int rbits, VlUnpacked<IData, T_Depth>& q, QData from) { static inline void VL_UNPACK_IQ(int lbits, int rbits, VlUnpacked<IData, N_Depth>& q, QData from) {
const IData mask = VL_MASK_I(lbits); const IData mask = VL_MASK_I(lbits);
for (size_t i = 0; i < T_Depth; ++i) q[i] = (from >> ((T_Depth - 1 - i) * lbits)) & mask; for (size_t i = 0; i < N_Depth; ++i) q[i] = (from >> ((N_Depth - 1 - i) * lbits)) & mask;
} }
template <std::size_t T_Depth> template <std::size_t N_Depth>
static inline void VL_UNPACK_QQ(int lbits, int rbits, VlUnpacked<QData, T_Depth>& q, QData from) { static inline void VL_UNPACK_QQ(int lbits, int rbits, VlUnpacked<QData, N_Depth>& q, QData from) {
const QData mask = VL_MASK_Q(lbits); const QData mask = VL_MASK_Q(lbits);
for (size_t i = 0; i < T_Depth; ++i) q[i] = (from >> ((T_Depth - 1 - i) * lbits)) & mask; for (size_t i = 0; i < N_Depth; ++i) q[i] = (from >> ((N_Depth - 1 - i) * lbits)) & mask;
} }
template <std::size_t T_Depth> template <std::size_t N_Depth>
static inline void VL_UNPACK_IW(int lbits, int rbits, VlUnpacked<CData, T_Depth>& q, static inline void VL_UNPACK_IW(int lbits, int rbits, VlUnpacked<CData, N_Depth>& q,
WDataInP rwp) { WDataInP rwp) {
const IData mask = VL_MASK_I(lbits); const IData mask = VL_MASK_I(lbits);
for (size_t i = 0; i < T_Depth; ++i) for (size_t i = 0; i < N_Depth; ++i)
q[i] = VL_SEL_IWII(rbits, rwp, (T_Depth - 1 - i) * lbits, lbits) & mask; q[i] = VL_SEL_IWII(rbits, rwp, (N_Depth - 1 - i) * lbits, lbits) & mask;
} }
template <std::size_t T_Depth> template <std::size_t N_Depth>
static inline void VL_UNPACK_IW(int lbits, int rbits, VlUnpacked<SData, T_Depth>& q, static inline void VL_UNPACK_IW(int lbits, int rbits, VlUnpacked<SData, N_Depth>& q,
WDataInP rwp) { WDataInP rwp) {
const IData mask = VL_MASK_I(lbits); const IData mask = VL_MASK_I(lbits);
for (size_t i = 0; i < T_Depth; ++i) for (size_t i = 0; i < N_Depth; ++i)
q[i] = VL_SEL_IWII(rbits, rwp, (T_Depth - 1 - i) * lbits, lbits) & mask; q[i] = VL_SEL_IWII(rbits, rwp, (N_Depth - 1 - i) * lbits, lbits) & mask;
} }
template <std::size_t T_Depth> template <std::size_t N_Depth>
static inline void VL_UNPACK_IW(int lbits, int rbits, VlUnpacked<IData, T_Depth>& q, static inline void VL_UNPACK_IW(int lbits, int rbits, VlUnpacked<IData, N_Depth>& q,
WDataInP rwp) { WDataInP rwp) {
const IData mask = VL_MASK_I(lbits); const IData mask = VL_MASK_I(lbits);
for (size_t i = 0; i < T_Depth; ++i) for (size_t i = 0; i < N_Depth; ++i)
q[i] = VL_SEL_IWII(rbits, rwp, (T_Depth - 1 - i) * lbits, lbits) & mask; q[i] = VL_SEL_IWII(rbits, rwp, (N_Depth - 1 - i) * lbits, lbits) & mask;
} }
template <std::size_t T_Depth> template <std::size_t N_Depth>
static inline void VL_UNPACK_QW(int lbits, int rbits, VlUnpacked<QData, T_Depth>& q, static inline void VL_UNPACK_QW(int lbits, int rbits, VlUnpacked<QData, N_Depth>& q,
WDataInP rwp) { WDataInP rwp) {
const QData mask = VL_MASK_Q(lbits); const QData mask = VL_MASK_Q(lbits);
for (size_t i = 0; i < T_Depth; ++i) for (size_t i = 0; i < N_Depth; ++i)
q[i] = VL_SEL_QWII(rbits, rwp, (T_Depth - 1 - i) * lbits, lbits) & mask; q[i] = VL_SEL_QWII(rbits, rwp, (N_Depth - 1 - i) * lbits, lbits) & mask;
} }
template <std::size_t T_Depth, std::size_t N> template <std::size_t N_Depth, std::size_t N_Words>
static inline void VL_UNPACK_WW(int lbits, int rbits, VlUnpacked<VlWide<N>, T_Depth>& q, static inline void VL_UNPACK_WW(int lbits, int rbits, VlUnpacked<VlWide<N_Words>, N_Depth>& q,
WDataInP rwp) { WDataInP rwp) {
for (size_t i = 0; i < T_Depth; ++i) for (size_t i = 0; i < N_Depth; ++i)
VL_SEL_WWII(lbits, rbits, q[i], rwp, (T_Depth - 1 - i) * lbits, lbits); VL_SEL_WWII(lbits, rbits, q[i], rwp, (N_Depth - 1 - i) * lbits, lbits);
} }
// Return QData from double (numeric) // Return QData from double (numeric)

View File

@ -198,7 +198,7 @@ public:
//============================================================================= //=============================================================================
// VlPgoProfiler is for collecting profiling data for PGO // VlPgoProfiler is for collecting profiling data for PGO
template <std::size_t T_Entries> template <std::size_t N_Entries>
class VlPgoProfiler final { class VlPgoProfiler final {
// TYPES // TYPES
struct Record final { struct Record final {
@ -207,7 +207,7 @@ class VlPgoProfiler final {
}; };
// Counters are stored packed, all together to reduce cache effects // Counters are stored packed, all together to reduce cache effects
std::array<uint64_t, T_Entries> m_counters; // Time spent on this record std::array<uint64_t, N_Entries> m_counters; // Time spent on this record
std::vector<Record> m_records; // Record information std::vector<Record> m_records; // Record information
public: public:
@ -216,7 +216,7 @@ public:
~VlPgoProfiler() = default; ~VlPgoProfiler() = default;
void write(const char* modelp, const std::string& filename) VL_MT_SAFE; void write(const char* modelp, const std::string& filename) VL_MT_SAFE;
void addCounter(size_t counter, const std::string& name) { void addCounter(size_t counter, const std::string& name) {
VL_DEBUG_IF(assert(counter < T_Entries);); VL_DEBUG_IF(assert(counter < N_Entries););
m_records.emplace_back(Record{name, counter}); m_records.emplace_back(Record{name, counter});
} }
void startCounter(size_t counter) { void startCounter(size_t counter) {
@ -227,8 +227,8 @@ public:
void stopCounter(size_t counter) { m_counters[counter] += VL_CPU_TICK(); } void stopCounter(size_t counter) { m_counters[counter] += VL_CPU_TICK(); }
}; };
template <std::size_t T_Entries> template <std::size_t N_Entries>
void VlPgoProfiler<T_Entries>::write(const char* modelp, const std::string& filename) VL_MT_SAFE { void VlPgoProfiler<N_Entries>::write(const char* modelp, const std::string& filename) VL_MT_SAFE {
static VerilatedMutex s_mutex; static VerilatedMutex s_mutex;
const VerilatedLockGuard lock{s_mutex}; const VerilatedLockGuard lock{s_mutex};

View File

@ -250,11 +250,11 @@ public:
record_arr_table(var, name, dimension, {}); record_arr_table(var, name, dimension, {});
} }
} }
template <typename T, std::size_t N> template <typename T, std::size_t N_Depth>
void write_var(VlUnpacked<T, N>& var, int width, const char* name, int dimension, void write_var(VlUnpacked<T, N_Depth>& var, int width, const char* name, int dimension,
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) { std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
if (m_vars.find(name) != m_vars.end()) return; if (m_vars.find(name) != m_vars.end()) return;
m_vars[name] = std::make_shared<const VlRandomArrayVar<VlUnpacked<T, N>>>( m_vars[name] = std::make_shared<const VlRandomArrayVar<VlUnpacked<T, N_Depth>>>(
name, width, &var, dimension, randmodeIdx); name, width, &var, dimension, randmodeIdx);
if (dimension > 0) { if (dimension > 0) {
idx = 0; idx = 0;
@ -295,11 +295,11 @@ public:
++idx; ++idx;
} }
} }
template <typename T, std::size_t N> template <typename T, std::size_t N_Depth>
void record_arr_table(VlUnpacked<T, N>& var, const std::string name, int dimension, void record_arr_table(VlUnpacked<T, N_Depth>& var, const std::string name, int dimension,
std::vector<size_t> indices) { std::vector<size_t> indices) {
if ((dimension > 0) && (N != 0)) { if ((dimension > 0) && (N_Depth != 0)) {
for (size_t i = 0; i < N; ++i) { for (size_t i = 0; i < N_Depth; ++i) {
const std::string indexed_name = name + "[" + std::to_string(i) + "]"; const std::string indexed_name = name + "[" + std::to_string(i) + "]";
indices.push_back(i); indices.push_back(i);
record_arr_table(var.operator[](i), indexed_name, dimension - 1, indices); record_arr_table(var.operator[](i), indexed_name, dimension - 1, indices);

View File

@ -161,10 +161,10 @@ public:
~VlWorkerThread(); ~VlWorkerThread();
// METHODS // METHODS
template <bool SpinWait> template <bool N_SpinWait>
void dequeWork(ExecRec* workp) VL_MT_SAFE_EXCLUDES(m_mutex) { void dequeWork(ExecRec* workp) VL_MT_SAFE_EXCLUDES(m_mutex) {
// Spin for a while, waiting for new data // Spin for a while, waiting for new data
if VL_CONSTEXPR_CXX17 (SpinWait) { if VL_CONSTEXPR_CXX17 (N_SpinWait) {
for (unsigned i = 0; i < VL_LOCK_SPINS; ++i) { for (unsigned i = 0; i < VL_LOCK_SPINS; ++i) {
if (VL_LIKELY(m_ready_size.load(std::memory_order_relaxed))) break; if (VL_LIKELY(m_ready_size.load(std::memory_order_relaxed))) break;
VL_CPU_RELAX(); VL_CPU_RELAX();

View File

@ -164,12 +164,12 @@ inline std::string VL_TO_STRING(const VlProcessRef& p) { return std::string("pro
//=================================================================== //===================================================================
// Activity trigger vector // Activity trigger vector
template <std::size_t T_size> // template <std::size_t N_Size> //
class VlTriggerVec final { class VlTriggerVec final {
// TODO: static assert T_size > 0, and don't generate when empty // TODO: static assert N_Size > 0, and don't generate when empty
// MEMBERS // MEMBERS
alignas(16) std::array<uint64_t, roundUpToMultipleOf<64>(T_size) / 64> m_flags; // The flags alignas(16) std::array<uint64_t, roundUpToMultipleOf<64>(N_Size) / 64> m_flags; // The flags
public: public:
// CONSTRUCTOR // CONSTRUCTOR
@ -200,12 +200,12 @@ public:
} }
// Set all elements true in 'this' that are set in 'other' // Set all elements true in 'this' that are set in 'other'
void thisOr(const VlTriggerVec<T_size>& other) { void thisOr(const VlTriggerVec<N_Size>& other) {
for (size_t i = 0; i < m_flags.size(); ++i) m_flags[i] |= other.m_flags[i]; for (size_t i = 0; i < m_flags.size(); ++i) m_flags[i] |= other.m_flags[i];
} }
// Set elements of 'this' to 'a & !b' element-wise // Set elements of 'this' to 'a & !b' element-wise
void andNot(const VlTriggerVec<T_size>& a, const VlTriggerVec<T_size>& b) { void andNot(const VlTriggerVec<N_Size>& a, const VlTriggerVec<N_Size>& b) {
for (size_t i = 0; i < m_flags.size(); ++i) m_flags[i] = a.m_flags[i] & ~b.m_flags[i]; for (size_t i = 0; i < m_flags.size(); ++i) m_flags[i] = a.m_flags[i] & ~b.m_flags[i];
} }
}; };
@ -309,7 +309,7 @@ public:
size_t operator()() { return VL_MASK_I(31) & vl_rand64(); } size_t operator()() { return VL_MASK_I(31) & vl_rand64(); }
}; };
template <typename T_Value, uint64_t T_numValues> template <typename T_Value, uint64_t N_NumValues>
class VlRandC final { class VlRandC final {
T_Value m_remaining = 0; // Number of values to pull before re-randomize T_Value m_remaining = 0; // Number of values to pull before re-randomize
T_Value m_lfsr = 1; // LFSR state T_Value m_lfsr = 1; // LFSR state
@ -317,8 +317,8 @@ class VlRandC final {
public: public:
// CONSTRUCTORS // CONSTRUCTORS
VlRandC() { VlRandC() {
static_assert(T_numValues >= 1, ""); static_assert(N_NumValues >= 1, "");
static_assert(sizeof(T_Value) == 8 || (T_numValues < (1ULL << (8 * sizeof(T_Value)))), ""); static_assert(sizeof(T_Value) == 8 || (N_NumValues < (1ULL << (8 * sizeof(T_Value)))), "");
} }
// METHODS // METHODS
T_Value randomize(VlRNG& rngr) { T_Value randomize(VlRNG& rngr) {
@ -337,23 +337,23 @@ public:
0x80000057ULL, // 32 0x80000057ULL, // 32
0x100000029ULL // 33 0x100000029ULL // 33
}; };
constexpr uint32_t clogWidth = VL_CLOG2_CE_Q(T_numValues) + 1; constexpr uint32_t clogWidth = VL_CLOG2_CE_Q(N_NumValues) + 1;
constexpr uint32_t lfsrWidth = (clogWidth < 2) ? 2 : clogWidth; constexpr uint32_t lfsrWidth = (clogWidth < 2) ? 2 : clogWidth;
constexpr T_Value polynomial = static_cast<T_Value>(s_polynomials[lfsrWidth]); constexpr T_Value polynomial = static_cast<T_Value>(s_polynomials[lfsrWidth]);
// printf(" numV=%ld w=%d poly=%x\n", T_numValues, lfsrWidth, polynomial); // printf(" numV=%ld w=%d poly=%x\n", N_NumValues, lfsrWidth, polynomial);
// Loop until get reasonable value. Because we picked a LFSR of at most one // Loop until get reasonable value. Because we picked a LFSR of at most one
// extra bit in width, this will only require at most on average 1.5 loops // extra bit in width, this will only require at most on average 1.5 loops
do { do {
m_lfsr = (m_lfsr & 1ULL) ? ((m_lfsr >> 1ULL) ^ polynomial) : (m_lfsr >> 1ULL); m_lfsr = (m_lfsr & 1ULL) ? ((m_lfsr >> 1ULL) ^ polynomial) : (m_lfsr >> 1ULL);
} while (m_lfsr > T_numValues); // Note if == then output value 0 } while (m_lfsr > N_NumValues); // Note if == then output value 0
--m_remaining; --m_remaining;
T_Value result = (m_lfsr == T_numValues) ? 0 : m_lfsr; T_Value result = (m_lfsr == N_NumValues) ? 0 : m_lfsr;
// printf(" result=%x (numv=%ld, rem=%d)\n", result, T_numValues, m_remaining); // printf(" result=%x (numv=%ld, rem=%d)\n", result, N_NumValues, m_remaining);
return result; return result;
} }
void reseed(VlRNG& rngr) { void reseed(VlRNG& rngr) {
constexpr uint32_t lfsrWidth = VL_CLOG2_CE_Q(T_numValues) + 1; constexpr uint32_t lfsrWidth = VL_CLOG2_CE_Q(N_NumValues) + 1;
m_remaining = T_numValues; m_remaining = N_NumValues;
do { do {
m_lfsr = rngr.rand64() & VL_MASK_Q(lfsrWidth); m_lfsr = rngr.rand64() & VL_MASK_Q(lfsrWidth);
// printf(" lfsr.reseed=%x\n", m_lfsr); // printf(" lfsr.reseed=%x\n", m_lfsr);
@ -414,23 +414,23 @@ public:
static int _vl_cmp_w(int words, WDataInP const lwp, WDataInP const rwp) VL_PURE; static int _vl_cmp_w(int words, WDataInP const lwp, WDataInP const rwp) VL_PURE;
template <std::size_t T_Words> template <std::size_t N_Words>
struct VlWide; struct VlWide;
// Type trait to check if a type is VlWide // Type trait to check if a type is VlWide
template <typename> template <typename>
struct VlIsVlWide : public std::false_type {}; struct VlIsVlWide : public std::false_type {};
template <std::size_t T_Words> template <std::size_t N_Words>
struct VlIsVlWide<VlWide<T_Words>> : public std::true_type {}; struct VlIsVlWide<VlWide<N_Words>> : public std::true_type {};
template <std::size_t T_Words> template <std::size_t N_Words>
struct VlWide final { struct VlWide final {
static constexpr size_t Words = T_Words; static constexpr size_t Words = N_Words;
// MEMBERS // MEMBERS
// This should be the only data member, otherwise generated static initializers need updating // This should be the only data member, otherwise generated static initializers need updating
EData m_storage[T_Words]; // Contents of the packed array EData m_storage[N_Words]; // Contents of the packed array
// CONSTRUCTORS // CONSTRUCTORS
// Default constructors and destructor are used. Note however that C++20 requires that // Default constructors and destructor are used. Note however that C++20 requires that
@ -441,8 +441,8 @@ struct VlWide final {
// Default copy assignment operators are used. // Default copy assignment operators are used.
operator WDataOutP() VL_PURE { return &m_storage[0]; } // This also allows [] operator WDataOutP() VL_PURE { return &m_storage[0]; } // This also allows []
operator WDataInP() const VL_PURE { return &m_storage[0]; } // This also allows [] operator WDataInP() const VL_PURE { return &m_storage[0]; } // This also allows []
bool operator!=(const VlWide<T_Words>& that) const VL_PURE { bool operator!=(const VlWide<N_Words>& that) const VL_PURE {
for (size_t i = 0; i < T_Words; ++i) { for (size_t i = 0; i < N_Words; ++i) {
if (m_storage[i] != that.m_storage[i]) return true; if (m_storage[i] != that.m_storage[i]) return true;
} }
return false; return false;
@ -453,21 +453,21 @@ struct VlWide final {
EData& at(size_t index) { return m_storage[index]; } EData& at(size_t index) { return m_storage[index]; }
WData* data() { return &m_storage[0]; } WData* data() { return &m_storage[0]; }
const WData* data() const { return &m_storage[0]; } const WData* data() const { return &m_storage[0]; }
bool operator<(const VlWide<T_Words>& rhs) const { bool operator<(const VlWide<N_Words>& rhs) const {
return _vl_cmp_w(T_Words, data(), rhs.data()) < 0; return _vl_cmp_w(N_Words, data(), rhs.data()) < 0;
} }
}; };
// Convert a C array to std::array reference by pointer magic, without copy. // Convert a C array to std::array reference by pointer magic, without copy.
// Data type (second argument) is so the function template can automatically generate. // Data type (second argument) is so the function template can automatically generate.
template <std::size_t T_Words> template <std::size_t N_Words>
VlWide<T_Words>& VL_CVT_W_A(const WDataInP inp, const VlWide<T_Words>&) { VlWide<N_Words>& VL_CVT_W_A(const WDataInP inp, const VlWide<N_Words>&) {
return *((VlWide<T_Words>*)inp); return *((VlWide<N_Words>*)inp);
} }
template <std::size_t T_Words> template <std::size_t N_Words>
std::string VL_TO_STRING(const VlWide<T_Words>& obj) { std::string VL_TO_STRING(const VlWide<N_Words>& obj) {
return VL_TO_STRING_W(T_Words, obj.data()); return VL_TO_STRING_W(N_Words, obj.data());
} }
//=================================================================== //===================================================================
@ -477,7 +477,7 @@ std::string VL_TO_STRING(const VlWide<T_Words>& obj) {
// //
// Bound here is the maximum size() allowed, e.g. 1 + SystemVerilog bound // Bound here is the maximum size() allowed, e.g. 1 + SystemVerilog bound
// For dynamic arrays it is always zero // For dynamic arrays it is always zero
template <typename T_Value, size_t T_MaxSize = 0> template <typename T_Value, size_t N_MaxSize = 0>
class VlQueue final { class VlQueue final {
private: private:
// TYPES // TYPES
@ -485,8 +485,8 @@ private:
public: public:
using const_iterator = typename Deque::const_iterator; using const_iterator = typename Deque::const_iterator;
template <typename Func> template <typename T_Func>
using WithFuncReturnType = decltype(std::declval<Func>()(0, std::declval<T_Value>())); using WithFuncReturnType = decltype(std::declval<T_Func>()(0, std::declval<T_Value>()));
private: private:
// MEMBERS // MEMBERS
@ -506,11 +506,11 @@ public:
bool operator!=(const VlQueue& rhs) const { return m_deque != rhs.m_deque; } bool operator!=(const VlQueue& rhs) const { return m_deque != rhs.m_deque; }
// Standard copy constructor works. Verilog: assoca = assocb // Standard copy constructor works. Verilog: assoca = assocb
// Also must allow conversion from a different T_MaxSize queue // Also must allow conversion from a different N_MaxSize queue
template <size_t U_MaxSize = 0> template <size_t N_RhsMaxSize = 0>
VlQueue operator=(const VlQueue<T_Value, U_MaxSize>& rhs) { VlQueue operator=(const VlQueue<T_Value, N_RhsMaxSize>& rhs) {
m_deque = rhs.privateDeque(); m_deque = rhs.privateDeque();
if (VL_UNLIKELY(T_MaxSize && T_MaxSize < m_deque.size())) m_deque.resize(T_MaxSize - 1); if (VL_UNLIKELY(N_MaxSize && N_MaxSize < m_deque.size())) m_deque.resize(N_MaxSize - 1);
return *this; return *this;
} }
@ -562,7 +562,7 @@ public:
m_deque.resize(size, atDefault()); m_deque.resize(size, atDefault());
} }
// Dynamic array new[]() becomes a renew_copy() // Dynamic array new[]() becomes a renew_copy()
void renew_copy(size_t size, const VlQueue<T_Value, T_MaxSize>& rhs) { void renew_copy(size_t size, const VlQueue<T_Value, N_MaxSize>& rhs) {
if (size == 0) { if (size == 0) {
clear(); clear();
} else { } else {
@ -575,11 +575,11 @@ public:
// function void q.push_front(value) // function void q.push_front(value)
void push_front(const T_Value& value) { void push_front(const T_Value& value) {
m_deque.push_front(value); m_deque.push_front(value);
if (VL_UNLIKELY(T_MaxSize != 0 && m_deque.size() > T_MaxSize)) m_deque.pop_back(); if (VL_UNLIKELY(N_MaxSize != 0 && m_deque.size() > N_MaxSize)) m_deque.pop_back();
} }
// function void q.push_back(value) // function void q.push_back(value)
void push_back(const T_Value& value) { void push_back(const T_Value& value) {
if (VL_LIKELY(T_MaxSize == 0 || m_deque.size() < T_MaxSize)) m_deque.push_back(value); if (VL_LIKELY(N_MaxSize == 0 || m_deque.size() < N_MaxSize)) m_deque.push_back(value);
} }
// function value_t q.pop_front(); // function value_t q.pop_front();
T_Value pop_front() { T_Value pop_front() {
@ -600,7 +600,7 @@ public:
T_Value& atWrite(int32_t index) { T_Value& atWrite(int32_t index) {
// cppcheck-suppress variableScope // cppcheck-suppress variableScope
static thread_local T_Value t_throwAway; static thread_local T_Value t_throwAway;
// Needs to work for dynamic arrays, so does not use T_MaxSize // Needs to work for dynamic arrays, so does not use N_MaxSize
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) { if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) {
t_throwAway = atDefault(); t_throwAway = atDefault();
return t_throwAway; return t_throwAway;
@ -621,7 +621,7 @@ public:
} }
// Accessing. Verilog: v = assoc[index] // Accessing. Verilog: v = assoc[index]
const T_Value& at(int32_t index) const { const T_Value& at(int32_t index) const {
// Needs to work for dynamic arrays, so does not use T_MaxSize // Needs to work for dynamic arrays, so does not use N_MaxSize
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) { if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) {
return atDefault(); return atDefault();
} else { } else {
@ -665,8 +665,8 @@ public:
// Methods // Methods
void sort() { std::sort(m_deque.begin(), m_deque.end()); } void sort() { std::sort(m_deque.begin(), m_deque.end()); }
template <typename Func> template <typename T_Func>
void sort(Func with_func) { void sort(T_Func with_func) {
// with_func returns arbitrary type to use for the sort comparison // with_func returns arbitrary type to use for the sort comparison
std::sort(m_deque.begin(), m_deque.end(), [=](const T_Value& a, const T_Value& b) { std::sort(m_deque.begin(), m_deque.end(), [=](const T_Value& a, const T_Value& b) {
// index number is meaningless with sort, as it changes // index number is meaningless with sort, as it changes
@ -674,8 +674,8 @@ public:
}); });
} }
void rsort() { std::sort(m_deque.rbegin(), m_deque.rend()); } void rsort() { std::sort(m_deque.rbegin(), m_deque.rend()); }
template <typename Func> template <typename T_Func>
void rsort(Func with_func) { void rsort(T_Func with_func) {
// with_func returns arbitrary type to use for the sort comparison // with_func returns arbitrary type to use for the sort comparison
std::sort(m_deque.rbegin(), m_deque.rend(), [=](const T_Value& a, const T_Value& b) { std::sort(m_deque.rbegin(), m_deque.rend(), [=](const T_Value& a, const T_Value& b) {
// index number is meaningless with sort, as it changes // index number is meaningless with sort, as it changes
@ -696,8 +696,8 @@ public:
} }
return out; return out;
} }
template <typename Func> template <typename T_Func>
VlQueue unique(Func with_func) const { VlQueue unique(T_Func with_func) const {
VlQueue out; VlQueue out;
std::set<decltype(with_func(0, m_deque[0]))> saw; std::set<decltype(with_func(0, m_deque[0]))> saw;
for (const auto& i : m_deque) { for (const auto& i : m_deque) {
@ -724,8 +724,8 @@ public:
} }
return out; return out;
} }
template <typename Func> template <typename T_Func>
VlQueue<IData> unique_index(Func with_func) const { VlQueue<IData> unique_index(T_Func with_func) const {
VlQueue<IData> out; VlQueue<IData> out;
IData index = 0; IData index = 0;
std::set<decltype(with_func(0, m_deque[0]))> saw; std::set<decltype(with_func(0, m_deque[0]))> saw;
@ -740,8 +740,8 @@ public:
} }
return out; return out;
} }
template <typename Func> template <typename T_Func>
VlQueue find(Func with_func) const { VlQueue find(T_Func with_func) const {
VlQueue out; VlQueue out;
IData index = 0; IData index = 0;
for (const auto& i : m_deque) { for (const auto& i : m_deque) {
@ -750,8 +750,8 @@ public:
} }
return out; return out;
} }
template <typename Func> template <typename T_Func>
VlQueue<IData> find_index(Func with_func) const { VlQueue<IData> find_index(T_Func with_func) const {
VlQueue<IData> out; VlQueue<IData> out;
IData index = 0; IData index = 0;
for (const auto& i : m_deque) { for (const auto& i : m_deque) {
@ -760,8 +760,8 @@ public:
} }
return out; return out;
} }
template <typename Func> template <typename T_Func>
VlQueue find_first(Func with_func) const { VlQueue find_first(T_Func with_func) const {
// Can't use std::find_if as need index number // Can't use std::find_if as need index number
IData index = 0; IData index = 0;
for (const auto& i : m_deque) { for (const auto& i : m_deque) {
@ -770,8 +770,8 @@ public:
} }
return VlQueue{}; return VlQueue{};
} }
template <typename Func> template <typename T_Func>
VlQueue<IData> find_first_index(Func with_func) const { VlQueue<IData> find_first_index(T_Func with_func) const {
IData index = 0; IData index = 0;
for (const auto& i : m_deque) { for (const auto& i : m_deque) {
if (with_func(index, i)) return VlQueue<IData>::consV(index); if (with_func(index, i)) return VlQueue<IData>::consV(index);
@ -779,8 +779,8 @@ public:
} }
return VlQueue<IData>{}; return VlQueue<IData>{};
} }
template <typename Func> template <typename T_Func>
VlQueue find_last(Func with_func) const { VlQueue find_last(T_Func with_func) const {
IData index = m_deque.size() - 1; IData index = m_deque.size() - 1;
for (auto& item : vlstd::reverse_view(m_deque)) { for (auto& item : vlstd::reverse_view(m_deque)) {
if (with_func(index, item)) return VlQueue::consV(item); if (with_func(index, item)) return VlQueue::consV(item);
@ -788,8 +788,8 @@ public:
} }
return VlQueue{}; return VlQueue{};
} }
template <typename Func> template <typename T_Func>
VlQueue<IData> find_last_index(Func with_func) const { VlQueue<IData> find_last_index(T_Func with_func) const {
IData index = m_deque.size() - 1; IData index = m_deque.size() - 1;
for (auto& item : vlstd::reverse_view(m_deque)) { for (auto& item : vlstd::reverse_view(m_deque)) {
if (with_func(index, item)) return VlQueue<IData>::consV(index); if (with_func(index, item)) return VlQueue<IData>::consV(index);
@ -804,8 +804,8 @@ public:
const auto it = std::min_element(m_deque.cbegin(), m_deque.cend()); const auto it = std::min_element(m_deque.cbegin(), m_deque.cend());
return VlQueue::consV(*it); return VlQueue::consV(*it);
} }
template <typename Func> template <typename T_Func>
VlQueue min(Func with_func) const { VlQueue min(T_Func with_func) const {
if (m_deque.empty()) return VlQueue{}; if (m_deque.empty()) return VlQueue{};
const auto it = std::min_element(m_deque.cbegin(), m_deque.cend(), const auto it = std::min_element(m_deque.cbegin(), m_deque.cend(),
[&with_func](const IData& a, const IData& b) { [&with_func](const IData& a, const IData& b) {
@ -818,8 +818,8 @@ public:
const auto it = std::max_element(m_deque.cbegin(), m_deque.cend()); const auto it = std::max_element(m_deque.cbegin(), m_deque.cend());
return VlQueue::consV(*it); return VlQueue::consV(*it);
} }
template <typename Func> template <typename T_Func>
VlQueue max(Func with_func) const { VlQueue max(T_Func with_func) const {
if (m_deque.empty()) return VlQueue{}; if (m_deque.empty()) return VlQueue{};
const auto it = std::max_element(m_deque.cbegin(), m_deque.cend(), const auto it = std::max_element(m_deque.cbegin(), m_deque.cend(),
[&with_func](const IData& a, const IData& b) { [&with_func](const IData& a, const IData& b) {
@ -833,9 +833,9 @@ public:
for (const auto& i : m_deque) out += i; for (const auto& i : m_deque) out += i;
return out; return out;
} }
template <typename Func> template <typename T_Func>
WithFuncReturnType<Func> r_sum(Func with_func) const { WithFuncReturnType<T_Func> r_sum(T_Func with_func) const {
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(0); WithFuncReturnType<T_Func> out = WithFuncReturnType<T_Func>(0);
IData index = 0; IData index = 0;
for (const auto& i : m_deque) out += with_func(index++, i); for (const auto& i : m_deque) out += with_func(index++, i);
return out; return out;
@ -846,10 +846,10 @@ public:
for (const auto& i : m_deque) out *= i; for (const auto& i : m_deque) out *= i;
return out; return out;
} }
template <typename Func> template <typename T_Func>
WithFuncReturnType<Func> r_product(Func with_func) const { WithFuncReturnType<T_Func> r_product(T_Func with_func) const {
if (m_deque.empty()) return WithFuncReturnType<Func>(0); // The big three do it this way if (m_deque.empty()) return WithFuncReturnType<T_Func>(0); // The big three do it this way
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(1); WithFuncReturnType<T_Func> out = WithFuncReturnType<T_Func>(1);
IData index = 0; IData index = 0;
for (const auto& i : m_deque) out *= with_func(index++, i); for (const auto& i : m_deque) out *= with_func(index++, i);
return out; return out;
@ -860,11 +860,11 @@ public:
for (const auto& i : m_deque) out &= i; for (const auto& i : m_deque) out &= i;
return out; return out;
} }
template <typename Func> template <typename T_Func>
WithFuncReturnType<Func> r_and(Func with_func) const { WithFuncReturnType<T_Func> r_and(T_Func with_func) const {
if (m_deque.empty()) return WithFuncReturnType<Func>(0); // The big three do it this way if (m_deque.empty()) return WithFuncReturnType<T_Func>(0); // The big three do it this way
IData index = 0; IData index = 0;
WithFuncReturnType<Func> out = ~WithFuncReturnType<Func>(0); WithFuncReturnType<T_Func> out = ~WithFuncReturnType<T_Func>(0);
for (const auto& i : m_deque) out &= with_func(index++, i); for (const auto& i : m_deque) out &= with_func(index++, i);
return out; return out;
} }
@ -873,9 +873,9 @@ public:
for (const auto& i : m_deque) out |= i; for (const auto& i : m_deque) out |= i;
return out; return out;
} }
template <typename Func> template <typename T_Func>
WithFuncReturnType<Func> r_or(Func with_func) const { WithFuncReturnType<T_Func> r_or(T_Func with_func) const {
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(0); WithFuncReturnType<T_Func> out = WithFuncReturnType<T_Func>(0);
IData index = 0; IData index = 0;
for (const auto& i : m_deque) out |= with_func(index++, i); for (const auto& i : m_deque) out |= with_func(index++, i);
return out; return out;
@ -888,9 +888,9 @@ public:
for (const auto& i : m_deque) out ^= i; for (const auto& i : m_deque) out ^= i;
return out; return out;
} }
template <typename Func> template <typename T_Func>
WithFuncReturnType<Func> r_xor(Func with_func) const { WithFuncReturnType<T_Func> r_xor(T_Func with_func) const {
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(0); WithFuncReturnType<T_Func> out = WithFuncReturnType<T_Func>(0);
IData index = 0; IData index = 0;
for (const auto& i : m_deque) out ^= with_func(index++, i); for (const auto& i : m_deque) out ^= with_func(index++, i);
return out; return out;
@ -909,8 +909,8 @@ public:
} }
}; };
template <typename T_Value, size_t T_MaxSize> template <typename T_Value, size_t N_MaxSize>
std::string VL_TO_STRING(const VlQueue<T_Value, T_MaxSize>& obj) { std::string VL_TO_STRING(const VlQueue<T_Value, N_MaxSize>& obj) {
return obj.to_string(); return obj.to_string();
} }
@ -927,9 +927,9 @@ private:
public: public:
using const_iterator = typename Map::const_iterator; using const_iterator = typename Map::const_iterator;
template <typename Func> template <typename T_Func>
using WithFuncReturnType using WithFuncReturnType
= decltype(std::declval<Func>()(std::declval<T_Key>(), std::declval<T_Value>())); = decltype(std::declval<T_Func>()(std::declval<T_Key>(), std::declval<T_Value>()));
private: private:
// MEMBERS // MEMBERS
@ -1038,8 +1038,8 @@ public:
} }
return out; return out;
} }
template <typename Func> template <typename T_Func>
VlQueue<T_Value> unique(Func with_func) const { VlQueue<T_Value> unique(T_Func with_func) const {
VlQueue<T_Value> out; VlQueue<T_Value> out;
T_Key default_key; T_Key default_key;
using WithType = decltype(with_func(m_map.begin()->first, m_map.begin()->second)); using WithType = decltype(with_func(m_map.begin()->first, m_map.begin()->second));
@ -1066,8 +1066,8 @@ public:
} }
return out; return out;
} }
template <typename Func> template <typename T_Func>
VlQueue<T_Key> unique_index(Func with_func) const { VlQueue<T_Key> unique_index(T_Func with_func) const {
VlQueue<T_Key> out; VlQueue<T_Key> out;
using WithType = decltype(with_func(m_map.begin()->first, m_map.begin()->second)); using WithType = decltype(with_func(m_map.begin()->first, m_map.begin()->second));
std::set<WithType> saw; std::set<WithType> saw;
@ -1081,22 +1081,22 @@ public:
} }
return out; return out;
} }
template <typename Func> template <typename T_Func>
VlQueue<T_Value> find(Func with_func) const { VlQueue<T_Value> find(T_Func with_func) const {
VlQueue<T_Value> out; VlQueue<T_Value> out;
for (const auto& i : m_map) for (const auto& i : m_map)
if (with_func(i.first, i.second)) out.push_back(i.second); if (with_func(i.first, i.second)) out.push_back(i.second);
return out; return out;
} }
template <typename Func> template <typename T_Func>
VlQueue<T_Key> find_index(Func with_func) const { VlQueue<T_Key> find_index(T_Func with_func) const {
VlQueue<T_Key> out; VlQueue<T_Key> out;
for (const auto& i : m_map) for (const auto& i : m_map)
if (with_func(i.first, i.second)) out.push_back(i.first); if (with_func(i.first, i.second)) out.push_back(i.first);
return out; return out;
} }
template <typename Func> template <typename T_Func>
VlQueue<T_Value> find_first(Func with_func) const { VlQueue<T_Value> find_first(T_Func with_func) const {
const auto it const auto it
= std::find_if(m_map.cbegin(), m_map.cend(), [=](const std::pair<T_Key, T_Value>& i) { = std::find_if(m_map.cbegin(), m_map.cend(), [=](const std::pair<T_Key, T_Value>& i) {
return with_func(i.first, i.second); return with_func(i.first, i.second);
@ -1104,8 +1104,8 @@ public:
if (it == m_map.end()) return VlQueue<T_Value>{}; if (it == m_map.end()) return VlQueue<T_Value>{};
return VlQueue<T_Value>::consV(it->second); return VlQueue<T_Value>::consV(it->second);
} }
template <typename Func> template <typename T_Func>
VlQueue<T_Key> find_first_index(Func with_func) const { VlQueue<T_Key> find_first_index(T_Func with_func) const {
const auto it const auto it
= std::find_if(m_map.cbegin(), m_map.cend(), [=](const std::pair<T_Key, T_Value>& i) { = std::find_if(m_map.cbegin(), m_map.cend(), [=](const std::pair<T_Key, T_Value>& i) {
return with_func(i.first, i.second); return with_func(i.first, i.second);
@ -1113,16 +1113,16 @@ public:
if (it == m_map.end()) return VlQueue<T_Value>{}; if (it == m_map.end()) return VlQueue<T_Value>{};
return VlQueue<T_Key>::consV(it->first); return VlQueue<T_Key>::consV(it->first);
} }
template <typename Func> template <typename T_Func>
VlQueue<T_Value> find_last(Func with_func) const { VlQueue<T_Value> find_last(T_Func with_func) const {
const auto it = std::find_if( const auto it = std::find_if(
m_map.crbegin(), m_map.crend(), m_map.crbegin(), m_map.crend(),
[=](const std::pair<T_Key, T_Value>& i) { return with_func(i.first, i.second); }); [=](const std::pair<T_Key, T_Value>& i) { return with_func(i.first, i.second); });
if (it == m_map.rend()) return VlQueue<T_Value>{}; if (it == m_map.rend()) return VlQueue<T_Value>{};
return VlQueue<T_Value>::consV(it->second); return VlQueue<T_Value>::consV(it->second);
} }
template <typename Func> template <typename T_Func>
VlQueue<T_Key> find_last_index(Func with_func) const { VlQueue<T_Key> find_last_index(T_Func with_func) const {
const auto it = std::find_if( const auto it = std::find_if(
m_map.crbegin(), m_map.crend(), m_map.crbegin(), m_map.crend(),
[=](const std::pair<T_Key, T_Value>& i) { return with_func(i.first, i.second); }); [=](const std::pair<T_Key, T_Value>& i) { return with_func(i.first, i.second); });
@ -1140,8 +1140,8 @@ public:
}); });
return VlQueue<T_Value>::consV(it->second); return VlQueue<T_Value>::consV(it->second);
} }
template <typename Func> template <typename T_Func>
VlQueue<T_Value> min(Func with_func) const { VlQueue<T_Value> min(T_Func with_func) const {
if (m_map.empty()) return VlQueue<T_Value>(); if (m_map.empty()) return VlQueue<T_Value>();
const auto it = std::min_element( const auto it = std::min_element(
m_map.cbegin(), m_map.cend(), m_map.cbegin(), m_map.cend(),
@ -1159,8 +1159,8 @@ public:
}); });
return VlQueue<T_Value>::consV(it->second); return VlQueue<T_Value>::consV(it->second);
} }
template <typename Func> template <typename T_Func>
VlQueue<T_Value> max(Func with_func) const { VlQueue<T_Value> max(T_Func with_func) const {
if (m_map.empty()) return VlQueue<T_Value>(); if (m_map.empty()) return VlQueue<T_Value>();
const auto it = std::max_element( const auto it = std::max_element(
m_map.cbegin(), m_map.cend(), m_map.cbegin(), m_map.cend(),
@ -1175,9 +1175,9 @@ public:
for (const auto& i : m_map) out += i.second; for (const auto& i : m_map) out += i.second;
return out; return out;
} }
template <typename Func> template <typename T_Func>
WithFuncReturnType<Func> r_sum(Func with_func) const { WithFuncReturnType<T_Func> r_sum(T_Func with_func) const {
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(0); WithFuncReturnType<T_Func> out = WithFuncReturnType<T_Func>(0);
for (const auto& i : m_map) out += with_func(i.first, i.second); for (const auto& i : m_map) out += with_func(i.first, i.second);
return out; return out;
} }
@ -1187,10 +1187,10 @@ public:
for (const auto& i : m_map) out *= i.second; for (const auto& i : m_map) out *= i.second;
return out; return out;
} }
template <typename Func> template <typename T_Func>
WithFuncReturnType<Func> r_product(Func with_func) const { WithFuncReturnType<T_Func> r_product(T_Func with_func) const {
if (m_map.empty()) return WithFuncReturnType<Func>(0); // The big three do it this way if (m_map.empty()) return WithFuncReturnType<T_Func>(0); // The big three do it this way
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(1); WithFuncReturnType<T_Func> out = WithFuncReturnType<T_Func>(1);
for (const auto& i : m_map) out *= with_func(i.first, i.second); for (const auto& i : m_map) out *= with_func(i.first, i.second);
return out; return out;
} }
@ -1200,10 +1200,10 @@ public:
for (const auto& i : m_map) out &= i.second; for (const auto& i : m_map) out &= i.second;
return out; return out;
} }
template <typename Func> template <typename T_Func>
WithFuncReturnType<Func> r_and(Func with_func) const { WithFuncReturnType<T_Func> r_and(T_Func with_func) const {
if (m_map.empty()) return WithFuncReturnType<Func>(0); // The big three do it this way if (m_map.empty()) return WithFuncReturnType<T_Func>(0); // The big three do it this way
WithFuncReturnType<Func> out = ~WithFuncReturnType<Func>(0); WithFuncReturnType<T_Func> out = ~WithFuncReturnType<T_Func>(0);
for (const auto& i : m_map) out &= with_func(i.first, i.second); for (const auto& i : m_map) out &= with_func(i.first, i.second);
return out; return out;
} }
@ -1212,8 +1212,8 @@ public:
for (const auto& i : m_map) out |= i.second; for (const auto& i : m_map) out |= i.second;
return out; return out;
} }
template <typename Func> template <typename T_Func>
T_Value r_or(Func with_func) const { T_Value r_or(T_Func with_func) const {
T_Value out = T_Value(0); T_Value out = T_Value(0);
for (const auto& i : m_map) out |= with_func(i.first, i.second); for (const auto& i : m_map) out |= with_func(i.first, i.second);
return out; return out;
@ -1223,9 +1223,9 @@ public:
for (const auto& i : m_map) out ^= i.second; for (const auto& i : m_map) out ^= i.second;
return out; return out;
} }
template <typename Func> template <typename T_Func>
WithFuncReturnType<Func> r_xor(Func with_func) const { WithFuncReturnType<T_Func> r_xor(T_Func with_func) const {
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(0); WithFuncReturnType<T_Func> out = WithFuncReturnType<T_Func>(0);
for (const auto& i : m_map) out ^= with_func(i.first, i.second); for (const auto& i : m_map) out ^= with_func(i.first, i.second);
return out; return out;
} }
@ -1287,11 +1287,11 @@ void VL_WRITEMEM_N(bool hex, int bits, const std::string& filename,
/// This class may get exposed to a Verilated Model's top I/O, if the top /// This class may get exposed to a Verilated Model's top I/O, if the top
/// IO has an unpacked array. /// IO has an unpacked array.
template <typename T_Value, std::size_t T_Depth> template <typename T_Value, std::size_t N_Depth>
class VlUnpacked final { class VlUnpacked final {
// TYPES // TYPES
using T_Key = IData; // Index type, for uniformity with other containers using T_Key = IData; // Index type, for uniformity with other containers
using Unpacked = T_Value[T_Depth]; using Unpacked = T_Value[N_Depth];
public: public:
// MEMBERS // MEMBERS
@ -1312,41 +1312,41 @@ public:
WData* data() { return &m_storage[0]; } WData* data() { return &m_storage[0]; }
const WData* data() const { return &m_storage[0]; } const WData* data() const { return &m_storage[0]; }
std::size_t size() const { return T_Depth; } std::size_t size() const { return N_Depth; }
// To fit C++14 // To fit C++14
template <std::size_t CurrentDimension = 0, typename U = T_Value> template <std::size_t N_CurrentDimension = 0, typename U = T_Value>
int find_length(int dimension, std::false_type) const { int find_length(int dimension, std::false_type) const {
return size(); return size();
} }
template <std::size_t CurrentDimension = 0, typename U = T_Value> template <std::size_t N_CurrentDimension = 0, typename U = T_Value>
int find_length(int dimension, std::true_type) const { int find_length(int dimension, std::true_type) const {
if (dimension == CurrentDimension) { if (dimension == N_CurrentDimension) {
return size(); return size();
} else { } else {
return m_storage[0].template find_length<CurrentDimension + 1>(dimension); return m_storage[0].template find_length<N_CurrentDimension + 1>(dimension);
} }
} }
template <std::size_t CurrentDimension = 0> template <std::size_t N_CurrentDimension = 0>
int find_length(int dimension) const { int find_length(int dimension) const {
return find_length<CurrentDimension>(dimension, std::is_class<T_Value>{}); return find_length<N_CurrentDimension>(dimension, std::is_class<T_Value>{});
} }
template <std::size_t CurrentDimension = 0, typename U = T_Value> template <std::size_t N_CurrentDimension = 0, typename U = T_Value>
auto& find_element(const std::vector<size_t>& indices, std::false_type) { auto& find_element(const std::vector<size_t>& indices, std::false_type) {
return m_storage[indices[CurrentDimension]]; return m_storage[indices[N_CurrentDimension]];
} }
template <std::size_t CurrentDimension = 0, typename U = T_Value> template <std::size_t N_CurrentDimension = 0, typename U = T_Value>
auto& find_element(const std::vector<size_t>& indices, std::true_type) { auto& find_element(const std::vector<size_t>& indices, std::true_type) {
return m_storage[indices[CurrentDimension]].template find_element<CurrentDimension + 1>( return m_storage[indices[N_CurrentDimension]]
indices); .template find_element<N_CurrentDimension + 1>(indices);
} }
template <std::size_t CurrentDimension = 0> template <std::size_t N_CurrentDimension = 0>
auto& find_element(const std::vector<size_t>& indices) { auto& find_element(const std::vector<size_t>& indices) {
return find_element<CurrentDimension>(indices, std::is_class<T_Value>{}); return find_element<N_CurrentDimension>(indices, std::is_class<T_Value>{});
} }
T_Value& operator[](size_t index) { return m_storage[index]; } T_Value& operator[](size_t index) { return m_storage[index]; }
@ -1354,15 +1354,15 @@ public:
// *this != that, which might be used for change detection/trigger computation, but avoid // *this != that, which might be used for change detection/trigger computation, but avoid
// operator overloading in VlUnpacked for safety in other contexts. // operator overloading in VlUnpacked for safety in other contexts.
bool neq(const VlUnpacked<T_Value, T_Depth>& that) const { return neq(*this, that); } bool neq(const VlUnpacked<T_Value, N_Depth>& that) const { return neq(*this, that); }
// Similar to 'neq' above, *this = that used for change detection // Similar to 'neq' above, *this = that used for change detection
void assign(const VlUnpacked<T_Value, T_Depth>& that) { *this = that; } void assign(const VlUnpacked<T_Value, N_Depth>& that) { *this = that; }
bool operator==(const VlUnpacked<T_Value, T_Depth>& that) const { return !neq(that); } bool operator==(const VlUnpacked<T_Value, N_Depth>& that) const { return !neq(that); }
bool operator!=(const VlUnpacked<T_Value, T_Depth>& that) const { return neq(that); } bool operator!=(const VlUnpacked<T_Value, N_Depth>& that) const { return neq(that); }
// interface to C style arrays (used in ports), see issue #5125 // interface to C style arrays (used in ports), see issue #5125
bool neq(const T_Value that[T_Depth]) const { return neq(*this, that); } bool neq(const T_Value that[N_Depth]) const { return neq(*this, that); }
void assign(const T_Value that[T_Depth]) { std::copy_n(that, T_Depth, m_storage); } void assign(const T_Value that[N_Depth]) { std::copy_n(that, N_Depth, m_storage); }
void operator=(const T_Value that[T_Depth]) { assign(that); } void operator=(const T_Value that[N_Depth]) { assign(that); }
// inside (set membership operator) // inside (set membership operator)
bool inside(const T_Value& value) const { bool inside(const T_Value& value) const {
@ -1370,8 +1370,8 @@ public:
} }
void sort() { std::sort(std::begin(m_storage), std::end(m_storage)); } void sort() { std::sort(std::begin(m_storage), std::end(m_storage)); }
template <typename Func> template <typename T_Func>
void sort(Func with_func) { void sort(T_Func with_func) {
// with_func returns arbitrary type to use for the sort comparison // with_func returns arbitrary type to use for the sort comparison
std::sort(std::begin(m_storage), std::end(m_storage), std::sort(std::begin(m_storage), std::end(m_storage),
[=](const T_Value& a, const T_Value& b) { [=](const T_Value& a, const T_Value& b) {
@ -1383,8 +1383,8 @@ public:
void rsort() { void rsort() {
std::sort(std::begin(m_storage), std::end(m_storage), std::greater<T_Value>()); std::sort(std::begin(m_storage), std::end(m_storage), std::greater<T_Value>());
} }
template <typename Func> template <typename T_Func>
void rsort(Func with_func) { void rsort(T_Func with_func) {
// with_func returns arbitrary type to use for the sort comparison // with_func returns arbitrary type to use for the sort comparison
// std::rbegin/std::rend not available until C++14, so using > below // std::rbegin/std::rend not available until C++14, so using > below
std::sort(std::begin(m_storage), std::end(m_storage), std::sort(std::begin(m_storage), std::end(m_storage),
@ -1407,8 +1407,8 @@ public:
} }
return out; return out;
} }
template <typename Func> template <typename T_Func>
VlQueue<T_Value> unique(Func with_func) const { VlQueue<T_Value> unique(T_Func with_func) const {
VlQueue<T_Value> out; VlQueue<T_Value> out;
std::set<T_Value> saw; std::set<T_Value> saw;
for (const auto& i : m_storage) { for (const auto& i : m_storage) {
@ -1435,8 +1435,8 @@ public:
} }
return out; return out;
} }
template <typename Func> template <typename T_Func>
VlQueue<T_Key> unique_index(Func with_func) const { VlQueue<T_Key> unique_index(T_Func with_func) const {
VlQueue<T_Key> out; VlQueue<T_Key> out;
IData index = 0; IData index = 0;
std::set<T_Value> saw; std::set<T_Value> saw;
@ -1451,8 +1451,8 @@ public:
} }
return out; return out;
} }
template <typename Func> template <typename T_Func>
VlQueue<T_Value> find(Func with_func) const { VlQueue<T_Value> find(T_Func with_func) const {
VlQueue<T_Value> out; VlQueue<T_Value> out;
IData index = 0; IData index = 0;
for (const auto& i : m_storage) { for (const auto& i : m_storage) {
@ -1461,8 +1461,8 @@ public:
} }
return out; return out;
} }
template <typename Func> template <typename T_Func>
VlQueue<T_Key> find_index(Func with_func) const { VlQueue<T_Key> find_index(T_Func with_func) const {
VlQueue<T_Key> out; VlQueue<T_Key> out;
IData index = 0; IData index = 0;
for (const auto& i : m_storage) { for (const auto& i : m_storage) {
@ -1471,8 +1471,8 @@ public:
} }
return out; return out;
} }
template <typename Func> template <typename T_Func>
VlQueue<T_Value> find_first(Func with_func) const { VlQueue<T_Value> find_first(T_Func with_func) const {
// Can't use std::find_if as need index number // Can't use std::find_if as need index number
IData index = 0; IData index = 0;
for (const auto& i : m_storage) { for (const auto& i : m_storage) {
@ -1481,8 +1481,8 @@ public:
} }
return VlQueue<T_Value>{}; return VlQueue<T_Value>{};
} }
template <typename Func> template <typename T_Func>
VlQueue<T_Key> find_first_index(Func with_func) const { VlQueue<T_Key> find_first_index(T_Func with_func) const {
IData index = 0; IData index = 0;
for (const auto& i : m_storage) { for (const auto& i : m_storage) {
if (with_func(index, i)) return VlQueue<IData>::consV(index); if (with_func(index, i)) return VlQueue<IData>::consV(index);
@ -1490,16 +1490,16 @@ public:
} }
return VlQueue<T_Key>{}; return VlQueue<T_Key>{};
} }
template <typename Func> template <typename T_Func>
VlQueue<T_Value> find_last(Func with_func) const { VlQueue<T_Value> find_last(T_Func with_func) const {
for (int i = T_Depth - 1; i >= 0; i--) { for (int i = N_Depth - 1; i >= 0; i--) {
if (with_func(i, m_storage[i])) return VlQueue<T_Value>::consV(m_storage[i]); if (with_func(i, m_storage[i])) return VlQueue<T_Value>::consV(m_storage[i]);
} }
return VlQueue<T_Value>{}; return VlQueue<T_Value>{};
} }
template <typename Func> template <typename T_Func>
VlQueue<T_Key> find_last_index(Func with_func) const { VlQueue<T_Key> find_last_index(T_Func with_func) const {
for (int i = T_Depth - 1; i >= 0; i--) { for (int i = N_Depth - 1; i >= 0; i--) {
if (with_func(i, m_storage[i])) return VlQueue<IData>::consV(i); if (with_func(i, m_storage[i])) return VlQueue<IData>::consV(i);
} }
return VlQueue<T_Key>{}; return VlQueue<T_Key>{};
@ -1510,8 +1510,8 @@ public:
const auto it = std::min_element(std::begin(m_storage), std::end(m_storage)); const auto it = std::min_element(std::begin(m_storage), std::end(m_storage));
return VlQueue<T_Value>::consV(*it); return VlQueue<T_Value>::consV(*it);
} }
template <typename Func> template <typename T_Func>
VlQueue<T_Value> min(Func with_func) const { VlQueue<T_Value> min(T_Func with_func) const {
const auto it = std::min_element(std::begin(m_storage), std::end(m_storage), const auto it = std::min_element(std::begin(m_storage), std::end(m_storage),
[&with_func](const IData& a, const IData& b) { [&with_func](const IData& a, const IData& b) {
return with_func(0, a) < with_func(0, b); return with_func(0, a) < with_func(0, b);
@ -1522,8 +1522,8 @@ public:
const auto it = std::max_element(std::begin(m_storage), std::end(m_storage)); const auto it = std::max_element(std::begin(m_storage), std::end(m_storage));
return VlQueue<T_Value>::consV(*it); return VlQueue<T_Value>::consV(*it);
} }
template <typename Func> template <typename T_Func>
VlQueue<T_Value> max(Func with_func) const { VlQueue<T_Value> max(T_Func with_func) const {
const auto it = std::max_element(std::begin(m_storage), std::end(m_storage), const auto it = std::max_element(std::begin(m_storage), std::end(m_storage),
[&with_func](const IData& a, const IData& b) { [&with_func](const IData& a, const IData& b) {
return with_func(0, a) < with_func(0, b); return with_func(0, a) < with_func(0, b);
@ -1535,7 +1535,7 @@ public:
std::string to_string() const { std::string to_string() const {
std::string out = "'{"; std::string out = "'{";
std::string comma; std::string comma;
for (int i = 0; i < T_Depth; ++i) { for (int i = 0; i < N_Depth; ++i) {
out += comma + VL_TO_STRING(m_storage[i]); out += comma + VL_TO_STRING(m_storage[i]);
comma = ", "; comma = ", ";
} }
@ -1543,18 +1543,18 @@ public:
} }
private: private:
template <typename T_Val, std::size_t T_Dep> template <typename T_Val, std::size_t N_Dep>
static bool neq(const VlUnpacked<T_Val, T_Dep>& a, const VlUnpacked<T_Val, T_Dep>& b) { static bool neq(const VlUnpacked<T_Val, N_Dep>& a, const VlUnpacked<T_Val, N_Dep>& b) {
for (size_t i = 0; i < T_Dep; ++i) { for (size_t i = 0; i < N_Dep; ++i) {
// Recursive 'neq', in case T_Val is also a VlUnpacked<_, _> // Recursive 'neq', in case T_Val is also a VlUnpacked<_, _>
if (neq(a.m_storage[i], b.m_storage[i])) return true; if (neq(a.m_storage[i], b.m_storage[i])) return true;
} }
return false; return false;
} }
template <typename T_Val, std::size_t T_Dep> template <typename T_Val, std::size_t N_Dep>
static bool neq(const VlUnpacked<T_Val, T_Dep>& a, const T_Val b[T_Dep]) { static bool neq(const VlUnpacked<T_Val, N_Dep>& a, const T_Val b[N_Dep]) {
for (size_t i = 0; i < T_Dep; ++i) { for (size_t i = 0; i < N_Dep; ++i) {
// Recursive 'neq', in case T_Val is also a VlUnpacked<_, _> // Recursive 'neq', in case T_Val is also a VlUnpacked<_, _>
if (neq(a.m_storage[i], b[i])) return true; if (neq(a.m_storage[i], b[i])) return true;
} }
@ -1568,25 +1568,25 @@ private:
} }
}; };
template <typename T_Value, std::size_t T_Depth> template <typename T_Value, std::size_t N_Depth>
std::string VL_TO_STRING(const VlUnpacked<T_Value, T_Depth>& obj) { std::string VL_TO_STRING(const VlUnpacked<T_Value, N_Depth>& obj) {
return obj.to_string(); return obj.to_string();
} }
//=================================================================== //===================================================================
// Helper to apply the given indices to a target expression // Helper to apply the given indices to a target expression
template <size_t Curr, size_t Rank, typename T_Target> template <size_t N_Curr, size_t N_Rank, typename T_Target>
struct VlApplyIndices final { struct VlApplyIndices final {
VL_ATTR_ALWINLINE VL_ATTR_ALWINLINE
static auto& apply(T_Target& target, const size_t* indicesp) { static auto& apply(T_Target& target, const size_t* indicesp) {
return VlApplyIndices<Curr + 1, Rank, decltype(target[indicesp[Curr]])>::apply( return VlApplyIndices<N_Curr + 1, N_Rank, decltype(target[indicesp[N_Curr]])>::apply(
target[indicesp[Curr]], indicesp); target[indicesp[N_Curr]], indicesp);
} }
}; };
template <size_t Rank, typename T_Target> template <size_t N_Rank, typename T_Target>
struct VlApplyIndices<Rank, Rank, T_Target> final { struct VlApplyIndices<N_Rank, N_Rank, T_Target> final {
VL_ATTR_ALWINLINE VL_ATTR_ALWINLINE
static T_Target& apply(T_Target& target, const size_t*) { return target; } static T_Target& apply(T_Target& target, const size_t*) { return target; }
}; };
@ -1621,17 +1621,17 @@ template <typename T_Target, // Type of the variable this commit queue updates
// The following we could figure out from 'T_Target using type traits, but passing // The following we could figure out from 'T_Target using type traits, but passing
// explicitly to avoid template expansion, as Verilator already knows them // explicitly to avoid template expansion, as Verilator already knows them
typename T_Element, // Non-array leaf element type of T_Target array typename T_Element, // Non-array leaf element type of T_Target array
std::size_t T_Rank // Rank of T_Target (i.e.: how many dimensions it has) std::size_t N_Rank // Rank of T_Target (i.e.: how many dimensions it has)
> >
class VlNBACommitQueue; class VlNBACommitQueue;
// Specialization for whole element updates only // Specialization for whole element updates only
template <typename T_Target, typename T_Element, std::size_t T_Rank> template <typename T_Target, typename T_Element, std::size_t N_Rank>
class VlNBACommitQueue<T_Target, /* Partial: */ false, T_Element, T_Rank> final { class VlNBACommitQueue<T_Target, /* Partial: */ false, T_Element, N_Rank> final {
// TYPES // TYPES
struct Entry final { struct Entry final {
T_Element value; T_Element value;
size_t indices[T_Rank]; size_t indices[N_Rank];
}; };
// STATE // STATE
@ -1643,8 +1643,8 @@ public:
VL_UNCOPYABLE(VlNBACommitQueue); VL_UNCOPYABLE(VlNBACommitQueue);
// METHODS // METHODS
template <typename... Args> template <typename... T_Args>
void enqueue(const T_Element& value, Args... indices) { void enqueue(const T_Element& value, T_Args... indices) {
m_pending.emplace_back(Entry{value, {indices...}}); m_pending.emplace_back(Entry{value, {indices...}});
} }
@ -1654,20 +1654,20 @@ public:
void commit(T_Commit& target) { void commit(T_Commit& target) {
if (m_pending.empty()) return; if (m_pending.empty()) return;
for (const Entry& entry : m_pending) { for (const Entry& entry : m_pending) {
VlApplyIndices<0, T_Rank, T_Commit>::apply(target, entry.indices) = entry.value; VlApplyIndices<0, N_Rank, T_Commit>::apply(target, entry.indices) = entry.value;
} }
m_pending.clear(); m_pending.clear();
} }
}; };
// With partial element updates // With partial element updates
template <typename T_Target, typename T_Element, std::size_t T_Rank> template <typename T_Target, typename T_Element, std::size_t N_Rank>
class VlNBACommitQueue<T_Target, /* Partial: */ true, T_Element, T_Rank> final { class VlNBACommitQueue<T_Target, /* Partial: */ true, T_Element, N_Rank> final {
// TYPES // TYPES
struct Entry final { struct Entry final {
T_Element value; T_Element value;
T_Element mask; T_Element mask;
size_t indices[T_Rank]; size_t indices[N_Rank];
}; };
// STATE // STATE
@ -1728,8 +1728,8 @@ public:
VL_UNCOPYABLE(VlNBACommitQueue); VL_UNCOPYABLE(VlNBACommitQueue);
// METHODS // METHODS
template <typename... Args> template <typename... T_Args>
void enqueue(const T_Element& value, const T_Element& mask, Args... indices) { void enqueue(const T_Element& value, const T_Element& mask, T_Args... indices) {
m_pending.emplace_back(Entry{value, mask, {indices...}}); m_pending.emplace_back(Entry{value, mask, {indices...}});
} }
@ -1739,7 +1739,7 @@ public:
void commit(T_Commit& target) { void commit(T_Commit& target) {
if (m_pending.empty()) return; if (m_pending.empty()) return;
for (const Entry& entry : m_pending) { // for (const Entry& entry : m_pending) { //
auto& ref = VlApplyIndices<0, T_Rank, T_Commit>::apply(target, entry.indices); auto& ref = VlApplyIndices<0, N_Rank, T_Commit>::apply(target, entry.indices);
// Maybe inefficient, but it works for now ... // Maybe inefficient, but it works for now ...
const auto oldValue = ref; const auto oldValue = ref;
ref = bOr(bAnd(entry.value, entry.mask), bAnd(oldValue, bNot(entry.mask))); ref = bOr(bAnd(entry.value, entry.mask), bAnd(oldValue, bNot(entry.mask)));
@ -1961,13 +1961,13 @@ public:
}; };
}; };
template <typename T, typename U> template <typename T_Lhs, typename T_Out>
static inline bool VL_CAST_DYNAMIC(VlClassRef<T> in, VlClassRef<U>& outr) { static inline bool VL_CAST_DYNAMIC(VlClassRef<T_Lhs> in, VlClassRef<T_Out>& outr) {
if (!in) { if (!in) {
outr = VlNull{}; outr = VlNull{};
return true; return true;
} }
VlClassRef<U> casted = in.template dynamicCast<U>(); VlClassRef<T_Out> casted = in.template dynamicCast<T_Out>();
if (VL_LIKELY(casted)) { if (VL_LIKELY(casted)) {
outr = casted; outr = casted;
return true; return true;
@ -1976,8 +1976,8 @@ static inline bool VL_CAST_DYNAMIC(VlClassRef<T> in, VlClassRef<U>& outr) {
} }
} }
template <typename T> template <typename T_Lhs>
static inline bool VL_CAST_DYNAMIC(VlNull in, VlClassRef<T>& outr) { static inline bool VL_CAST_DYNAMIC(VlNull in, VlClassRef<T_Lhs>& outr) {
outr = VlNull{}; outr = VlNull{};
return true; return true;
} }

View File

@ -230,7 +230,7 @@ class ActiveNamer final : public VNVisitor {
void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstNode* nodep) override { iterateChildren(nodep); }
// Specialized below for the special sensitivity classes // Specialized below for the special sensitivity classes
template <typename SenItemKind> template <typename T_SenItemKind>
AstActive*& getSpecialActive(); AstActive*& getSpecialActive();
public: public:
@ -246,17 +246,17 @@ public:
} }
// Make a new AstActive sensitive to the given special sensitivity class and return it // Make a new AstActive sensitive to the given special sensitivity class and return it
template <typename SenItemKind> template <typename T_SenItemKind>
AstActive* makeSpecialActive(FileLine* const fl) { AstActive* makeSpecialActive(FileLine* const fl) {
AstSenTree* const senTreep = new AstSenTree{fl, new AstSenItem{fl, SenItemKind{}}}; AstSenTree* const senTreep = new AstSenTree{fl, new AstSenItem{fl, T_SenItemKind{}}};
return makeActive(fl, senTreep); return makeActive(fl, senTreep);
} }
// Return an AstActive sensitive to the given special sensitivity class (possibly pre-created) // Return an AstActive sensitive to the given special sensitivity class (possibly pre-created)
template <typename SenItemKind> template <typename T_SenItemKind>
AstActive* getSpecialActive(FileLine* fl) { AstActive* getSpecialActive(FileLine* fl) {
AstActive*& cachep = getSpecialActive<SenItemKind>(); AstActive*& cachep = getSpecialActive<T_SenItemKind>();
if (!cachep) cachep = makeSpecialActive<SenItemKind>(fl); if (!cachep) cachep = makeSpecialActive<T_SenItemKind>(fl);
return cachep; return cachep;
} }

View File

@ -2553,21 +2553,21 @@ protected:
inline static bool privateTypeTest(const AstNode* nodep); inline static bool privateTypeTest(const AstNode* nodep);
// For internal use only. // For internal use only.
template <typename TargetType, typename DeclType> template <typename T_TargetType, typename T_DeclType>
constexpr static bool uselessCast() VL_PURE { constexpr static bool uselessCast() VL_PURE {
using NonRef = typename std::remove_reference<DeclType>::type; using NonRef = typename std::remove_reference<T_DeclType>::type;
using NonPtr = typename std::remove_pointer<NonRef>::type; using NonPtr = typename std::remove_pointer<NonRef>::type;
using NonCV = typename std::remove_cv<NonPtr>::type; using NonCV = typename std::remove_cv<NonPtr>::type;
return std::is_base_of<TargetType, NonCV>::value; return std::is_base_of<T_TargetType, NonCV>::value;
} }
// For internal use only. // For internal use only.
template <typename TargetType, typename DeclType> template <typename T_TargetType, typename T_DeclType>
constexpr static bool impossibleCast() VL_PURE { constexpr static bool impossibleCast() VL_PURE {
using NonRef = typename std::remove_reference<DeclType>::type; using NonRef = typename std::remove_reference<T_DeclType>::type;
using NonPtr = typename std::remove_pointer<NonRef>::type; using NonPtr = typename std::remove_pointer<NonRef>::type;
using NonCV = typename std::remove_cv<NonPtr>::type; using NonCV = typename std::remove_cv<NonPtr>::type;
return !std::is_base_of<NonCV, TargetType>::value; return !std::is_base_of<NonCV, T_TargetType>::value;
} }
public: public:
@ -2655,12 +2655,12 @@ private:
using ConstCorrectAstNode = using ConstCorrectAstNode =
typename std::conditional<std::is_const<T_Arg>::value, const AstNode, AstNode>::type; typename std::conditional<std::is_const<T_Arg>::value, const AstNode, AstNode>::type;
template <typename T_Arg, typename Callable> template <typename T_Arg, typename T_Callable>
inline static void foreachImpl(ConstCorrectAstNode<T_Arg>* nodep, const Callable& f, inline static void foreachImpl(ConstCorrectAstNode<T_Arg>* nodep, const T_Callable& f,
bool visitNext); bool visitNext);
template <typename T_Arg, bool Default, typename Callable> template <typename T_Arg, bool N_Default, typename T_Callable>
inline static bool predicateImpl(ConstCorrectAstNode<T_Arg>* nodep, const Callable& p); inline static bool predicateImpl(ConstCorrectAstNode<T_Arg>* nodep, const T_Callable& p);
public: public:
// Given a callable 'f' that takes a single argument of some AstNode subtype 'T_Node', traverse // Given a callable 'f' that takes a single argument of some AstNode subtype 'T_Node', traverse
@ -2670,46 +2670,48 @@ public:
// handle a single (or a few) node types, as it's easier to write, but more importantly, the // handle a single (or a few) node types, as it's easier to write, but more importantly, the
// dispatch to the callable in 'foreach' should be completely predictable by branch target // dispatch to the callable in 'foreach' should be completely predictable by branch target
// caches in modern CPUs, while it is basically unpredictable for VNVisitor. // caches in modern CPUs, while it is basically unpredictable for VNVisitor.
template <typename Callable> template <typename T_Callable>
void foreach(Callable&& f) { void foreach(T_Callable&& f) {
using T_Node = typename FunctionArgNoPointerNoCV<Callable, 0>::type; using T_Node = typename FunctionArgNoPointerNoCV<T_Callable, 0>::type;
static_assert(vlstd::is_invocable<Callable, T_Node*>::value static_assert(vlstd::is_invocable<T_Callable, T_Node*>::value
&& std::is_base_of<AstNode, T_Node>::value, && std::is_base_of<AstNode, T_Node>::value,
"Callable 'f' must have a signature compatible with 'void(T_Node*)', " "T_Callable 'f' must have a signature compatible with 'void(T_Node*)', "
"with 'T_Node' being a subtype of 'AstNode'"); "with 'T_Node' being a subtype of 'AstNode'");
foreachImpl<T_Node>(this, f, /* visitNext: */ false); foreachImpl<T_Node>(this, f, /* visitNext: */ false);
} }
// Same as above, but for 'const' nodes // Same as above, but for 'const' nodes
template <typename Callable> template <typename T_Callable>
void foreach(Callable&& f) const { void foreach(T_Callable&& f) const {
using T_Node = typename FunctionArgNoPointerNoCV<Callable, 0>::type; using T_Node = typename FunctionArgNoPointerNoCV<T_Callable, 0>::type;
static_assert(vlstd::is_invocable<Callable, const T_Node*>::value static_assert(
&& std::is_base_of<AstNode, T_Node>::value, vlstd::is_invocable<T_Callable, const T_Node*>::value
"Callable 'f' must have a signature compatible with 'void(const T_Node*)', " && std::is_base_of<AstNode, T_Node>::value,
"with 'T_Node' being a subtype of 'AstNode'"); "T_Callable 'f' must have a signature compatible with 'void(const T_Node*)', "
"with 'T_Node' being a subtype of 'AstNode'");
foreachImpl<const T_Node>(this, f, /* visitNext: */ false); foreachImpl<const T_Node>(this, f, /* visitNext: */ false);
} }
// Same as 'foreach' but also traverses 'this->nextp()' transitively // Same as 'foreach' but also traverses 'this->nextp()' transitively
template <typename Callable> template <typename T_Callable>
void foreachAndNext(Callable&& f) { void foreachAndNext(T_Callable&& f) {
using T_Node = typename FunctionArgNoPointerNoCV<Callable, 0>::type; using T_Node = typename FunctionArgNoPointerNoCV<T_Callable, 0>::type;
static_assert(vlstd::is_invocable<Callable, T_Node*>::value static_assert(vlstd::is_invocable<T_Callable, T_Node*>::value
&& std::is_base_of<AstNode, T_Node>::value, && std::is_base_of<AstNode, T_Node>::value,
"Callable 'f' must have a signature compatible with 'void(T_Node*)', " "T_Callable 'f' must have a signature compatible with 'void(T_Node*)', "
"with 'T_Node' being a subtype of 'AstNode'"); "with 'T_Node' being a subtype of 'AstNode'");
foreachImpl<T_Node>(this, f, /* visitNext: */ true); foreachImpl<T_Node>(this, f, /* visitNext: */ true);
} }
// Same as above, but for 'const' nodes // Same as above, but for 'const' nodes
template <typename Callable> template <typename T_Callable>
void foreachAndNext(Callable&& f) const { void foreachAndNext(T_Callable&& f) const {
using T_Node = typename FunctionArgNoPointerNoCV<Callable, 0>::type; using T_Node = typename FunctionArgNoPointerNoCV<T_Callable, 0>::type;
static_assert(vlstd::is_invocable<Callable, const T_Node*>::value static_assert(
&& std::is_base_of<AstNode, T_Node>::value, vlstd::is_invocable<T_Callable, const T_Node*>::value
"Callable 'f' must have a signature compatible with 'void(const T_Node*)', " && std::is_base_of<AstNode, T_Node>::value,
"with 'T_Node' being a subtype of 'AstNode'"); "T_Callable 'f' must have a signature compatible with 'void(const T_Node*)', "
"with 'T_Node' being a subtype of 'AstNode'");
foreachImpl<const T_Node>(this, f, /* visitNext: */ true); foreachImpl<const T_Node>(this, f, /* visitNext: */ true);
} }
@ -2718,50 +2720,50 @@ public:
// that satisfies the predicate 'p'. Returns false if no node of type 'T_Node' is present. // that satisfies the predicate 'p'. Returns false if no node of type 'T_Node' is present.
// Traversal is performed in some arbitrary order and is terminated as soon as the result can // Traversal is performed in some arbitrary order and is terminated as soon as the result can
// be determined. // be determined.
template <typename Callable> template <typename T_Callable>
bool exists(Callable&& p) { bool exists(T_Callable&& p) {
using T_Node = typename FunctionArgNoPointerNoCV<Callable, 0>::type; using T_Node = typename FunctionArgNoPointerNoCV<T_Callable, 0>::type;
static_assert(vlstd::is_invocable_r<bool, Callable, T_Node*>::value static_assert(vlstd::is_invocable_r<bool, T_Callable, T_Node*>::value
&& std::is_base_of<AstNode, T_Node>::value, && std::is_base_of<AstNode, T_Node>::value,
"Predicate 'p' must have a signature compatible with 'bool(T_Node*)', " "Predicate 'p' must have a signature compatible with 'bool(T_Node*)', "
"with 'T_Node' being a subtype of 'AstNode'"); "with 'T_Node' being a subtype of 'AstNode'");
return predicateImpl<T_Node, /* Default: */ false>(this, p); return predicateImpl<T_Node, /* N_Default: */ false>(this, p);
} }
// Same as above, but for 'const' nodes // Same as above, but for 'const' nodes
template <typename Callable> template <typename T_Callable>
bool exists(Callable&& p) const { bool exists(T_Callable&& p) const {
using T_Node = typename FunctionArgNoPointerNoCV<Callable, 0>::type; using T_Node = typename FunctionArgNoPointerNoCV<T_Callable, 0>::type;
static_assert(vlstd::is_invocable_r<bool, Callable, const T_Node*>::value static_assert(vlstd::is_invocable_r<bool, T_Callable, const T_Node*>::value
&& std::is_base_of<AstNode, T_Node>::value, && std::is_base_of<AstNode, T_Node>::value,
"Predicate 'p' must have a signature compatible with 'bool(const T_Node*)', " "Predicate 'p' must have a signature compatible with 'bool(const T_Node*)', "
"with 'T_Node' being a subtype of 'AstNode'"); "with 'T_Node' being a subtype of 'AstNode'");
return predicateImpl<const T_Node, /* Default: */ false>(this, p); return predicateImpl<const T_Node, /* N_Default: */ false>(this, p);
} }
// Given a predicate 'p' that takes a single argument of some AstNode subtype 'T_Node', return // Given a predicate 'p' that takes a single argument of some AstNode subtype 'T_Node', return
// true if and only if all nodes of type 'T_Node' in the tree rooted at this node satisfy the // true if and only if all nodes of type 'T_Node' in the tree rooted at this node satisfy the
// predicate 'p'. Returns true if no node of type 'T_Node' is present. Traversal is performed // predicate 'p'. Returns true if no node of type 'T_Node' is present. Traversal is performed
// in some arbitrary order and is terminated as soon as the result can be determined. // in some arbitrary order and is terminated as soon as the result can be determined.
template <typename Callable> template <typename T_Callable>
bool forall(Callable&& p) { bool forall(T_Callable&& p) {
using T_Node = typename FunctionArgNoPointerNoCV<Callable, 0>::type; using T_Node = typename FunctionArgNoPointerNoCV<T_Callable, 0>::type;
static_assert(vlstd::is_invocable_r<bool, Callable, T_Node*>::value static_assert(vlstd::is_invocable_r<bool, T_Callable, T_Node*>::value
&& std::is_base_of<AstNode, T_Node>::value, && std::is_base_of<AstNode, T_Node>::value,
"Predicate 'p' must have a signature compatible with 'bool(T_Node*)', " "Predicate 'p' must have a signature compatible with 'bool(T_Node*)', "
"with 'T_Node' being a subtype of 'AstNode'"); "with 'T_Node' being a subtype of 'AstNode'");
return predicateImpl<T_Node, /* Default: */ true>(this, p); return predicateImpl<T_Node, /* N_Default: */ true>(this, p);
} }
// Same as above, but for 'const' nodes // Same as above, but for 'const' nodes
template <typename Callable> template <typename T_Callable>
bool forall(Callable&& p) const { bool forall(T_Callable&& p) const {
using T_Node = typename FunctionArgNoPointerNoCV<Callable, 0>::type; using T_Node = typename FunctionArgNoPointerNoCV<T_Callable, 0>::type;
static_assert(vlstd::is_invocable_r<bool, Callable, const T_Node*>::value static_assert(vlstd::is_invocable_r<bool, T_Callable, const T_Node*>::value
&& std::is_base_of<AstNode, T_Node>::value, && std::is_base_of<AstNode, T_Node>::value,
"Predicate 'p' must have a signature compatible with 'bool(const T_Node*)', " "Predicate 'p' must have a signature compatible with 'bool(const T_Node*)', "
"with 'T_Node' being a subtype of 'AstNode'"); "with 'T_Node' being a subtype of 'AstNode'");
return predicateImpl<const T_Node, /* Default: */ true>(this, p); return predicateImpl<const T_Node, /* N_Default: */ true>(this, p);
} }
int nodeCount() const { int nodeCount() const {
@ -2834,8 +2836,8 @@ constexpr bool AstNode::isLeaf<AstVarXRef>() {
} }
// foreach implementation // foreach implementation
template <typename T_Arg, typename Callable> template <typename T_Arg, typename T_Callable>
void AstNode::foreachImpl(ConstCorrectAstNode<T_Arg>* nodep, const Callable& f, bool visitNext) { void AstNode::foreachImpl(ConstCorrectAstNode<T_Arg>* nodep, const T_Callable& f, bool visitNext) {
// Pre-order traversal implemented directly (without recursion) for speed reasons. The very // Pre-order traversal implemented directly (without recursion) for speed reasons. The very
// first iteration (the one that operates on the input nodep) is special, as we might or // first iteration (the one that operates on the input nodep) is special, as we might or
// might not need to enqueue nodep->nextp() depending on VisitNext, while in all other // might not need to enqueue nodep->nextp() depending on VisitNext, while in all other
@ -2915,8 +2917,8 @@ void AstNode::foreachImpl(ConstCorrectAstNode<T_Arg>* nodep, const Callable& f,
} }
// predicate implementation // predicate implementation
template <typename T_Arg, bool Default, typename Callable> template <typename T_Arg, bool N_Default, typename T_Callable>
bool AstNode::predicateImpl(ConstCorrectAstNode<T_Arg>* nodep, const Callable& p) { bool AstNode::predicateImpl(ConstCorrectAstNode<T_Arg>* nodep, const T_Callable& p) {
// Implementation similar to foreach, but abort traversal as soon as result is determined // Implementation similar to foreach, but abort traversal as soon as result is determined
using T_Arg_NonConst = typename std::remove_const<T_Arg>::type; using T_Arg_NonConst = typename std::remove_const<T_Arg>::type;
using Node = ConstCorrectAstNode<T_Arg>; using Node = ConstCorrectAstNode<T_Arg>;
@ -2951,7 +2953,7 @@ bool AstNode::predicateImpl(ConstCorrectAstNode<T_Arg>* nodep, const Callable& p
// Type test this node // Type test this node
if (AstNode::privateTypeTest<T_Arg_NonConst>(currp)) { if (AstNode::privateTypeTest<T_Arg_NonConst>(currp)) {
// Call the client function // Call the client function
if (p(static_cast<T_Arg*>(currp)) != Default) return true; if (p(static_cast<T_Arg*>(currp)) != N_Default) return true;
// Short circuit if iterating leaf nodes // Short circuit if iterating leaf nodes
if VL_CONSTEXPR_CXX17 (isLeaf<T_Arg_NonConst>()) return false; if VL_CONSTEXPR_CXX17 (isLeaf<T_Arg_NonConst>()) return false;
} }
@ -2968,7 +2970,7 @@ bool AstNode::predicateImpl(ConstCorrectAstNode<T_Arg>* nodep, const Callable& p
}; };
// Visit the root node // Visit the root node
if (visit(nodep)) return !Default; if (visit(nodep)) return !N_Default;
// Visit the rest of the tree // Visit the rest of the tree
while (VL_LIKELY(topp > basep)) { while (VL_LIKELY(topp > basep)) {
@ -2985,10 +2987,10 @@ bool AstNode::predicateImpl(ConstCorrectAstNode<T_Arg>* nodep, const Callable& p
if (headp->nextp()) *topp++ = headp->nextp(); if (headp->nextp()) *topp++ = headp->nextp();
// Visit the head node // Visit the head node
if (visit(headp)) return !Default; if (visit(headp)) return !N_Default;
} }
return Default; return N_Default;
} }
inline std::ostream& operator<<(std::ostream& os, const AstNode* rhs) { inline std::ostream& operator<<(std::ostream& os, const AstNode* rhs) {

View File

@ -2401,13 +2401,13 @@ public:
// Iterates top level members of the class, taking into account inheritance (starting from the // Iterates top level members of the class, taking into account inheritance (starting from the
// root superclass). Note: after V3Scope, several children are moved under an AstScope and will // root superclass). Note: after V3Scope, several children are moved under an AstScope and will
// not be found by this. // not be found by this.
template <typename Callable> template <typename T_Callable>
void foreachMember(const Callable& f) { void foreachMember(const T_Callable& f) {
using T_Node = typename FunctionArgNoPointerNoCV<Callable, 1>::type; using T_Node = typename FunctionArgNoPointerNoCV<T_Callable, 1>::type;
static_assert( static_assert(
vlstd::is_invocable<Callable, AstClass*, T_Node*>::value vlstd::is_invocable<T_Callable, AstClass*, T_Node*>::value
&& std::is_base_of<AstNode, T_Node>::value, && std::is_base_of<AstNode, T_Node>::value,
"Callable 'f' must have a signature compatible with 'void(AstClass*, T_Node*)', " "T_Callable 'f' must have a signature compatible with 'void(AstClass*, T_Node*)', "
"with 'T_Node' being a subtype of 'AstNode'"); "with 'T_Node' being a subtype of 'AstNode'");
if (AstClassExtends* const cextendsp = this->extendsp()) { if (AstClassExtends* const cextendsp = this->extendsp()) {
cextendsp->classp()->foreachMember(f); cextendsp->classp()->foreachMember(f);
@ -2417,13 +2417,14 @@ public:
} }
} }
// Same as above, but stops after first match // Same as above, but stops after first match
template <typename Callable> template <typename T_Callable>
bool existsMember(const Callable& p) const { bool existsMember(const T_Callable& p) const {
using T_Node = typename FunctionArgNoPointerNoCV<Callable, 1>::type; using T_Node = typename FunctionArgNoPointerNoCV<T_Callable, 1>::type;
static_assert(vlstd::is_invocable_r<bool, Callable, const AstClass*, const T_Node*>::value static_assert(
&& std::is_base_of<AstNode, T_Node>::value, vlstd::is_invocable_r<bool, T_Callable, const AstClass*, const T_Node*>::value
"Predicate 'p' must have a signature compatible with 'bool(const AstClass*, " && std::is_base_of<AstNode, T_Node>::value,
"const T_Node*)', with 'T_Node' being a subtype of 'AstNode'"); "Predicate 'p' must have a signature compatible with 'bool(const AstClass*, "
"const T_Node*)', with 'T_Node' being a subtype of 'AstNode'");
if (AstClassExtends* const cextendsp = this->extendsp()) { if (AstClassExtends* const cextendsp = this->extendsp()) {
if (cextendsp->classp()->existsMember(p)) return true; if (cextendsp->classp()->existsMember(p)) return true;
} }

View File

@ -27,22 +27,22 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
template <typename T_Node, typename T_Data, int T_UserN> template <typename T_Node, typename T_Data, int N_UserN>
class AstUserAllocatorBase VL_NOT_FINAL { class AstUserAllocatorBase VL_NOT_FINAL {
static_assert(1 <= T_UserN && T_UserN <= 4, "Wrong user pointer number"); static_assert(1 <= N_UserN && N_UserN <= 4, "Wrong user pointer number");
static_assert(std::is_base_of<AstNode, T_Node>::value, "T_Node must be an AstNode type"); static_assert(std::is_base_of<AstNode, T_Node>::value, "T_Node must be an AstNode type");
private: private:
std::deque<T_Data> m_allocated; std::deque<T_Data> m_allocated;
T_Data* getUserp(const T_Node* nodep) const { T_Data* getUserp(const T_Node* nodep) const {
if VL_CONSTEXPR_CXX17 (T_UserN == 1) { if VL_CONSTEXPR_CXX17 (N_UserN == 1) {
const VNUser user = nodep->user1u(); const VNUser user = nodep->user1u();
return user.to<T_Data*>(); return user.to<T_Data*>();
} else if VL_CONSTEXPR_CXX17 (T_UserN == 2) { } else if VL_CONSTEXPR_CXX17 (N_UserN == 2) {
const VNUser user = nodep->user2u(); const VNUser user = nodep->user2u();
return user.to<T_Data*>(); return user.to<T_Data*>();
} else if VL_CONSTEXPR_CXX17 (T_UserN == 3) { } else if VL_CONSTEXPR_CXX17 (N_UserN == 3) {
const VNUser user = nodep->user3u(); const VNUser user = nodep->user3u();
return user.to<T_Data*>(); return user.to<T_Data*>();
} else { } else {
@ -52,11 +52,11 @@ private:
} }
void setUserp(T_Node* nodep, T_Data* userp) const { void setUserp(T_Node* nodep, T_Data* userp) const {
if VL_CONSTEXPR_CXX17 (T_UserN == 1) { if VL_CONSTEXPR_CXX17 (N_UserN == 1) {
nodep->user1u(VNUser{userp}); nodep->user1u(VNUser{userp});
} else if VL_CONSTEXPR_CXX17 (T_UserN == 2) { } else if VL_CONSTEXPR_CXX17 (N_UserN == 2) {
nodep->user2u(VNUser{userp}); nodep->user2u(VNUser{userp});
} else if VL_CONSTEXPR_CXX17 (T_UserN == 3) { } else if VL_CONSTEXPR_CXX17 (N_UserN == 3) {
nodep->user3u(VNUser{userp}); nodep->user3u(VNUser{userp});
} else { } else {
nodep->user4u(VNUser{userp}); nodep->user4u(VNUser{userp});
@ -65,11 +65,11 @@ private:
protected: protected:
AstUserAllocatorBase() { AstUserAllocatorBase() {
if VL_CONSTEXPR_CXX17 (T_UserN == 1) { if VL_CONSTEXPR_CXX17 (N_UserN == 1) {
VNUser1InUse::check(); VNUser1InUse::check();
} else if VL_CONSTEXPR_CXX17 (T_UserN == 2) { } else if VL_CONSTEXPR_CXX17 (N_UserN == 2) {
VNUser2InUse::check(); VNUser2InUse::check();
} else if VL_CONSTEXPR_CXX17 (T_UserN == 3) { } else if VL_CONSTEXPR_CXX17 (N_UserN == 3) {
VNUser3InUse::check(); VNUser3InUse::check();
} else { } else {
VNUser4InUse::check(); VNUser4InUse::check();

View File

@ -534,17 +534,17 @@ class DelayedVisitor final : public VNVisitor {
} }
// Scheme::ValueQueuePartial/Scheme::ValueQueueWhole // Scheme::ValueQueuePartial/Scheme::ValueQueueWhole
template <bool Partial> template <bool N_Partial>
void prepareSchemeValueQueue(AstVarScope* vscp, VarScopeInfo& vscpInfo) { void prepareSchemeValueQueue(AstVarScope* vscp, VarScopeInfo& vscpInfo) {
UASSERT_OBJ(Partial ? vscpInfo.m_scheme == Scheme::ValueQueuePartial UASSERT_OBJ(N_Partial ? vscpInfo.m_scheme == Scheme::ValueQueuePartial
: vscpInfo.m_scheme == Scheme::ValueQueueWhole, : vscpInfo.m_scheme == Scheme::ValueQueueWhole,
vscp, "Inconsisten<t NBA s>cheme"); vscp, "Inconsisten<t NBA s>cheme");
FileLine* const flp = vscp->fileline(); FileLine* const flp = vscp->fileline();
AstScope* const scopep = vscp->scopep(); AstScope* const scopep = vscp->scopep();
// Create the commit queue variable // Create the commit queue variable
auto* const cqDTypep auto* const cqDTypep
= new AstNBACommitQueueDType{flp, vscp->dtypep()->skipRefp(), Partial}; = new AstNBACommitQueueDType{flp, vscp->dtypep()->skipRefp(), N_Partial};
v3Global.rootp()->typeTablep()->addTypesp(cqDTypep); v3Global.rootp()->typeTablep()->addTypesp(cqDTypep);
const std::string name = "__VdlyCommitQueue" + vscp->varp()->shortName(); const std::string name = "__VdlyCommitQueue" + vscp->varp()->shortName();
AstVarScope* const queueVscp = createTemp(flp, scopep, name, cqDTypep); AstVarScope* const queueVscp = createTemp(flp, scopep, name, cqDTypep);

View File

@ -427,52 +427,52 @@ public:
// Implementation of dataflow graph vertices with a fixed number of sources // Implementation of dataflow graph vertices with a fixed number of sources
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
template <size_t Arity> template <size_t N_Arity>
class DfgVertexWithArity VL_NOT_FINAL : public DfgVertex { class DfgVertexWithArity VL_NOT_FINAL : public DfgVertex {
static_assert(1 <= Arity && Arity <= 4, "Arity must be between 1 and 4 inclusive"); static_assert(1 <= N_Arity && N_Arity <= 4, "N_Arity must be between 1 and 4 inclusive");
std::array<DfgEdge, Arity> m_srcs; // Source edges std::array<DfgEdge, N_Arity> m_srcs; // Source edges
protected: protected:
DfgVertexWithArity(DfgGraph& dfg, VDfgType type, FileLine* flp, AstNodeDType* dtypep) DfgVertexWithArity(DfgGraph& dfg, VDfgType type, FileLine* flp, AstNodeDType* dtypep)
: DfgVertex{dfg, type, flp, dtypep} { : DfgVertex{dfg, type, flp, dtypep} {
// Initialize source edges // Initialize source edges
for (size_t i = 0; i < Arity; ++i) m_srcs[i].init(this); for (size_t i = 0; i < N_Arity; ++i) m_srcs[i].init(this);
} }
~DfgVertexWithArity() override = default; ~DfgVertexWithArity() override = default;
public: public:
std::pair<DfgEdge*, size_t> sourceEdges() final override { // std::pair<DfgEdge*, size_t> sourceEdges() final override { //
return {m_srcs.data(), Arity}; return {m_srcs.data(), N_Arity};
} }
std::pair<const DfgEdge*, size_t> sourceEdges() const final override { std::pair<const DfgEdge*, size_t> sourceEdges() const final override {
return {m_srcs.data(), Arity}; return {m_srcs.data(), N_Arity};
} }
template <size_t Index> template <size_t N_Index>
DfgEdge* sourceEdge() { DfgEdge* sourceEdge() {
static_assert(Index < Arity, "Source index out of range"); static_assert(N_Index < N_Arity, "Source index out of range");
return &m_srcs[Index]; return &m_srcs[N_Index];
} }
template <size_t Index> template <size_t N_Index>
const DfgEdge* sourceEdge() const { const DfgEdge* sourceEdge() const {
static_assert(Index < Arity, "Source index out of range"); static_assert(N_Index < N_Arity, "Source index out of range");
return &m_srcs[Index]; return &m_srcs[N_Index];
} }
template <size_t Index> template <size_t N_Index>
DfgVertex* source() const { DfgVertex* source() const {
static_assert(Index < Arity, "Source index out of range"); static_assert(N_Index < N_Arity, "Source index out of range");
return m_srcs[Index].sourcep(); return m_srcs[N_Index].sourcep();
} }
template <size_t Index> template <size_t N_Index>
void relinkSource(DfgVertex* newSourcep) { void relinkSource(DfgVertex* newSourcep) {
static_assert(Index < Arity, "Source index out of range"); static_assert(N_Index < N_Arity, "Source index out of range");
UASSERT_OBJ(m_srcs[Index].sinkp() == this, this, "Inconsistent"); UASSERT_OBJ(m_srcs[N_Index].sinkp() == this, this, "Inconsistent");
m_srcs[Index].relinkSource(newSourcep); m_srcs[N_Index].relinkSource(newSourcep);
} }
}; };

View File

@ -37,9 +37,9 @@ namespace {
// Create a DfgVertex out of a AstNodeExpr. For most AstNodeExpr subtypes, this can be done // Create a DfgVertex out of a AstNodeExpr. For most AstNodeExpr subtypes, this can be done
// automatically. For the few special cases, we provide specializations below // automatically. For the few special cases, we provide specializations below
template <typename Vertex, typename Node> template <typename T_Vertex, typename T_Node>
Vertex* makeVertex(const Node* nodep, DfgGraph& dfg) { T_Vertex* makeVertex(const T_Node* nodep, DfgGraph& dfg) {
return new Vertex{dfg, nodep->fileline(), DfgVertex::dtypeFor(nodep)}; return new T_Vertex{dfg, nodep->fileline(), DfgVertex::dtypeFor(nodep)};
} }
//====================================================================== //======================================================================

View File

@ -157,8 +157,8 @@ public:
}; };
}; };
template <typename Key, typename Val> template <typename T_Key, typename T_Val>
using Cache = std::unordered_map<Key, Val, typename Key::Hash, typename Key::Equal>; using Cache = std::unordered_map<T_Key, T_Val, typename T_Key::Hash, typename T_Key::Equal>;
using CacheSel = Cache<KeySel, DfgSel*>; using CacheSel = Cache<KeySel, DfgSel*>;
using CacheUnary = Cache<KeyUnary, DfgVertexUnary*>; using CacheUnary = Cache<KeyUnary, DfgVertexUnary*>;
@ -246,10 +246,10 @@ inline void setOperands(DfgVertexTernary* vtxp, DfgVertex* src0p, DfgVertex* src
} }
// Get or create (and insert) vertex with given operands // Get or create (and insert) vertex with given operands
template <typename Vertex, typename Cache, typename... Operands> template <typename Vertex, typename T_Cache, typename... Operands>
inline Vertex* getOrCreate(DfgGraph& dfg, FileLine* flp, AstNodeDType* dtypep, Cache& cache, inline Vertex* getOrCreate(DfgGraph& dfg, FileLine* flp, AstNodeDType* dtypep, T_Cache& cache,
Operands... operands) { Operands... operands) {
typename Cache::mapped_type& entrypr = getEntry(cache, dtypep, operands...); typename T_Cache::mapped_type& entrypr = getEntry(cache, dtypep, operands...);
if (!entrypr) { if (!entrypr) {
Vertex* const newp = new Vertex{dfg, flp, dtypep}; Vertex* const newp = new Vertex{dfg, flp, dtypep};
setOperands(newp, operands...); setOperands(newp, operands...);

View File

@ -40,9 +40,9 @@ namespace {
// Create an AstNodeExpr out of a DfgVertex. For most AstNodeExpr subtypes, this can be done // Create an AstNodeExpr out of a DfgVertex. For most AstNodeExpr subtypes, this can be done
// automatically. For the few special cases, we provide specializations below // automatically. For the few special cases, we provide specializations below
template <typename Node, typename Vertex, typename... Ops> template <typename T_Node, typename T_Vertex, typename... Ops>
Node* makeNode(const Vertex* vtxp, Ops... ops) { T_Node* makeNode(const T_Vertex* vtxp, Ops... ops) {
Node* const nodep = new Node{vtxp->fileline(), ops...}; T_Node* const nodep = new T_Node{vtxp->fileline(), ops...};
UASSERT_OBJ(nodep->width() == static_cast<int>(vtxp->width()), vtxp, UASSERT_OBJ(nodep->width() == static_cast<int>(vtxp->width()), vtxp,
"Incorrect width in AstNode created from DfgVertex " "Incorrect width in AstNode created from DfgVertex "
<< vtxp->typeName() << ": " << nodep->width() << " vs " << vtxp->width()); << vtxp->typeName() << ": " << nodep->width() << " vs " << vtxp->width());

View File

@ -146,8 +146,8 @@ public:
void emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* modp, bool cLinkage = false); void emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* modp, bool cLinkage = false);
void emitVarDecl(const AstVar* nodep, bool asRef = false); void emitVarDecl(const AstVar* nodep, bool asRef = false);
void emitVarAccessors(const AstVar* nodep); void emitVarAccessors(const AstVar* nodep);
template <typename F> template <typename T_Callable>
static void forModCUse(const AstNodeModule* modp, VUseType useType, F action) { static void forModCUse(const AstNodeModule* modp, VUseType useType, T_Callable action) {
for (AstNode* itemp = modp->stmtsp(); itemp; itemp = itemp->nextp()) { for (AstNode* itemp = modp->stmtsp(); itemp; itemp = itemp->nextp()) {
if (AstCUse* const usep = VN_CAST(itemp, CUse)) { if (AstCUse* const usep = VN_CAST(itemp, CUse)) {
if (usep->useType().containsAny(useType)) { if (usep->useType().containsAny(useType)) {

View File

@ -36,8 +36,8 @@ class CMakeEmitter final {
// STATIC FUNCTIONS // STATIC FUNCTIONS
// Concatenate all strings in 'strs' with ' ' between them. // Concatenate all strings in 'strs' with ' ' between them.
template <typename List> template <typename T_List>
static string cmake_list(const List& strs) { static string cmake_list(const T_List& strs) {
string s; string s;
for (auto it = strs.begin(); it != strs.end(); ++it) { for (auto it = strs.begin(); it != strs.end(); ++it) {
s += '"'; s += '"';

View File

@ -32,25 +32,25 @@ struct FunctionTraits final
: public FunctionTraits<decltype(&std::remove_reference<T>::type::operator())> {}; : public FunctionTraits<decltype(&std::remove_reference<T>::type::operator())> {};
// Specialization for pointers to member function // Specialization for pointers to member function
template <typename ClassType, typename ReturnType, typename... Args> template <typename T_ClassType, typename T_ReturnType, typename... Args>
struct FunctionTraits<ReturnType (ClassType::*)(Args...) const> VL_NOT_FINAL { struct FunctionTraits<T_ReturnType (T_ClassType::*)(Args...) const> VL_NOT_FINAL {
// Number of arguments // Number of arguments
static constexpr size_t arity = sizeof...(Args); static constexpr size_t arity = sizeof...(Args);
// Type of result // Type of result
using result_type = ReturnType; using result_type = T_ReturnType;
// Type of arguments // Type of arguments
template <std::size_t I> template <std::size_t N>
struct arg final { struct arg final {
using type = typename std::tuple_element<I, std::tuple<Args...>>::type; using type = typename std::tuple_element<N, std::tuple<Args...>>::type;
}; };
}; };
template <typename T_Callable, size_t index> template <typename T_Callable, size_t N_Index>
struct FunctionArgNoPointerNoCV final { struct FunctionArgNoPointerNoCV final {
using Traits = FunctionTraits<T_Callable>; using Traits = FunctionTraits<T_Callable>;
using T_Arg = typename Traits::template arg<index>::type; using T_Arg = typename Traits::template arg<N_Index>::type;
using T_ArgNoPtr = typename std::remove_pointer<T_Arg>::type; using T_ArgNoPtr = typename std::remove_pointer<T_Arg>::type;
using type = typename std::remove_cv<T_ArgNoPtr>::type; using type = typename std::remove_cv<T_ArgNoPtr>::type;
}; };

View File

@ -79,12 +79,12 @@ void V3GraphVertex::rerouteEdges(V3Graph* graphp) {
unlinkEdges(graphp); unlinkEdges(graphp);
} }
template <GraphWay::en T_Way> template <GraphWay::en N_Way>
V3GraphEdge* V3GraphVertex::findConnectingEdgep(V3GraphVertex* waywardp) { V3GraphEdge* V3GraphVertex::findConnectingEdgep(V3GraphVertex* waywardp) {
// O(edges) linear search. Searches search both nodes' edge lists in // O(edges) linear search. Searches search both nodes' edge lists in
// parallel. The lists probably aren't _both_ huge, so this is // parallel. The lists probably aren't _both_ huge, so this is
// unlikely to blow up even on fairly nasty graphs. // unlikely to blow up even on fairly nasty graphs.
constexpr GraphWay way{T_Way}; constexpr GraphWay way{N_Way};
constexpr GraphWay inv = way.invert(); constexpr GraphWay inv = way.invert();
auto& aEdges = this->edges<way>(); auto& aEdges = this->edges<way>();
auto aIt = aEdges.begin(); auto aIt = aEdges.begin();

View File

@ -187,9 +187,9 @@ public:
uint64_t user() const { return m_user; } uint64_t user() const { return m_user; }
V3GraphVertex* fromp() const { return m_fromp; } V3GraphVertex* fromp() const { return m_fromp; }
V3GraphVertex* top() const { return m_top; } V3GraphVertex* top() const { return m_top; }
template <GraphWay::en T_Way> template <GraphWay::en N_Way>
V3GraphVertex* furtherp() const { V3GraphVertex* furtherp() const {
return T_Way == GraphWay::FORWARD ? top() : fromp(); return N_Way == GraphWay::FORWARD ? top() : fromp();
} }
// STATIC ACCESSORS // STATIC ACCESSORS
static bool followNotCutable(const V3GraphEdge* edgep) { return !edgep->m_cutable; } static bool followNotCutable(const V3GraphEdge* edgep) { return !edgep->m_cutable; }
@ -301,9 +301,9 @@ public:
void* userp() const VL_MT_STABLE { return m_userp; } void* userp() const VL_MT_STABLE { return m_userp; }
V3GraphEdge::IList& inEdges() { return m_ins; } V3GraphEdge::IList& inEdges() { return m_ins; }
const V3GraphEdge::IList& inEdges() const { return m_ins; } const V3GraphEdge::IList& inEdges() const { return m_ins; }
template <GraphWay::en T_Way> template <GraphWay::en N_Way>
inline auto& edges(); inline auto& edges();
template <GraphWay::en T_Way> template <GraphWay::en N_Way>
inline const auto& edges() const; inline const auto& edges() const;
bool inEmpty() const { return m_ins.empty(); } bool inEmpty() const { return m_ins.empty(); }
bool inSize1() const { return m_ins.hasSingleElement(); } bool inSize1() const { return m_ins.hasSingleElement(); }
@ -320,7 +320,7 @@ public:
void rerouteEdges(V3Graph* graphp) VL_MT_DISABLED; void rerouteEdges(V3Graph* graphp) VL_MT_DISABLED;
// Find the edge connecting this vertex to the given vertex. // Find the edge connecting this vertex to the given vertex.
// If edge is not found returns nullptr. O(edges) performance. // If edge is not found returns nullptr. O(edges) performance.
template <GraphWay::en T_Way> template <GraphWay::en N_Way>
V3GraphEdge* findConnectingEdgep(V3GraphVertex* otherp) VL_MT_DISABLED; V3GraphEdge* findConnectingEdgep(V3GraphVertex* otherp) VL_MT_DISABLED;
}; };

View File

@ -53,9 +53,9 @@ struct GraphPCNode final {
//###################################################################### //######################################################################
// GraphPathChecker implementation // GraphPathChecker implementation
template <GraphWay::en T_Way> template <GraphWay::en N_Way>
void GraphPathChecker::initHalfCriticalPaths(bool checkOnly) { void GraphPathChecker::initHalfCriticalPaths(bool checkOnly) {
constexpr GraphWay way{T_Way}; constexpr GraphWay way{N_Way};
constexpr GraphWay rev = way.invert(); constexpr GraphWay rev = way.invert();
GraphStreamUnordered order(m_graphp, way); GraphStreamUnordered order(m_graphp, way);
while (const V3GraphVertex* const vertexp = order.nextp()) { while (const V3GraphVertex* const vertexp = order.nextp()) {

View File

@ -53,7 +53,7 @@ public:
private: private:
bool pathExistsInternal(const V3GraphVertex* ap, const V3GraphVertex* bp, bool pathExistsInternal(const V3GraphVertex* ap, const V3GraphVertex* bp,
unsigned* costp = nullptr) VL_MT_DISABLED; unsigned* costp = nullptr) VL_MT_DISABLED;
template <GraphWay::en T_Way> template <GraphWay::en N_Way>
void initHalfCriticalPaths(bool checkOnly) VL_MT_DISABLED; void initHalfCriticalPaths(bool checkOnly) VL_MT_DISABLED;
void incGeneration() { ++m_generation; } void incGeneration() { ++m_generation; }

View File

@ -264,9 +264,9 @@ public:
} }
private: private:
template <uint8_t T_Way> // template <uint8_t N_Way> //
VL_ATTR_NOINLINE void init(V3Graph* graphp) { VL_ATTR_NOINLINE void init(V3Graph* graphp) {
constexpr GraphWay way{T_Way}; constexpr GraphWay way{N_Way};
// Assign every vertex without an incoming edge to ready, others to waiting // Assign every vertex without an incoming edge to ready, others to waiting
for (V3GraphVertex& vertex : graphp->vertices()) { for (V3GraphVertex& vertex : graphp->vertices()) {
const uint32_t nDeps = vertex.edges<way.invert()>().size(); const uint32_t nDeps = vertex.edges<way.invert()>().size();
@ -275,9 +275,9 @@ private:
} }
} }
template <uint8_t T_Way> // template <uint8_t N_Way> //
VL_ATTR_NOINLINE const V3GraphVertex* unblock(const V3GraphVertex* resultp) { VL_ATTR_NOINLINE const V3GraphVertex* unblock(const V3GraphVertex* resultp) {
constexpr GraphWay way{T_Way}; constexpr GraphWay way{N_Way};
for (const V3GraphEdge& edge : resultp->edges<way>()) { for (const V3GraphEdge& edge : resultp->edges<way>()) {
V3GraphVertex* const vertexp = edge.furtherp<way>(); V3GraphVertex* const vertexp = edge.furtherp<way>();
#if VL_DEBUG #if VL_DEBUG

View File

@ -89,7 +89,7 @@ class V3List final {
// Iterator class template for V3List. This is just enough to support range based for loops // Iterator class template for V3List. This is just enough to support range based for loops
// and basic usage. Feel free to extend as required. // and basic usage. Feel free to extend as required.
template <typename T_IteratorElement, bool T_Reverse> template <typename T_IteratorElement, bool N_Reverse>
class SimpleItertatorImpl final { class SimpleItertatorImpl final {
static_assert(std::is_same<T_IteratorElement, T_Element>::value static_assert(std::is_same<T_IteratorElement, T_Element>::value
|| std::is_same<T_IteratorElement, const T_Element>::value, || std::is_same<T_IteratorElement, const T_Element>::value,
@ -99,7 +99,7 @@ class V3List final {
template <typename B, V3ListLinks<B>& (B::*)(), typename> template <typename B, V3ListLinks<B>& (B::*)(), typename>
friend class V3List; friend class V3List;
using IteratorType = SimpleItertatorImpl<T_IteratorElement, T_Reverse>; using IteratorType = SimpleItertatorImpl<T_IteratorElement, N_Reverse>;
T_Base* m_currp; // Currently iterated element, or 'nullptr' for 'end()' iterator T_Base* m_currp; // Currently iterated element, or 'nullptr' for 'end()' iterator
@ -109,7 +109,7 @@ class V3List final {
VL_ATTR_ALWINLINE VL_ATTR_ALWINLINE
static T_Base* step(T_Base* currp) { static T_Base* step(T_Base* currp) {
if VL_CONSTEXPR_CXX17 (T_Reverse) { if VL_CONSTEXPR_CXX17 (N_Reverse) {
return toLinks(currp).m_prevp; return toLinks(currp).m_prevp;
} else { } else {
return toLinks(currp).m_nextp; return toLinks(currp).m_nextp;
@ -145,8 +145,8 @@ class V3List final {
bool operator!=(const IteratorType& other) const { return m_currp != other.m_currp; } bool operator!=(const IteratorType& other) const { return m_currp != other.m_currp; }
// Convert to const iterator // Convert to const iterator
VL_ATTR_ALWINLINE VL_ATTR_ALWINLINE
operator SimpleItertatorImpl<const T_IteratorElement, T_Reverse>() const { operator SimpleItertatorImpl<const T_IteratorElement, N_Reverse>() const {
return SimpleItertatorImpl<const T_IteratorElement, T_Reverse>{m_currp}; return SimpleItertatorImpl<const T_IteratorElement, N_Reverse>{m_currp};
} }
}; };
@ -221,10 +221,10 @@ class V3List final {
}; };
public: public:
using iterator = SimpleItertatorImpl<T_Element, /* T_Reverse: */ false>; using iterator = SimpleItertatorImpl<T_Element, /* N_Reverse: */ false>;
using const_iterator = SimpleItertatorImpl<const T_Element, /* T_Reverse: */ false>; using const_iterator = SimpleItertatorImpl<const T_Element, /* N_Reverse: */ false>;
using reverse_iterator = SimpleItertatorImpl<T_Element, /* T_Reverse: */ true>; using reverse_iterator = SimpleItertatorImpl<T_Element, /* N_Reverse: */ true>;
using const_reverse_iterator = SimpleItertatorImpl<const T_Element, /* T_Reverse: */ true>; using const_reverse_iterator = SimpleItertatorImpl<const T_Element, /* N_Reverse: */ true>;
// CONSTRUCTOR // CONSTRUCTOR
V3List() = default; V3List() = default;

View File

@ -37,14 +37,14 @@ struct V3OptionParser::Impl final {
VALUE // "-opt val" VALUE // "-opt val"
}; };
// Base class of actual action classes // Base class of actual action classes
template <en MODE, bool ALLOW_PARTIAL_MATCH = false> template <en N_Mode, bool N_Allow_Partial_Match = false>
class ActionBase VL_NOT_FINAL : public ActionIfs { class ActionBase VL_NOT_FINAL : public ActionIfs {
bool m_undocumented = false; // This option is not documented bool m_undocumented = false; // This option is not documented
public: public:
bool isValueNeeded() const override final { return MODE == en::VALUE; } bool isValueNeeded() const override final { return N_Mode == en::VALUE; }
bool isFOnOffAllowed() const override final { return MODE == en::FONOFF; } bool isFOnOffAllowed() const override final { return N_Mode == en::FONOFF; }
bool isOnOffAllowed() const override final { return MODE == en::ONOFF; } bool isOnOffAllowed() const override final { return N_Mode == en::ONOFF; }
bool isPartialMatchAllowed() const override final { return ALLOW_PARTIAL_MATCH; } bool isPartialMatchAllowed() const override final { return N_Allow_Partial_Match; }
bool isUndocumented() const override { return m_undocumented; } bool isUndocumented() const override { return m_undocumented; }
void undocumented() override { m_undocumented = true; } void undocumented() override { m_undocumented = true; }
}; };
@ -52,9 +52,9 @@ struct V3OptionParser::Impl final {
// Actual action classes // Actual action classes
template <typename T> template <typename T>
class ActionSet; // "-opt" for bool-ish, "-opt val" for int and string class ActionSet; // "-opt" for bool-ish, "-opt val" for int and string
template <typename BOOL> template <typename N_Bool>
class ActionFOnOff; // "-fopt" and "-fno-opt" for bool-ish class ActionFOnOff; // "-fopt" and "-fno-opt" for bool-ish
template <typename BOOL> template <typename N_Bool>
class ActionOnOff; // "-opt" and "-no-opt" for bool-ish class ActionOnOff; // "-opt" and "-no-opt" for bool-ish
class ActionCbCall; // Callback without argument for "-opt" class ActionCbCall; // Callback without argument for "-opt"
class ActionCbFOnOff; // Callback for "-fopt" and "-fno-opt" class ActionCbFOnOff; // Callback for "-fopt" and "-fno-opt"
@ -171,10 +171,10 @@ V3OptionParser::ActionIfs* V3OptionParser::find(const char* optp) {
return nullptr; return nullptr;
} }
template <typename ACT, typename ARG> template <typename T_Act, typename T_Arg>
V3OptionParser::ActionIfs& V3OptionParser::add(const std::string& opt, ARG arg) { V3OptionParser::ActionIfs& V3OptionParser::add(const std::string& opt, T_Arg arg) {
UASSERT(!m_pimpl->m_isFinalized, "Cannot add after finalize() is called"); UASSERT(!m_pimpl->m_isFinalized, "Cannot add after finalize() is called");
std::unique_ptr<ACT> act{new ACT{std::move(arg)}}; std::unique_ptr<T_Act> act{new T_Act{std::move(arg)}};
UASSERT(opt.size() >= 2, opt << " is too short"); UASSERT(opt.size() >= 2, opt << " is too short");
UASSERT(opt[0] == '-' || opt[0] == '+', opt << " does not start with either '-' or '+'"); UASSERT(opt[0] == '-' || opt[0] == '+', opt << " does not start with either '-' or '+'");
UASSERT(!(opt[0] == '-' && opt[1] == '-'), "Option must have single '-', but " << opt); UASSERT(!(opt[0] == '-' && opt[1] == '-'), "Option must have single '-', but " << opt);

View File

@ -65,8 +65,8 @@ private:
// METHODS // METHODS
ActionIfs* find(const char* optp) VL_MT_DISABLED; ActionIfs* find(const char* optp) VL_MT_DISABLED;
template <typename ACT, typename ARG> template <typename T_Act, typename T_Arg>
ActionIfs& add(const string& opt, ARG arg) VL_MT_DISABLED; ActionIfs& add(const string& opt, T_Arg arg) VL_MT_DISABLED;
// Returns true if strp starts with "-fno" // Returns true if strp starts with "-fno"
static bool hasPrefixFNo(const char* strp) VL_MT_DISABLED; static bool hasPrefixFNo(const char* strp) VL_MT_DISABLED;
// Returns true if strp starts with "-no" // Returns true if strp starts with "-no"

View File

@ -268,7 +268,7 @@ static_assert(!std::is_polymorphic<SiblingMC>::value, "Should not have a vtable"
class MTaskEdge final : public V3GraphEdge, public MergeCandidate { class MTaskEdge final : public V3GraphEdge, public MergeCandidate {
VL_RTTI_IMPL(MTaskEdge, V3GraphEdge) VL_RTTI_IMPL(MTaskEdge, V3GraphEdge)
friend class LogicMTask; friend class LogicMTask;
template <GraphWay::en T_Way> template <GraphWay::en N_Way>
friend class PropagateCp; friend class PropagateCp;
// MEMBERS // MEMBERS
@ -280,7 +280,7 @@ public:
// CONSTRUCTORS // CONSTRUCTORS
MTaskEdge(V3Graph* graphp, LogicMTask* fromp, LogicMTask* top, int weight); MTaskEdge(V3Graph* graphp, LogicMTask* fromp, LogicMTask* top, int weight);
// METHODS // METHODS
template <GraphWay::en T_Way> template <GraphWay::en N_Way>
inline LogicMTask* furtherMTaskp() const; inline LogicMTask* furtherMTaskp() const;
inline LogicMTask* fromMTaskp() const; inline LogicMTask* fromMTaskp() const;
inline LogicMTask* toMTaskp() const; inline LogicMTask* toMTaskp() const;
@ -307,7 +307,7 @@ private:
class LogicMTask final : public V3GraphVertex { class LogicMTask final : public V3GraphVertex {
VL_RTTI_IMPL(LogicMTask, V3GraphVertex) VL_RTTI_IMPL(LogicMTask, V3GraphVertex)
template <GraphWay::en T_Way> template <GraphWay::en N_Way>
friend class PropagateCp; friend class PropagateCp;
public: public:
@ -419,28 +419,28 @@ public:
#endif #endif
} }
template <GraphWay::en T_Way> template <GraphWay::en N_Way>
void addRelativeEdge(MTaskEdge* edgep) { void addRelativeEdge(MTaskEdge* edgep) {
constexpr GraphWay way{T_Way}; constexpr GraphWay way{N_Way};
constexpr GraphWay inv = way.invert(); constexpr GraphWay inv = way.invert();
// Add to the edge heap // Add to the edge heap
LogicMTask* const relativep = edgep->furtherMTaskp<T_Way>(); LogicMTask* const relativep = edgep->furtherMTaskp<N_Way>();
// Value is !way cp to this edge // Value is !way cp to this edge
const uint32_t cp = relativep->stepCost() + relativep->critPathCost(inv); const uint32_t cp = relativep->stepCost() + relativep->critPathCost(inv);
// //
m_edgeHeap[way].insert(&edgep->m_edgeHeapNode[way], {relativep->id(), cp}); m_edgeHeap[way].insert(&edgep->m_edgeHeapNode[way], {relativep->id(), cp});
} }
template <GraphWay::en T_Way> template <GraphWay::en N_Way>
void stealRelativeEdge(MTaskEdge* edgep) { void stealRelativeEdge(MTaskEdge* edgep) {
constexpr GraphWay way{T_Way}; constexpr GraphWay way{N_Way};
// Make heap node insertable, ruining the heap it is currently in. // Make heap node insertable, ruining the heap it is currently in.
edgep->m_edgeHeapNode[way].yank(); edgep->m_edgeHeapNode[way].yank();
// Add the edge as new // Add the edge as new
addRelativeEdge<T_Way>(edgep); addRelativeEdge<N_Way>(edgep);
} }
template <GraphWay::en T_Way> template <GraphWay::en N_Way>
void removeRelativeEdge(MTaskEdge* edgep) { void removeRelativeEdge(MTaskEdge* edgep) {
constexpr GraphWay way{T_Way}; constexpr GraphWay way{N_Way};
// Remove from the edge heap // Remove from the edge heap
m_edgeHeap[way].remove(&edgep->m_edgeHeapNode[way]); m_edgeHeap[way].remove(&edgep->m_edgeHeapNode[way]);
} }
@ -456,12 +456,12 @@ public:
} }
bool hasRelativeMTask(LogicMTask* relativep) const { return m_edgeSet.count(relativep); } bool hasRelativeMTask(LogicMTask* relativep) const { return m_edgeSet.count(relativep); }
template <GraphWay::en T_Way> template <GraphWay::en N_Way>
void checkRelativesCp() const { void checkRelativesCp() const {
constexpr GraphWay way{T_Way}; constexpr GraphWay way{N_Way};
for (const V3GraphEdge& edge : edges<T_Way>()) { for (const V3GraphEdge& edge : edges<N_Way>()) {
const LogicMTask* const relativep const LogicMTask* const relativep
= static_cast<const LogicMTask*>(edge.furtherp<T_Way>()); = static_cast<const LogicMTask*>(edge.furtherp<N_Way>());
const uint32_t cachedCp = static_cast<const MTaskEdge&>(edge).cachedCp(way); const uint32_t cachedCp = static_cast<const MTaskEdge&>(edge).cachedCp(way);
const uint32_t cp = relativep->critPathCost(way.invert()) + relativep->stepCost(); const uint32_t cp = relativep->critPathCost(way.invert()) + relativep->stepCost();
partCheckCachedScoreVsActual(cachedCp, cp); partCheckCachedScoreVsActual(cachedCp, cp);
@ -479,14 +479,14 @@ public:
void setCritPathCost(GraphWay way, uint32_t cost) { m_critPathCost[way] = cost; } void setCritPathCost(GraphWay way, uint32_t cost) { m_critPathCost[way] = cost; }
uint32_t critPathCost(GraphWay way) const { return m_critPathCost[way]; } uint32_t critPathCost(GraphWay way) const { return m_critPathCost[way]; }
template <GraphWay::en T_Way> template <GraphWay::en N_Way>
uint32_t critPathCostWithout(const V3GraphEdge* withoutp) const { uint32_t critPathCostWithout(const V3GraphEdge* withoutp) const {
const GraphWay way{T_Way}; const GraphWay way{N_Way};
const GraphWay inv = way.invert(); const GraphWay inv = way.invert();
// Compute the critical path cost wayward to this node, without considering edge // Compute the critical path cost wayward to this node, without considering edge
// 'withoutp'. We need to look at two edges at most, the critical path if that is not via // 'withoutp'. We need to look at two edges at most, the critical path if that is not via
// 'withoutp', or the second-worst path, if the critical path is via 'withoutp'. // 'withoutp', or the second-worst path, if the critical path is via 'withoutp'.
UDEBUGONLY(UASSERT(withoutp->furtherp<T_Way>() == this, UDEBUGONLY(UASSERT(withoutp->furtherp<N_Way>() == this,
"In critPathCostWithout(), edge 'withoutp' must further to 'this'");); "In critPathCostWithout(), edge 'withoutp' must further to 'this'"););
const EdgeHeap& edgeHeap = m_edgeHeap[inv]; const EdgeHeap& edgeHeap = m_edgeHeap[inv];
const EdgeHeap::Node* const maxp = edgeHeap.max(); const EdgeHeap::Node* const maxp = edgeHeap.max();
@ -690,9 +690,9 @@ MTaskEdge::MTaskEdge(V3Graph* graphp, LogicMTask* fromp, LogicMTask* top, int we
top->addRelativeEdge<GraphWay::REVERSE>(this); top->addRelativeEdge<GraphWay::REVERSE>(this);
} }
template <GraphWay::en T_Way> template <GraphWay::en N_Way>
LogicMTask* MTaskEdge::furtherMTaskp() const { LogicMTask* MTaskEdge::furtherMTaskp() const {
return static_cast<LogicMTask*>(this->furtherp<T_Way>()); return static_cast<LogicMTask*>(this->furtherp<N_Way>());
} }
LogicMTask* MTaskEdge::fromMTaskp() const { return static_cast<LogicMTask*>(fromp()); } LogicMTask* MTaskEdge::fromMTaskp() const { return static_cast<LogicMTask*>(fromp()); }
LogicMTask* MTaskEdge::toMTaskp() const { return static_cast<LogicMTask*>(top()); } LogicMTask* MTaskEdge::toMTaskp() const { return static_cast<LogicMTask*>(top()); }
@ -716,9 +716,9 @@ void MTaskEdge::resetCriticalPaths() {
// Look at vertex costs (in one way) to form critical paths for each // Look at vertex costs (in one way) to form critical paths for each
// vertex. // vertex.
template <GraphWay::en T_Way> template <GraphWay::en N_Way>
static void partInitHalfCriticalPaths(V3Graph& mTaskGraph, bool checkOnly) { static void partInitHalfCriticalPaths(V3Graph& mTaskGraph, bool checkOnly) {
constexpr GraphWay way{T_Way}; constexpr GraphWay way{N_Way};
constexpr GraphWay rev = way.invert(); constexpr GraphWay rev = way.invert();
GraphStreamUnordered order{&mTaskGraph, way}; GraphStreamUnordered order{&mTaskGraph, way};
for (const V3GraphVertex* vertexp; (vertexp = order.nextp());) { for (const V3GraphVertex* vertexp; (vertexp = order.nextp());) {
@ -776,7 +776,7 @@ static void partCheckCriticalPaths(V3Graph& mTaskGraph) {
// ###################################################################### // ######################################################################
// PropagateCp // PropagateCp
template <GraphWay::en T_Way> template <GraphWay::en N_Way>
class PropagateCp final { class PropagateCp final {
// Propagate increasing critical path (CP) costs through a graph. // Propagate increasing critical path (CP) costs through a graph.
// //
@ -862,7 +862,7 @@ private:
public: public:
void cpHasIncreased(V3GraphVertex* vxp, uint32_t newInclusiveCp) { void cpHasIncreased(V3GraphVertex* vxp, uint32_t newInclusiveCp) {
constexpr GraphWay way{T_Way}; constexpr GraphWay way{N_Way};
constexpr GraphWay inv{way.invert()}; constexpr GraphWay inv{way.invert()};
// For *vxp, whose CP-inclusive has just increased to // For *vxp, whose CP-inclusive has just increased to
@ -871,7 +871,7 @@ public:
for (V3GraphEdge& graphEdge : vxp->edges<way>()) { for (V3GraphEdge& graphEdge : vxp->edges<way>()) {
MTaskEdge& edge = static_cast<MTaskEdge&>(graphEdge); MTaskEdge& edge = static_cast<MTaskEdge&>(graphEdge);
LogicMTask* const relativep = edge.furtherMTaskp<T_Way>(); LogicMTask* const relativep = edge.furtherMTaskp<N_Way>();
EdgeHeap::Node& edgeHeapNode = edge.m_edgeHeapNode[inv]; EdgeHeap::Node& edgeHeapNode = edge.m_edgeHeapNode[inv];
if (newInclusiveCp > edgeHeapNode.key().m_score) { if (newInclusiveCp > edgeHeapNode.key().m_score) {
relativep->m_edgeHeap[inv].increaseKey(&edgeHeapNode, newInclusiveCp); relativep->m_edgeHeap[inv].increaseKey(&edgeHeapNode, newInclusiveCp);
@ -899,7 +899,7 @@ public:
} }
void go() { void go() {
constexpr GraphWay way{T_Way}; constexpr GraphWay way{N_Way};
constexpr GraphWay inv{way.invert()}; constexpr GraphWay inv{way.invert()};
// m_pending maps each pending vertex to the amount that it wayward // m_pending maps each pending vertex to the amount that it wayward
@ -982,7 +982,7 @@ public:
partInitCriticalPaths(graph); partInitCriticalPaths(graph);
PropagateCp<T_Way> prop{true}; PropagateCp<N_Way> prop{true};
// Seed the propagator with every input node; // Seed the propagator with every input node;
// This should result in the complete graph getting all CP's assigned. // This should result in the complete graph getting all CP's assigned.
@ -1316,9 +1316,9 @@ public:
} }
private: private:
template <GraphWay::en T_Way> template <GraphWay::en N_Way>
NewCp newCp(LogicMTask* mtaskp, LogicMTask* otherp, MTaskEdge* mergeEdgep) { NewCp newCp(LogicMTask* mtaskp, LogicMTask* otherp, MTaskEdge* mergeEdgep) {
constexpr GraphWay way{T_Way}; constexpr GraphWay way{N_Way};
// Return new wayward-CP for mtaskp reflecting its upcoming merge // Return new wayward-CP for mtaskp reflecting its upcoming merge
// with otherp. Set 'result.propagate' if mtaskp's wayward // with otherp. Set 'result.propagate' if mtaskp's wayward
// relatives will see a new wayward CP from this merge. // relatives will see a new wayward CP from this merge.
@ -1528,9 +1528,9 @@ private:
} }
} }
template <GraphWay::en T_Way, bool Exhaustive> template <GraphWay::en N_Way, bool N_Exhaustive>
void siblingPairFromRelatives(V3GraphVertex* mtaskp) { void siblingPairFromRelatives(V3GraphVertex* mtaskp) {
constexpr GraphWay way{T_Way}; constexpr GraphWay way{N_Way};
// Need at least 2 edges // Need at least 2 edges
auto& edges = mtaskp->edges<way>(); auto& edges = mtaskp->edges<way>();
if (!edges.hasMultipleElements()) return; if (!edges.hasMultipleElements()) return;
@ -1575,7 +1575,7 @@ private:
// Just make a few pairs. // Just make a few pairs.
constexpr size_t MAX_NONEXHAUSTIVE_PAIRS = 3; constexpr size_t MAX_NONEXHAUSTIVE_PAIRS = 3;
if (Exhaustive || n <= 2 * MAX_NONEXHAUSTIVE_PAIRS) { if (N_Exhaustive || n <= 2 * MAX_NONEXHAUSTIVE_PAIRS) {
const size_t end = n & ~static_cast<size_t>(1); // Round down to even, (we want pairs) const size_t end = n & ~static_cast<size_t>(1); // Round down to even, (we want pairs)
std::sort(sortRecs.begin(), sortRecs.begin() + n); std::sort(sortRecs.begin(), sortRecs.begin() + n);
for (size_t i = 0; i < end; i += 2) { for (size_t i = 0; i < end; i += 2) {

View File

@ -934,14 +934,14 @@ class CaptureVisitor final : public VNVisitor {
return false; return false;
} }
template <typename NodeT> template <typename T_Node>
void fixupClassOrPackage(AstNode* memberp, NodeT refp) { void fixupClassOrPackage(AstNode* memberp, T_Node refp) {
AstNodeModule* const declClassp = VN_AS(memberp->user2p(), NodeModule); AstNodeModule* const declClassp = VN_AS(memberp->user2p(), NodeModule);
if (declClassp != m_targetp) refp->classOrPackagep(declClassp); if (declClassp != m_targetp) refp->classOrPackagep(declClassp);
} }
template <typename NodeT> template <typename T_Node>
bool isReferenceToInnerMember(NodeT nodep) { bool isReferenceToInnerMember(T_Node nodep) {
return VN_IS(nodep->fromp(), LambdaArgRef); return VN_IS(nodep->fromp(), LambdaArgRef);
} }

View File

@ -233,8 +233,8 @@ class TimingSuspendableVisitor final : public VNVisitor {
if (passFlag(parentp, depp, flag)) propagateFlags(depVxp, flag); if (passFlag(parentp, depp, flag)) propagateFlags(depVxp, flag);
} }
} }
template <typename Predicate> template <typename T_Predicate>
void propagateFlagsIf(DepVtx* const vxp, NodeFlag flag, Predicate p) { void propagateFlagsIf(DepVtx* const vxp, NodeFlag flag, T_Predicate p) {
auto* const parentp = vxp->nodep(); auto* const parentp = vxp->nodep();
for (V3GraphEdge& edge : vxp->outEdges()) { for (V3GraphEdge& edge : vxp->outEdges()) {
auto* const depVxp = static_cast<DepVtx*>(edge.top()); auto* const depVxp = static_cast<DepVtx*>(edge.top());
@ -242,8 +242,8 @@ class TimingSuspendableVisitor final : public VNVisitor {
if (p(&edge) && passFlag(parentp, depp, flag)) propagateFlagsIf(depVxp, flag, p); if (p(&edge) && passFlag(parentp, depp, flag)) propagateFlagsIf(depVxp, flag, p);
} }
} }
template <typename Predicate> template <typename T_Predicate>
void propagateFlagsReversedIf(DepVtx* const vxp, NodeFlag flag, Predicate p) { void propagateFlagsReversedIf(DepVtx* const vxp, NodeFlag flag, T_Predicate p) {
auto* const parentp = vxp->nodep(); auto* const parentp = vxp->nodep();
for (V3GraphEdge& edge : vxp->inEdges()) { for (V3GraphEdge& edge : vxp->inEdges()) {
auto* const depVxp = static_cast<DepVtx*>(edge.fromp()); auto* const depVxp = static_cast<DepVtx*>(edge.fromp());