mirror of
https://github.com/verilator/verilator.git
synced 2024-12-29 10:47:34 +00:00
Internals: Standardize template argument names. No functional change.
This commit is contained in:
parent
990ccd6763
commit
0c820c3068
@ -1604,26 +1604,26 @@ static inline IData VL_PACK_II(int obits, int lbits, const VlQueue<IData>& q) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth>
|
||||
static inline IData VL_PACK_II(int obits, int lbits, const VlUnpacked<CData, T_Depth>& q) {
|
||||
template <std::size_t N_Depth>
|
||||
static inline IData VL_PACK_II(int obits, int lbits, const VlUnpacked<CData, N_Depth>& q) {
|
||||
IData ret = 0;
|
||||
for (size_t i = 0; i < T_Depth; ++i)
|
||||
ret |= static_cast<IData>(q[T_Depth - 1 - i]) << (i * lbits);
|
||||
for (size_t i = 0; i < N_Depth; ++i)
|
||||
ret |= static_cast<IData>(q[N_Depth - 1 - i]) << (i * lbits);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth>
|
||||
static inline IData VL_PACK_II(int obits, int lbits, const VlUnpacked<SData, T_Depth>& q) {
|
||||
template <std::size_t N_Depth>
|
||||
static inline IData VL_PACK_II(int obits, int lbits, const VlUnpacked<SData, N_Depth>& q) {
|
||||
IData ret = 0;
|
||||
for (size_t i = 0; i < T_Depth; ++i)
|
||||
ret |= static_cast<IData>(q[T_Depth - 1 - i]) << (i * lbits);
|
||||
for (size_t i = 0; i < N_Depth; ++i)
|
||||
ret |= static_cast<IData>(q[N_Depth - 1 - i]) << (i * lbits);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth>
|
||||
static inline IData VL_PACK_II(int obits, int lbits, const VlUnpacked<IData, T_Depth>& q) {
|
||||
template <std::size_t N_Depth>
|
||||
static inline IData VL_PACK_II(int obits, int lbits, const VlUnpacked<IData, N_Depth>& q) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1645,27 +1645,27 @@ static inline QData VL_PACK_QI(int obits, int lbits, const VlQueue<IData>& q) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth>
|
||||
static inline QData VL_PACK_QI(int obits, int lbits, const VlUnpacked<CData, T_Depth>& q) {
|
||||
template <std::size_t N_Depth>
|
||||
static inline QData VL_PACK_QI(int obits, int lbits, const VlUnpacked<CData, N_Depth>& q) {
|
||||
QData ret = 0;
|
||||
for (size_t i = 0; i < T_Depth; ++i)
|
||||
ret |= static_cast<QData>(q[T_Depth - 1 - i]) << (i * lbits);
|
||||
for (size_t i = 0; i < N_Depth; ++i)
|
||||
ret |= static_cast<QData>(q[N_Depth - 1 - i]) << (i * lbits);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth>
|
||||
static inline QData VL_PACK_QI(int obits, int lbits, const VlUnpacked<SData, T_Depth>& q) {
|
||||
template <std::size_t N_Depth>
|
||||
static inline QData VL_PACK_QI(int obits, int lbits, const VlUnpacked<SData, N_Depth>& q) {
|
||||
QData ret = 0;
|
||||
for (size_t i = 0; i < T_Depth; ++i)
|
||||
ret |= static_cast<QData>(q[T_Depth - 1 - i]) << (i * lbits);
|
||||
for (size_t i = 0; i < N_Depth; ++i)
|
||||
ret |= static_cast<QData>(q[N_Depth - 1 - i]) << (i * lbits);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth>
|
||||
static inline QData VL_PACK_QI(int obits, int lbits, const VlUnpacked<IData, T_Depth>& q) {
|
||||
template <std::size_t N_Depth>
|
||||
static inline QData VL_PACK_QI(int obits, int lbits, const VlUnpacked<IData, N_Depth>& q) {
|
||||
QData ret = 0;
|
||||
for (size_t i = 0; i < T_Depth; ++i)
|
||||
ret |= static_cast<QData>(q[T_Depth - 1 - i]) << (i * lbits);
|
||||
for (size_t i = 0; i < N_Depth; ++i)
|
||||
ret |= static_cast<QData>(q[N_Depth - 1 - i]) << (i * lbits);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1675,10 +1675,10 @@ static inline QData VL_PACK_QQ(int obits, int lbits, const VlQueue<QData>& q) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth>
|
||||
static inline QData VL_PACK_QQ(int obits, int lbits, const VlUnpacked<QData, T_Depth>& q) {
|
||||
template <std::size_t N_Depth>
|
||||
static inline QData VL_PACK_QQ(int obits, int lbits, const VlUnpacked<QData, N_Depth>& q) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1703,30 +1703,30 @@ static inline WDataOutP VL_PACK_WI(int obits, int lbits, WDataOutP owp, const Vl
|
||||
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,
|
||||
const VlUnpacked<CData, T_Depth>& q) {
|
||||
const VlUnpacked<CData, N_Depth>& q) {
|
||||
VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1);
|
||||
for (size_t i = 0; i < T_Depth; ++i)
|
||||
_vl_insert_WI(owp, q[T_Depth - 1 - i], i * lbits + lbits - 1, i * lbits);
|
||||
for (size_t i = 0; i < N_Depth; ++i)
|
||||
_vl_insert_WI(owp, q[N_Depth - 1 - i], i * lbits + lbits - 1, i * lbits);
|
||||
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,
|
||||
const VlUnpacked<SData, T_Depth>& q) {
|
||||
const VlUnpacked<SData, N_Depth>& q) {
|
||||
VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1);
|
||||
for (size_t i = 0; i < T_Depth; ++i)
|
||||
_vl_insert_WI(owp, q[T_Depth - 1 - i], i * lbits + lbits - 1, i * lbits);
|
||||
for (size_t i = 0; i < N_Depth; ++i)
|
||||
_vl_insert_WI(owp, q[N_Depth - 1 - i], i * lbits + lbits - 1, i * lbits);
|
||||
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,
|
||||
const VlUnpacked<IData, T_Depth>& q) {
|
||||
const VlUnpacked<IData, N_Depth>& q) {
|
||||
VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1);
|
||||
for (size_t i = 0; i < T_Depth; ++i)
|
||||
_vl_insert_WI(owp, q[T_Depth - 1 - i], i * lbits + lbits - 1, i * lbits);
|
||||
for (size_t i = 0; i < N_Depth; ++i)
|
||||
_vl_insert_WI(owp, q[N_Depth - 1 - i], i * lbits + lbits - 1, i * lbits);
|
||||
return owp;
|
||||
}
|
||||
|
||||
@ -1737,30 +1737,30 @@ static inline WDataOutP VL_PACK_WQ(int obits, int lbits, WDataOutP owp, const Vl
|
||||
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,
|
||||
const VlUnpacked<QData, T_Depth>& q) {
|
||||
const VlUnpacked<QData, N_Depth>& q) {
|
||||
VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1);
|
||||
for (size_t i = 0; i < T_Depth; ++i)
|
||||
_vl_insert_WQ(owp, q[T_Depth - 1 - i], i * lbits + lbits - 1, i * lbits);
|
||||
for (size_t i = 0; i < N_Depth; ++i)
|
||||
_vl_insert_WQ(owp, q[N_Depth - 1 - i], i * lbits + lbits - 1, i * lbits);
|
||||
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,
|
||||
const VlQueue<VlWide<N>>& q) {
|
||||
const VlQueue<VlWide<N_Words>>& q) {
|
||||
VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1);
|
||||
for (size_t i = 0; i < q.size(); ++i)
|
||||
_vl_insert_WW(owp, q.at(i), i * lbits + lbits - 1, i * lbits);
|
||||
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,
|
||||
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);
|
||||
for (size_t i = 0; i < T_Depth; ++i)
|
||||
_vl_insert_WW(owp, q[T_Depth - 1 - i], i * lbits + lbits - 1, i * lbits);
|
||||
for (size_t i = 0; i < N_Depth; ++i)
|
||||
_vl_insert_WW(owp, q[N_Depth - 1 - i], i * lbits + lbits - 1, i * lbits);
|
||||
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>
|
||||
static inline void VL_UNPACK_WW(int lbits, int rbits, VlQueue<VlWide<N>>& q, WDataInP rwp) {
|
||||
template <std::size_t N_Words>
|
||||
static inline void VL_UNPACK_WW(int lbits, int rbits, VlQueue<VlWide<N_Words>>& q, WDataInP rwp) {
|
||||
const int size = (rbits + lbits - 1) / lbits;
|
||||
q.renew(size);
|
||||
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>
|
||||
static inline void VL_UNPACK_II(int lbits, int rbits, VlUnpacked<CData, T_Depth>& q, IData from) {
|
||||
template <std::size_t N_Depth>
|
||||
static inline void VL_UNPACK_II(int lbits, int rbits, VlUnpacked<CData, N_Depth>& q, IData from) {
|
||||
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>
|
||||
static inline void VL_UNPACK_II(int lbits, int rbits, VlUnpacked<SData, T_Depth>& q, IData from) {
|
||||
template <std::size_t N_Depth>
|
||||
static inline void VL_UNPACK_II(int lbits, int rbits, VlUnpacked<SData, N_Depth>& q, IData from) {
|
||||
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>
|
||||
static inline void VL_UNPACK_II(int lbits, int rbits, VlUnpacked<IData, T_Depth>& q, IData from) {
|
||||
template <std::size_t N_Depth>
|
||||
static inline void VL_UNPACK_II(int lbits, int rbits, VlUnpacked<IData, N_Depth>& q, IData from) {
|
||||
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>
|
||||
static inline void VL_UNPACK_IQ(int lbits, int rbits, VlUnpacked<CData, T_Depth>& q, QData from) {
|
||||
template <std::size_t N_Depth>
|
||||
static inline void VL_UNPACK_IQ(int lbits, int rbits, VlUnpacked<CData, N_Depth>& q, QData from) {
|
||||
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>
|
||||
static inline void VL_UNPACK_IQ(int lbits, int rbits, VlUnpacked<SData, T_Depth>& q, QData from) {
|
||||
template <std::size_t N_Depth>
|
||||
static inline void VL_UNPACK_IQ(int lbits, int rbits, VlUnpacked<SData, N_Depth>& q, QData from) {
|
||||
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>
|
||||
static inline void VL_UNPACK_IQ(int lbits, int rbits, VlUnpacked<IData, T_Depth>& q, QData from) {
|
||||
template <std::size_t N_Depth>
|
||||
static inline void VL_UNPACK_IQ(int lbits, int rbits, VlUnpacked<IData, N_Depth>& q, QData from) {
|
||||
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>
|
||||
static inline void VL_UNPACK_QQ(int lbits, int rbits, VlUnpacked<QData, T_Depth>& q, QData from) {
|
||||
template <std::size_t N_Depth>
|
||||
static inline void VL_UNPACK_QQ(int lbits, int rbits, VlUnpacked<QData, N_Depth>& q, QData from) {
|
||||
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>
|
||||
static inline void VL_UNPACK_IW(int lbits, int rbits, VlUnpacked<CData, T_Depth>& q,
|
||||
template <std::size_t N_Depth>
|
||||
static inline void VL_UNPACK_IW(int lbits, int rbits, VlUnpacked<CData, N_Depth>& q,
|
||||
WDataInP rwp) {
|
||||
const IData mask = VL_MASK_I(lbits);
|
||||
for (size_t i = 0; i < T_Depth; ++i)
|
||||
q[i] = VL_SEL_IWII(rbits, rwp, (T_Depth - 1 - i) * lbits, lbits) & mask;
|
||||
for (size_t i = 0; i < N_Depth; ++i)
|
||||
q[i] = VL_SEL_IWII(rbits, rwp, (N_Depth - 1 - i) * lbits, lbits) & mask;
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth>
|
||||
static inline void VL_UNPACK_IW(int lbits, int rbits, VlUnpacked<SData, T_Depth>& q,
|
||||
template <std::size_t N_Depth>
|
||||
static inline void VL_UNPACK_IW(int lbits, int rbits, VlUnpacked<SData, N_Depth>& q,
|
||||
WDataInP rwp) {
|
||||
const IData mask = VL_MASK_I(lbits);
|
||||
for (size_t i = 0; i < T_Depth; ++i)
|
||||
q[i] = VL_SEL_IWII(rbits, rwp, (T_Depth - 1 - i) * lbits, lbits) & mask;
|
||||
for (size_t i = 0; i < N_Depth; ++i)
|
||||
q[i] = VL_SEL_IWII(rbits, rwp, (N_Depth - 1 - i) * lbits, lbits) & mask;
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth>
|
||||
static inline void VL_UNPACK_IW(int lbits, int rbits, VlUnpacked<IData, T_Depth>& q,
|
||||
template <std::size_t N_Depth>
|
||||
static inline void VL_UNPACK_IW(int lbits, int rbits, VlUnpacked<IData, N_Depth>& q,
|
||||
WDataInP rwp) {
|
||||
const IData mask = VL_MASK_I(lbits);
|
||||
for (size_t i = 0; i < T_Depth; ++i)
|
||||
q[i] = VL_SEL_IWII(rbits, rwp, (T_Depth - 1 - i) * lbits, lbits) & mask;
|
||||
for (size_t i = 0; i < N_Depth; ++i)
|
||||
q[i] = VL_SEL_IWII(rbits, rwp, (N_Depth - 1 - i) * lbits, lbits) & mask;
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth>
|
||||
static inline void VL_UNPACK_QW(int lbits, int rbits, VlUnpacked<QData, T_Depth>& q,
|
||||
template <std::size_t N_Depth>
|
||||
static inline void VL_UNPACK_QW(int lbits, int rbits, VlUnpacked<QData, N_Depth>& q,
|
||||
WDataInP rwp) {
|
||||
const QData mask = VL_MASK_Q(lbits);
|
||||
for (size_t i = 0; i < T_Depth; ++i)
|
||||
q[i] = VL_SEL_QWII(rbits, rwp, (T_Depth - 1 - i) * lbits, lbits) & mask;
|
||||
for (size_t i = 0; i < N_Depth; ++i)
|
||||
q[i] = VL_SEL_QWII(rbits, rwp, (N_Depth - 1 - i) * lbits, lbits) & mask;
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth, std::size_t N>
|
||||
static inline void VL_UNPACK_WW(int lbits, int rbits, VlUnpacked<VlWide<N>, T_Depth>& q,
|
||||
template <std::size_t N_Depth, std::size_t N_Words>
|
||||
static inline void VL_UNPACK_WW(int lbits, int rbits, VlUnpacked<VlWide<N_Words>, N_Depth>& q,
|
||||
WDataInP rwp) {
|
||||
for (size_t i = 0; i < T_Depth; ++i)
|
||||
VL_SEL_WWII(lbits, rbits, q[i], rwp, (T_Depth - 1 - i) * lbits, lbits);
|
||||
for (size_t i = 0; i < N_Depth; ++i)
|
||||
VL_SEL_WWII(lbits, rbits, q[i], rwp, (N_Depth - 1 - i) * lbits, lbits);
|
||||
}
|
||||
|
||||
// Return QData from double (numeric)
|
||||
|
@ -198,7 +198,7 @@ public:
|
||||
//=============================================================================
|
||||
// VlPgoProfiler is for collecting profiling data for PGO
|
||||
|
||||
template <std::size_t T_Entries>
|
||||
template <std::size_t N_Entries>
|
||||
class VlPgoProfiler final {
|
||||
// TYPES
|
||||
struct Record final {
|
||||
@ -207,7 +207,7 @@ class VlPgoProfiler final {
|
||||
};
|
||||
|
||||
// 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
|
||||
|
||||
public:
|
||||
@ -216,7 +216,7 @@ public:
|
||||
~VlPgoProfiler() = default;
|
||||
void write(const char* modelp, const std::string& filename) VL_MT_SAFE;
|
||||
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});
|
||||
}
|
||||
void startCounter(size_t counter) {
|
||||
@ -227,8 +227,8 @@ public:
|
||||
void stopCounter(size_t counter) { m_counters[counter] += VL_CPU_TICK(); }
|
||||
};
|
||||
|
||||
template <std::size_t T_Entries>
|
||||
void VlPgoProfiler<T_Entries>::write(const char* modelp, const std::string& filename) VL_MT_SAFE {
|
||||
template <std::size_t N_Entries>
|
||||
void VlPgoProfiler<N_Entries>::write(const char* modelp, const std::string& filename) VL_MT_SAFE {
|
||||
static VerilatedMutex s_mutex;
|
||||
const VerilatedLockGuard lock{s_mutex};
|
||||
|
||||
|
@ -250,11 +250,11 @@ public:
|
||||
record_arr_table(var, name, dimension, {});
|
||||
}
|
||||
}
|
||||
template <typename T, std::size_t N>
|
||||
void write_var(VlUnpacked<T, N>& var, int width, const char* name, int dimension,
|
||||
template <typename T, std::size_t N_Depth>
|
||||
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()) {
|
||||
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);
|
||||
if (dimension > 0) {
|
||||
idx = 0;
|
||||
@ -295,11 +295,11 @@ public:
|
||||
++idx;
|
||||
}
|
||||
}
|
||||
template <typename T, std::size_t N>
|
||||
void record_arr_table(VlUnpacked<T, N>& var, const std::string name, int dimension,
|
||||
template <typename T, std::size_t N_Depth>
|
||||
void record_arr_table(VlUnpacked<T, N_Depth>& var, const std::string name, int dimension,
|
||||
std::vector<size_t> indices) {
|
||||
if ((dimension > 0) && (N != 0)) {
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
if ((dimension > 0) && (N_Depth != 0)) {
|
||||
for (size_t i = 0; i < N_Depth; ++i) {
|
||||
const std::string indexed_name = name + "[" + std::to_string(i) + "]";
|
||||
indices.push_back(i);
|
||||
record_arr_table(var.operator[](i), indexed_name, dimension - 1, indices);
|
||||
|
@ -161,10 +161,10 @@ public:
|
||||
~VlWorkerThread();
|
||||
|
||||
// METHODS
|
||||
template <bool SpinWait>
|
||||
template <bool N_SpinWait>
|
||||
void dequeWork(ExecRec* workp) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||
// 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) {
|
||||
if (VL_LIKELY(m_ready_size.load(std::memory_order_relaxed))) break;
|
||||
VL_CPU_RELAX();
|
||||
|
@ -164,12 +164,12 @@ inline std::string VL_TO_STRING(const VlProcessRef& p) { return std::string("pro
|
||||
//===================================================================
|
||||
// Activity trigger vector
|
||||
|
||||
template <std::size_t T_size> //
|
||||
template <std::size_t N_Size> //
|
||||
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
|
||||
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:
|
||||
// CONSTRUCTOR
|
||||
@ -200,12 +200,12 @@ public:
|
||||
}
|
||||
|
||||
// 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];
|
||||
}
|
||||
|
||||
// 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];
|
||||
}
|
||||
};
|
||||
@ -309,7 +309,7 @@ public:
|
||||
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 {
|
||||
T_Value m_remaining = 0; // Number of values to pull before re-randomize
|
||||
T_Value m_lfsr = 1; // LFSR state
|
||||
@ -317,8 +317,8 @@ class VlRandC final {
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VlRandC() {
|
||||
static_assert(T_numValues >= 1, "");
|
||||
static_assert(sizeof(T_Value) == 8 || (T_numValues < (1ULL << (8 * sizeof(T_Value)))), "");
|
||||
static_assert(N_NumValues >= 1, "");
|
||||
static_assert(sizeof(T_Value) == 8 || (N_NumValues < (1ULL << (8 * sizeof(T_Value)))), "");
|
||||
}
|
||||
// METHODS
|
||||
T_Value randomize(VlRNG& rngr) {
|
||||
@ -337,23 +337,23 @@ public:
|
||||
0x80000057ULL, // 32
|
||||
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 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
|
||||
// extra bit in width, this will only require at most on average 1.5 loops
|
||||
do {
|
||||
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;
|
||||
T_Value result = (m_lfsr == T_numValues) ? 0 : m_lfsr;
|
||||
// printf(" result=%x (numv=%ld, rem=%d)\n", result, T_numValues, m_remaining);
|
||||
T_Value result = (m_lfsr == N_NumValues) ? 0 : m_lfsr;
|
||||
// printf(" result=%x (numv=%ld, rem=%d)\n", result, N_NumValues, m_remaining);
|
||||
return result;
|
||||
}
|
||||
void reseed(VlRNG& rngr) {
|
||||
constexpr uint32_t lfsrWidth = VL_CLOG2_CE_Q(T_numValues) + 1;
|
||||
m_remaining = T_numValues;
|
||||
constexpr uint32_t lfsrWidth = VL_CLOG2_CE_Q(N_NumValues) + 1;
|
||||
m_remaining = N_NumValues;
|
||||
do {
|
||||
m_lfsr = rngr.rand64() & VL_MASK_Q(lfsrWidth);
|
||||
// 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;
|
||||
|
||||
template <std::size_t T_Words>
|
||||
template <std::size_t N_Words>
|
||||
struct VlWide;
|
||||
|
||||
// Type trait to check if a type is VlWide
|
||||
template <typename>
|
||||
struct VlIsVlWide : public std::false_type {};
|
||||
|
||||
template <std::size_t T_Words>
|
||||
struct VlIsVlWide<VlWide<T_Words>> : public std::true_type {};
|
||||
template <std::size_t N_Words>
|
||||
struct VlIsVlWide<VlWide<N_Words>> : public std::true_type {};
|
||||
|
||||
template <std::size_t T_Words>
|
||||
template <std::size_t N_Words>
|
||||
struct VlWide final {
|
||||
static constexpr size_t Words = T_Words;
|
||||
static constexpr size_t Words = N_Words;
|
||||
|
||||
// MEMBERS
|
||||
// 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
|
||||
// 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.
|
||||
operator WDataOutP() 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 {
|
||||
for (size_t i = 0; i < T_Words; ++i) {
|
||||
bool operator!=(const VlWide<N_Words>& that) const VL_PURE {
|
||||
for (size_t i = 0; i < N_Words; ++i) {
|
||||
if (m_storage[i] != that.m_storage[i]) return true;
|
||||
}
|
||||
return false;
|
||||
@ -453,21 +453,21 @@ struct VlWide final {
|
||||
EData& at(size_t index) { return m_storage[index]; }
|
||||
WData* data() { return &m_storage[0]; }
|
||||
const WData* data() const { return &m_storage[0]; }
|
||||
bool operator<(const VlWide<T_Words>& rhs) const {
|
||||
return _vl_cmp_w(T_Words, data(), rhs.data()) < 0;
|
||||
bool operator<(const VlWide<N_Words>& rhs) const {
|
||||
return _vl_cmp_w(N_Words, data(), rhs.data()) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
// 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.
|
||||
template <std::size_t T_Words>
|
||||
VlWide<T_Words>& VL_CVT_W_A(const WDataInP inp, const VlWide<T_Words>&) {
|
||||
return *((VlWide<T_Words>*)inp);
|
||||
template <std::size_t N_Words>
|
||||
VlWide<N_Words>& VL_CVT_W_A(const WDataInP inp, const VlWide<N_Words>&) {
|
||||
return *((VlWide<N_Words>*)inp);
|
||||
}
|
||||
|
||||
template <std::size_t T_Words>
|
||||
std::string VL_TO_STRING(const VlWide<T_Words>& obj) {
|
||||
return VL_TO_STRING_W(T_Words, obj.data());
|
||||
template <std::size_t N_Words>
|
||||
std::string VL_TO_STRING(const VlWide<N_Words>& obj) {
|
||||
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
|
||||
// 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 {
|
||||
private:
|
||||
// TYPES
|
||||
@ -485,8 +485,8 @@ private:
|
||||
|
||||
public:
|
||||
using const_iterator = typename Deque::const_iterator;
|
||||
template <typename Func>
|
||||
using WithFuncReturnType = decltype(std::declval<Func>()(0, std::declval<T_Value>()));
|
||||
template <typename T_Func>
|
||||
using WithFuncReturnType = decltype(std::declval<T_Func>()(0, std::declval<T_Value>()));
|
||||
|
||||
private:
|
||||
// MEMBERS
|
||||
@ -506,11 +506,11 @@ public:
|
||||
bool operator!=(const VlQueue& rhs) const { return m_deque != rhs.m_deque; }
|
||||
|
||||
// Standard copy constructor works. Verilog: assoca = assocb
|
||||
// Also must allow conversion from a different T_MaxSize queue
|
||||
template <size_t U_MaxSize = 0>
|
||||
VlQueue operator=(const VlQueue<T_Value, U_MaxSize>& rhs) {
|
||||
// Also must allow conversion from a different N_MaxSize queue
|
||||
template <size_t N_RhsMaxSize = 0>
|
||||
VlQueue operator=(const VlQueue<T_Value, N_RhsMaxSize>& rhs) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -562,7 +562,7 @@ public:
|
||||
m_deque.resize(size, atDefault());
|
||||
}
|
||||
// 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) {
|
||||
clear();
|
||||
} else {
|
||||
@ -575,11 +575,11 @@ public:
|
||||
// function void q.push_front(value)
|
||||
void push_front(const T_Value& 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)
|
||||
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();
|
||||
T_Value pop_front() {
|
||||
@ -600,7 +600,7 @@ public:
|
||||
T_Value& atWrite(int32_t index) {
|
||||
// cppcheck-suppress variableScope
|
||||
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())) {
|
||||
t_throwAway = atDefault();
|
||||
return t_throwAway;
|
||||
@ -621,7 +621,7 @@ public:
|
||||
}
|
||||
// Accessing. Verilog: v = assoc[index]
|
||||
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())) {
|
||||
return atDefault();
|
||||
} else {
|
||||
@ -665,8 +665,8 @@ public:
|
||||
|
||||
// Methods
|
||||
void sort() { std::sort(m_deque.begin(), m_deque.end()); }
|
||||
template <typename Func>
|
||||
void sort(Func with_func) {
|
||||
template <typename T_Func>
|
||||
void sort(T_Func with_func) {
|
||||
// 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) {
|
||||
// index number is meaningless with sort, as it changes
|
||||
@ -674,8 +674,8 @@ public:
|
||||
});
|
||||
}
|
||||
void rsort() { std::sort(m_deque.rbegin(), m_deque.rend()); }
|
||||
template <typename Func>
|
||||
void rsort(Func with_func) {
|
||||
template <typename T_Func>
|
||||
void rsort(T_Func with_func) {
|
||||
// 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) {
|
||||
// index number is meaningless with sort, as it changes
|
||||
@ -696,8 +696,8 @@ public:
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue unique(Func with_func) const {
|
||||
template <typename T_Func>
|
||||
VlQueue unique(T_Func with_func) const {
|
||||
VlQueue out;
|
||||
std::set<decltype(with_func(0, m_deque[0]))> saw;
|
||||
for (const auto& i : m_deque) {
|
||||
@ -724,8 +724,8 @@ public:
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<IData> unique_index(Func with_func) const {
|
||||
template <typename T_Func>
|
||||
VlQueue<IData> unique_index(T_Func with_func) const {
|
||||
VlQueue<IData> out;
|
||||
IData index = 0;
|
||||
std::set<decltype(with_func(0, m_deque[0]))> saw;
|
||||
@ -740,8 +740,8 @@ public:
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue find(Func with_func) const {
|
||||
template <typename T_Func>
|
||||
VlQueue find(T_Func with_func) const {
|
||||
VlQueue out;
|
||||
IData index = 0;
|
||||
for (const auto& i : m_deque) {
|
||||
@ -750,8 +750,8 @@ public:
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<IData> find_index(Func with_func) const {
|
||||
template <typename T_Func>
|
||||
VlQueue<IData> find_index(T_Func with_func) const {
|
||||
VlQueue<IData> out;
|
||||
IData index = 0;
|
||||
for (const auto& i : m_deque) {
|
||||
@ -760,8 +760,8 @@ public:
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue find_first(Func with_func) const {
|
||||
template <typename T_Func>
|
||||
VlQueue find_first(T_Func with_func) const {
|
||||
// Can't use std::find_if as need index number
|
||||
IData index = 0;
|
||||
for (const auto& i : m_deque) {
|
||||
@ -770,8 +770,8 @@ public:
|
||||
}
|
||||
return VlQueue{};
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<IData> find_first_index(Func with_func) const {
|
||||
template <typename T_Func>
|
||||
VlQueue<IData> find_first_index(T_Func with_func) const {
|
||||
IData index = 0;
|
||||
for (const auto& i : m_deque) {
|
||||
if (with_func(index, i)) return VlQueue<IData>::consV(index);
|
||||
@ -779,8 +779,8 @@ public:
|
||||
}
|
||||
return VlQueue<IData>{};
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue find_last(Func with_func) const {
|
||||
template <typename T_Func>
|
||||
VlQueue find_last(T_Func with_func) const {
|
||||
IData index = m_deque.size() - 1;
|
||||
for (auto& item : vlstd::reverse_view(m_deque)) {
|
||||
if (with_func(index, item)) return VlQueue::consV(item);
|
||||
@ -788,8 +788,8 @@ public:
|
||||
}
|
||||
return VlQueue{};
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<IData> find_last_index(Func with_func) const {
|
||||
template <typename T_Func>
|
||||
VlQueue<IData> find_last_index(T_Func with_func) const {
|
||||
IData index = m_deque.size() - 1;
|
||||
for (auto& item : vlstd::reverse_view(m_deque)) {
|
||||
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());
|
||||
return VlQueue::consV(*it);
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue min(Func with_func) const {
|
||||
template <typename T_Func>
|
||||
VlQueue min(T_Func with_func) const {
|
||||
if (m_deque.empty()) return VlQueue{};
|
||||
const auto it = std::min_element(m_deque.cbegin(), m_deque.cend(),
|
||||
[&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());
|
||||
return VlQueue::consV(*it);
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue max(Func with_func) const {
|
||||
template <typename T_Func>
|
||||
VlQueue max(T_Func with_func) const {
|
||||
if (m_deque.empty()) return VlQueue{};
|
||||
const auto it = std::max_element(m_deque.cbegin(), m_deque.cend(),
|
||||
[&with_func](const IData& a, const IData& b) {
|
||||
@ -833,9 +833,9 @@ public:
|
||||
for (const auto& i : m_deque) out += i;
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
WithFuncReturnType<Func> r_sum(Func with_func) const {
|
||||
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(0);
|
||||
template <typename T_Func>
|
||||
WithFuncReturnType<T_Func> r_sum(T_Func with_func) const {
|
||||
WithFuncReturnType<T_Func> out = WithFuncReturnType<T_Func>(0);
|
||||
IData index = 0;
|
||||
for (const auto& i : m_deque) out += with_func(index++, i);
|
||||
return out;
|
||||
@ -846,10 +846,10 @@ public:
|
||||
for (const auto& i : m_deque) out *= i;
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
WithFuncReturnType<Func> r_product(Func with_func) const {
|
||||
if (m_deque.empty()) return WithFuncReturnType<Func>(0); // The big three do it this way
|
||||
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(1);
|
||||
template <typename T_Func>
|
||||
WithFuncReturnType<T_Func> r_product(T_Func with_func) const {
|
||||
if (m_deque.empty()) return WithFuncReturnType<T_Func>(0); // The big three do it this way
|
||||
WithFuncReturnType<T_Func> out = WithFuncReturnType<T_Func>(1);
|
||||
IData index = 0;
|
||||
for (const auto& i : m_deque) out *= with_func(index++, i);
|
||||
return out;
|
||||
@ -860,11 +860,11 @@ public:
|
||||
for (const auto& i : m_deque) out &= i;
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
WithFuncReturnType<Func> r_and(Func with_func) const {
|
||||
if (m_deque.empty()) return WithFuncReturnType<Func>(0); // The big three do it this way
|
||||
template <typename T_Func>
|
||||
WithFuncReturnType<T_Func> r_and(T_Func with_func) const {
|
||||
if (m_deque.empty()) return WithFuncReturnType<T_Func>(0); // The big three do it this way
|
||||
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);
|
||||
return out;
|
||||
}
|
||||
@ -873,9 +873,9 @@ public:
|
||||
for (const auto& i : m_deque) out |= i;
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
WithFuncReturnType<Func> r_or(Func with_func) const {
|
||||
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(0);
|
||||
template <typename T_Func>
|
||||
WithFuncReturnType<T_Func> r_or(T_Func with_func) const {
|
||||
WithFuncReturnType<T_Func> out = WithFuncReturnType<T_Func>(0);
|
||||
IData index = 0;
|
||||
for (const auto& i : m_deque) out |= with_func(index++, i);
|
||||
return out;
|
||||
@ -888,9 +888,9 @@ public:
|
||||
for (const auto& i : m_deque) out ^= i;
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
WithFuncReturnType<Func> r_xor(Func with_func) const {
|
||||
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(0);
|
||||
template <typename T_Func>
|
||||
WithFuncReturnType<T_Func> r_xor(T_Func with_func) const {
|
||||
WithFuncReturnType<T_Func> out = WithFuncReturnType<T_Func>(0);
|
||||
IData index = 0;
|
||||
for (const auto& i : m_deque) out ^= with_func(index++, i);
|
||||
return out;
|
||||
@ -909,8 +909,8 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T_Value, size_t T_MaxSize>
|
||||
std::string VL_TO_STRING(const VlQueue<T_Value, T_MaxSize>& obj) {
|
||||
template <typename T_Value, size_t N_MaxSize>
|
||||
std::string VL_TO_STRING(const VlQueue<T_Value, N_MaxSize>& obj) {
|
||||
return obj.to_string();
|
||||
}
|
||||
|
||||
@ -927,9 +927,9 @@ private:
|
||||
|
||||
public:
|
||||
using const_iterator = typename Map::const_iterator;
|
||||
template <typename Func>
|
||||
template <typename T_Func>
|
||||
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:
|
||||
// MEMBERS
|
||||
@ -1038,8 +1038,8 @@ public:
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Value> unique(Func with_func) const {
|
||||
template <typename T_Func>
|
||||
VlQueue<T_Value> unique(T_Func with_func) const {
|
||||
VlQueue<T_Value> out;
|
||||
T_Key default_key;
|
||||
using WithType = decltype(with_func(m_map.begin()->first, m_map.begin()->second));
|
||||
@ -1066,8 +1066,8 @@ public:
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Key> unique_index(Func with_func) const {
|
||||
template <typename T_Func>
|
||||
VlQueue<T_Key> unique_index(T_Func with_func) const {
|
||||
VlQueue<T_Key> out;
|
||||
using WithType = decltype(with_func(m_map.begin()->first, m_map.begin()->second));
|
||||
std::set<WithType> saw;
|
||||
@ -1081,22 +1081,22 @@ public:
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Value> find(Func with_func) const {
|
||||
template <typename T_Func>
|
||||
VlQueue<T_Value> find(T_Func with_func) const {
|
||||
VlQueue<T_Value> out;
|
||||
for (const auto& i : m_map)
|
||||
if (with_func(i.first, i.second)) out.push_back(i.second);
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Key> find_index(Func with_func) const {
|
||||
template <typename T_Func>
|
||||
VlQueue<T_Key> find_index(T_Func with_func) const {
|
||||
VlQueue<T_Key> out;
|
||||
for (const auto& i : m_map)
|
||||
if (with_func(i.first, i.second)) out.push_back(i.first);
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Value> find_first(Func with_func) const {
|
||||
template <typename T_Func>
|
||||
VlQueue<T_Value> find_first(T_Func with_func) const {
|
||||
const auto it
|
||||
= std::find_if(m_map.cbegin(), m_map.cend(), [=](const std::pair<T_Key, T_Value>& i) {
|
||||
return with_func(i.first, i.second);
|
||||
@ -1104,8 +1104,8 @@ public:
|
||||
if (it == m_map.end()) return VlQueue<T_Value>{};
|
||||
return VlQueue<T_Value>::consV(it->second);
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Key> find_first_index(Func with_func) const {
|
||||
template <typename T_Func>
|
||||
VlQueue<T_Key> find_first_index(T_Func with_func) const {
|
||||
const auto it
|
||||
= std::find_if(m_map.cbegin(), m_map.cend(), [=](const std::pair<T_Key, T_Value>& i) {
|
||||
return with_func(i.first, i.second);
|
||||
@ -1113,16 +1113,16 @@ public:
|
||||
if (it == m_map.end()) return VlQueue<T_Value>{};
|
||||
return VlQueue<T_Key>::consV(it->first);
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Value> find_last(Func with_func) const {
|
||||
template <typename T_Func>
|
||||
VlQueue<T_Value> find_last(T_Func with_func) const {
|
||||
const auto it = std::find_if(
|
||||
m_map.crbegin(), m_map.crend(),
|
||||
[=](const std::pair<T_Key, T_Value>& i) { return with_func(i.first, i.second); });
|
||||
if (it == m_map.rend()) return VlQueue<T_Value>{};
|
||||
return VlQueue<T_Value>::consV(it->second);
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Key> find_last_index(Func with_func) const {
|
||||
template <typename T_Func>
|
||||
VlQueue<T_Key> find_last_index(T_Func with_func) const {
|
||||
const auto it = std::find_if(
|
||||
m_map.crbegin(), m_map.crend(),
|
||||
[=](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);
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Value> min(Func with_func) const {
|
||||
template <typename T_Func>
|
||||
VlQueue<T_Value> min(T_Func with_func) const {
|
||||
if (m_map.empty()) return VlQueue<T_Value>();
|
||||
const auto it = std::min_element(
|
||||
m_map.cbegin(), m_map.cend(),
|
||||
@ -1159,8 +1159,8 @@ public:
|
||||
});
|
||||
return VlQueue<T_Value>::consV(it->second);
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Value> max(Func with_func) const {
|
||||
template <typename T_Func>
|
||||
VlQueue<T_Value> max(T_Func with_func) const {
|
||||
if (m_map.empty()) return VlQueue<T_Value>();
|
||||
const auto it = std::max_element(
|
||||
m_map.cbegin(), m_map.cend(),
|
||||
@ -1175,9 +1175,9 @@ public:
|
||||
for (const auto& i : m_map) out += i.second;
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
WithFuncReturnType<Func> r_sum(Func with_func) const {
|
||||
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(0);
|
||||
template <typename T_Func>
|
||||
WithFuncReturnType<T_Func> r_sum(T_Func with_func) const {
|
||||
WithFuncReturnType<T_Func> out = WithFuncReturnType<T_Func>(0);
|
||||
for (const auto& i : m_map) out += with_func(i.first, i.second);
|
||||
return out;
|
||||
}
|
||||
@ -1187,10 +1187,10 @@ public:
|
||||
for (const auto& i : m_map) out *= i.second;
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
WithFuncReturnType<Func> r_product(Func with_func) const {
|
||||
if (m_map.empty()) return WithFuncReturnType<Func>(0); // The big three do it this way
|
||||
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(1);
|
||||
template <typename T_Func>
|
||||
WithFuncReturnType<T_Func> r_product(T_Func with_func) const {
|
||||
if (m_map.empty()) return WithFuncReturnType<T_Func>(0); // The big three do it this way
|
||||
WithFuncReturnType<T_Func> out = WithFuncReturnType<T_Func>(1);
|
||||
for (const auto& i : m_map) out *= with_func(i.first, i.second);
|
||||
return out;
|
||||
}
|
||||
@ -1200,10 +1200,10 @@ public:
|
||||
for (const auto& i : m_map) out &= i.second;
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
WithFuncReturnType<Func> r_and(Func with_func) const {
|
||||
if (m_map.empty()) return WithFuncReturnType<Func>(0); // The big three do it this way
|
||||
WithFuncReturnType<Func> out = ~WithFuncReturnType<Func>(0);
|
||||
template <typename T_Func>
|
||||
WithFuncReturnType<T_Func> r_and(T_Func with_func) const {
|
||||
if (m_map.empty()) return WithFuncReturnType<T_Func>(0); // The big three do it this way
|
||||
WithFuncReturnType<T_Func> out = ~WithFuncReturnType<T_Func>(0);
|
||||
for (const auto& i : m_map) out &= with_func(i.first, i.second);
|
||||
return out;
|
||||
}
|
||||
@ -1212,8 +1212,8 @@ public:
|
||||
for (const auto& i : m_map) out |= i.second;
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
T_Value r_or(Func with_func) const {
|
||||
template <typename T_Func>
|
||||
T_Value r_or(T_Func with_func) const {
|
||||
T_Value out = T_Value(0);
|
||||
for (const auto& i : m_map) out |= with_func(i.first, i.second);
|
||||
return out;
|
||||
@ -1223,9 +1223,9 @@ public:
|
||||
for (const auto& i : m_map) out ^= i.second;
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
WithFuncReturnType<Func> r_xor(Func with_func) const {
|
||||
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(0);
|
||||
template <typename T_Func>
|
||||
WithFuncReturnType<T_Func> r_xor(T_Func with_func) const {
|
||||
WithFuncReturnType<T_Func> out = WithFuncReturnType<T_Func>(0);
|
||||
for (const auto& i : m_map) out ^= with_func(i.first, i.second);
|
||||
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
|
||||
/// 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 {
|
||||
// TYPES
|
||||
using T_Key = IData; // Index type, for uniformity with other containers
|
||||
using Unpacked = T_Value[T_Depth];
|
||||
using Unpacked = T_Value[N_Depth];
|
||||
|
||||
public:
|
||||
// MEMBERS
|
||||
@ -1312,41 +1312,41 @@ public:
|
||||
WData* data() { 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
|
||||
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 {
|
||||
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 {
|
||||
if (dimension == CurrentDimension) {
|
||||
if (dimension == N_CurrentDimension) {
|
||||
return size();
|
||||
} 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 {
|
||||
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) {
|
||||
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) {
|
||||
return m_storage[indices[CurrentDimension]].template find_element<CurrentDimension + 1>(
|
||||
indices);
|
||||
return m_storage[indices[N_CurrentDimension]]
|
||||
.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) {
|
||||
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]; }
|
||||
@ -1354,15 +1354,15 @@ public:
|
||||
|
||||
// *this != that, which might be used for change detection/trigger computation, but avoid
|
||||
// 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
|
||||
void assign(const VlUnpacked<T_Value, T_Depth>& that) { *this = that; }
|
||||
bool operator==(const VlUnpacked<T_Value, T_Depth>& that) const { return !neq(that); }
|
||||
bool operator!=(const VlUnpacked<T_Value, T_Depth>& that) const { return neq(that); }
|
||||
void assign(const VlUnpacked<T_Value, N_Depth>& that) { *this = that; }
|
||||
bool operator==(const VlUnpacked<T_Value, N_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
|
||||
bool neq(const T_Value that[T_Depth]) const { return neq(*this, that); }
|
||||
void assign(const T_Value that[T_Depth]) { std::copy_n(that, T_Depth, m_storage); }
|
||||
void operator=(const T_Value that[T_Depth]) { assign(that); }
|
||||
bool neq(const T_Value that[N_Depth]) const { return neq(*this, that); }
|
||||
void assign(const T_Value that[N_Depth]) { std::copy_n(that, N_Depth, m_storage); }
|
||||
void operator=(const T_Value that[N_Depth]) { assign(that); }
|
||||
|
||||
// inside (set membership operator)
|
||||
bool inside(const T_Value& value) const {
|
||||
@ -1370,8 +1370,8 @@ public:
|
||||
}
|
||||
|
||||
void sort() { std::sort(std::begin(m_storage), std::end(m_storage)); }
|
||||
template <typename Func>
|
||||
void sort(Func with_func) {
|
||||
template <typename T_Func>
|
||||
void sort(T_Func with_func) {
|
||||
// with_func returns arbitrary type to use for the sort comparison
|
||||
std::sort(std::begin(m_storage), std::end(m_storage),
|
||||
[=](const T_Value& a, const T_Value& b) {
|
||||
@ -1383,8 +1383,8 @@ public:
|
||||
void rsort() {
|
||||
std::sort(std::begin(m_storage), std::end(m_storage), std::greater<T_Value>());
|
||||
}
|
||||
template <typename Func>
|
||||
void rsort(Func with_func) {
|
||||
template <typename T_Func>
|
||||
void rsort(T_Func with_func) {
|
||||
// with_func returns arbitrary type to use for the sort comparison
|
||||
// std::rbegin/std::rend not available until C++14, so using > below
|
||||
std::sort(std::begin(m_storage), std::end(m_storage),
|
||||
@ -1407,8 +1407,8 @@ public:
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Value> unique(Func with_func) const {
|
||||
template <typename T_Func>
|
||||
VlQueue<T_Value> unique(T_Func with_func) const {
|
||||
VlQueue<T_Value> out;
|
||||
std::set<T_Value> saw;
|
||||
for (const auto& i : m_storage) {
|
||||
@ -1435,8 +1435,8 @@ public:
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Key> unique_index(Func with_func) const {
|
||||
template <typename T_Func>
|
||||
VlQueue<T_Key> unique_index(T_Func with_func) const {
|
||||
VlQueue<T_Key> out;
|
||||
IData index = 0;
|
||||
std::set<T_Value> saw;
|
||||
@ -1451,8 +1451,8 @@ public:
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Value> find(Func with_func) const {
|
||||
template <typename T_Func>
|
||||
VlQueue<T_Value> find(T_Func with_func) const {
|
||||
VlQueue<T_Value> out;
|
||||
IData index = 0;
|
||||
for (const auto& i : m_storage) {
|
||||
@ -1461,8 +1461,8 @@ public:
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Key> find_index(Func with_func) const {
|
||||
template <typename T_Func>
|
||||
VlQueue<T_Key> find_index(T_Func with_func) const {
|
||||
VlQueue<T_Key> out;
|
||||
IData index = 0;
|
||||
for (const auto& i : m_storage) {
|
||||
@ -1471,8 +1471,8 @@ public:
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Value> find_first(Func with_func) const {
|
||||
template <typename T_Func>
|
||||
VlQueue<T_Value> find_first(T_Func with_func) const {
|
||||
// Can't use std::find_if as need index number
|
||||
IData index = 0;
|
||||
for (const auto& i : m_storage) {
|
||||
@ -1481,8 +1481,8 @@ public:
|
||||
}
|
||||
return VlQueue<T_Value>{};
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Key> find_first_index(Func with_func) const {
|
||||
template <typename T_Func>
|
||||
VlQueue<T_Key> find_first_index(T_Func with_func) const {
|
||||
IData index = 0;
|
||||
for (const auto& i : m_storage) {
|
||||
if (with_func(index, i)) return VlQueue<IData>::consV(index);
|
||||
@ -1490,16 +1490,16 @@ public:
|
||||
}
|
||||
return VlQueue<T_Key>{};
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Value> find_last(Func with_func) const {
|
||||
for (int i = T_Depth - 1; i >= 0; i--) {
|
||||
template <typename T_Func>
|
||||
VlQueue<T_Value> find_last(T_Func with_func) const {
|
||||
for (int i = N_Depth - 1; i >= 0; i--) {
|
||||
if (with_func(i, m_storage[i])) return VlQueue<T_Value>::consV(m_storage[i]);
|
||||
}
|
||||
return VlQueue<T_Value>{};
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Key> find_last_index(Func with_func) const {
|
||||
for (int i = T_Depth - 1; i >= 0; i--) {
|
||||
template <typename T_Func>
|
||||
VlQueue<T_Key> find_last_index(T_Func with_func) const {
|
||||
for (int i = N_Depth - 1; i >= 0; i--) {
|
||||
if (with_func(i, m_storage[i])) return VlQueue<IData>::consV(i);
|
||||
}
|
||||
return VlQueue<T_Key>{};
|
||||
@ -1510,8 +1510,8 @@ public:
|
||||
const auto it = std::min_element(std::begin(m_storage), std::end(m_storage));
|
||||
return VlQueue<T_Value>::consV(*it);
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Value> min(Func with_func) const {
|
||||
template <typename T_Func>
|
||||
VlQueue<T_Value> min(T_Func with_func) const {
|
||||
const auto it = std::min_element(std::begin(m_storage), std::end(m_storage),
|
||||
[&with_func](const IData& a, const IData& 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));
|
||||
return VlQueue<T_Value>::consV(*it);
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Value> max(Func with_func) const {
|
||||
template <typename T_Func>
|
||||
VlQueue<T_Value> max(T_Func with_func) const {
|
||||
const auto it = std::max_element(std::begin(m_storage), std::end(m_storage),
|
||||
[&with_func](const IData& a, const IData& b) {
|
||||
return with_func(0, a) < with_func(0, b);
|
||||
@ -1535,7 +1535,7 @@ public:
|
||||
std::string to_string() const {
|
||||
std::string out = "'{";
|
||||
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]);
|
||||
comma = ", ";
|
||||
}
|
||||
@ -1543,18 +1543,18 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T_Val, std::size_t T_Dep>
|
||||
static bool neq(const VlUnpacked<T_Val, T_Dep>& a, const VlUnpacked<T_Val, T_Dep>& b) {
|
||||
for (size_t i = 0; i < T_Dep; ++i) {
|
||||
template <typename T_Val, std::size_t N_Dep>
|
||||
static bool neq(const VlUnpacked<T_Val, N_Dep>& a, const VlUnpacked<T_Val, N_Dep>& b) {
|
||||
for (size_t i = 0; i < N_Dep; ++i) {
|
||||
// Recursive 'neq', in case T_Val is also a VlUnpacked<_, _>
|
||||
if (neq(a.m_storage[i], b.m_storage[i])) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T_Val, std::size_t T_Dep>
|
||||
static bool neq(const VlUnpacked<T_Val, T_Dep>& a, const T_Val b[T_Dep]) {
|
||||
for (size_t i = 0; i < T_Dep; ++i) {
|
||||
template <typename T_Val, std::size_t N_Dep>
|
||||
static bool neq(const VlUnpacked<T_Val, N_Dep>& a, const T_Val b[N_Dep]) {
|
||||
for (size_t i = 0; i < N_Dep; ++i) {
|
||||
// Recursive 'neq', in case T_Val is also a VlUnpacked<_, _>
|
||||
if (neq(a.m_storage[i], b[i])) return true;
|
||||
}
|
||||
@ -1568,25 +1568,25 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T_Value, std::size_t T_Depth>
|
||||
std::string VL_TO_STRING(const VlUnpacked<T_Value, T_Depth>& obj) {
|
||||
template <typename T_Value, std::size_t N_Depth>
|
||||
std::string VL_TO_STRING(const VlUnpacked<T_Value, N_Depth>& obj) {
|
||||
return obj.to_string();
|
||||
}
|
||||
|
||||
//===================================================================
|
||||
// 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 {
|
||||
VL_ATTR_ALWINLINE
|
||||
static auto& apply(T_Target& target, const size_t* indicesp) {
|
||||
return VlApplyIndices<Curr + 1, Rank, decltype(target[indicesp[Curr]])>::apply(
|
||||
target[indicesp[Curr]], indicesp);
|
||||
return VlApplyIndices<N_Curr + 1, N_Rank, decltype(target[indicesp[N_Curr]])>::apply(
|
||||
target[indicesp[N_Curr]], indicesp);
|
||||
}
|
||||
};
|
||||
|
||||
template <size_t Rank, typename T_Target>
|
||||
struct VlApplyIndices<Rank, Rank, T_Target> final {
|
||||
template <size_t N_Rank, typename T_Target>
|
||||
struct VlApplyIndices<N_Rank, N_Rank, T_Target> final {
|
||||
VL_ATTR_ALWINLINE
|
||||
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
|
||||
// explicitly to avoid template expansion, as Verilator already knows them
|
||||
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;
|
||||
|
||||
// Specialization for whole element updates only
|
||||
template <typename T_Target, typename T_Element, std::size_t T_Rank>
|
||||
class VlNBACommitQueue<T_Target, /* Partial: */ false, T_Element, T_Rank> final {
|
||||
template <typename T_Target, typename T_Element, std::size_t N_Rank>
|
||||
class VlNBACommitQueue<T_Target, /* Partial: */ false, T_Element, N_Rank> final {
|
||||
// TYPES
|
||||
struct Entry final {
|
||||
T_Element value;
|
||||
size_t indices[T_Rank];
|
||||
size_t indices[N_Rank];
|
||||
};
|
||||
|
||||
// STATE
|
||||
@ -1643,8 +1643,8 @@ public:
|
||||
VL_UNCOPYABLE(VlNBACommitQueue);
|
||||
|
||||
// METHODS
|
||||
template <typename... Args>
|
||||
void enqueue(const T_Element& value, Args... indices) {
|
||||
template <typename... T_Args>
|
||||
void enqueue(const T_Element& value, T_Args... indices) {
|
||||
m_pending.emplace_back(Entry{value, {indices...}});
|
||||
}
|
||||
|
||||
@ -1654,20 +1654,20 @@ public:
|
||||
void commit(T_Commit& target) {
|
||||
if (m_pending.empty()) return;
|
||||
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();
|
||||
}
|
||||
};
|
||||
|
||||
// With partial element updates
|
||||
template <typename T_Target, typename T_Element, std::size_t T_Rank>
|
||||
class VlNBACommitQueue<T_Target, /* Partial: */ true, T_Element, T_Rank> final {
|
||||
template <typename T_Target, typename T_Element, std::size_t N_Rank>
|
||||
class VlNBACommitQueue<T_Target, /* Partial: */ true, T_Element, N_Rank> final {
|
||||
// TYPES
|
||||
struct Entry final {
|
||||
T_Element value;
|
||||
T_Element mask;
|
||||
size_t indices[T_Rank];
|
||||
size_t indices[N_Rank];
|
||||
};
|
||||
|
||||
// STATE
|
||||
@ -1728,8 +1728,8 @@ public:
|
||||
VL_UNCOPYABLE(VlNBACommitQueue);
|
||||
|
||||
// METHODS
|
||||
template <typename... Args>
|
||||
void enqueue(const T_Element& value, const T_Element& mask, Args... indices) {
|
||||
template <typename... T_Args>
|
||||
void enqueue(const T_Element& value, const T_Element& mask, T_Args... indices) {
|
||||
m_pending.emplace_back(Entry{value, mask, {indices...}});
|
||||
}
|
||||
|
||||
@ -1739,7 +1739,7 @@ public:
|
||||
void commit(T_Commit& target) {
|
||||
if (m_pending.empty()) return;
|
||||
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 ...
|
||||
const auto oldValue = ref;
|
||||
ref = bOr(bAnd(entry.value, entry.mask), bAnd(oldValue, bNot(entry.mask)));
|
||||
@ -1961,13 +1961,13 @@ public:
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
static inline bool VL_CAST_DYNAMIC(VlClassRef<T> in, VlClassRef<U>& outr) {
|
||||
template <typename T_Lhs, typename T_Out>
|
||||
static inline bool VL_CAST_DYNAMIC(VlClassRef<T_Lhs> in, VlClassRef<T_Out>& outr) {
|
||||
if (!in) {
|
||||
outr = VlNull{};
|
||||
return true;
|
||||
}
|
||||
VlClassRef<U> casted = in.template dynamicCast<U>();
|
||||
VlClassRef<T_Out> casted = in.template dynamicCast<T_Out>();
|
||||
if (VL_LIKELY(casted)) {
|
||||
outr = casted;
|
||||
return true;
|
||||
@ -1976,8 +1976,8 @@ static inline bool VL_CAST_DYNAMIC(VlClassRef<T> in, VlClassRef<U>& outr) {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline bool VL_CAST_DYNAMIC(VlNull in, VlClassRef<T>& outr) {
|
||||
template <typename T_Lhs>
|
||||
static inline bool VL_CAST_DYNAMIC(VlNull in, VlClassRef<T_Lhs>& outr) {
|
||||
outr = VlNull{};
|
||||
return true;
|
||||
}
|
||||
|
@ -230,7 +230,7 @@ class ActiveNamer final : public VNVisitor {
|
||||
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
// Specialized below for the special sensitivity classes
|
||||
template <typename SenItemKind>
|
||||
template <typename T_SenItemKind>
|
||||
AstActive*& getSpecialActive();
|
||||
|
||||
public:
|
||||
@ -246,17 +246,17 @@ public:
|
||||
}
|
||||
|
||||
// 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) {
|
||||
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 an AstActive sensitive to the given special sensitivity class (possibly pre-created)
|
||||
template <typename SenItemKind>
|
||||
template <typename T_SenItemKind>
|
||||
AstActive* getSpecialActive(FileLine* fl) {
|
||||
AstActive*& cachep = getSpecialActive<SenItemKind>();
|
||||
if (!cachep) cachep = makeSpecialActive<SenItemKind>(fl);
|
||||
AstActive*& cachep = getSpecialActive<T_SenItemKind>();
|
||||
if (!cachep) cachep = makeSpecialActive<T_SenItemKind>(fl);
|
||||
return cachep;
|
||||
}
|
||||
|
||||
|
126
src/V3Ast.h
126
src/V3Ast.h
@ -2553,21 +2553,21 @@ protected:
|
||||
inline static bool privateTypeTest(const AstNode* nodep);
|
||||
|
||||
// For internal use only.
|
||||
template <typename TargetType, typename DeclType>
|
||||
template <typename T_TargetType, typename T_DeclType>
|
||||
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 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.
|
||||
template <typename TargetType, typename DeclType>
|
||||
template <typename T_TargetType, typename T_DeclType>
|
||||
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 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:
|
||||
@ -2655,12 +2655,12 @@ private:
|
||||
using ConstCorrectAstNode =
|
||||
typename std::conditional<std::is_const<T_Arg>::value, const AstNode, AstNode>::type;
|
||||
|
||||
template <typename T_Arg, typename Callable>
|
||||
inline static void foreachImpl(ConstCorrectAstNode<T_Arg>* nodep, const Callable& f,
|
||||
template <typename T_Arg, typename T_Callable>
|
||||
inline static void foreachImpl(ConstCorrectAstNode<T_Arg>* nodep, const T_Callable& f,
|
||||
bool visitNext);
|
||||
|
||||
template <typename T_Arg, bool Default, typename Callable>
|
||||
inline static bool predicateImpl(ConstCorrectAstNode<T_Arg>* nodep, const Callable& p);
|
||||
template <typename T_Arg, bool N_Default, typename T_Callable>
|
||||
inline static bool predicateImpl(ConstCorrectAstNode<T_Arg>* nodep, const T_Callable& p);
|
||||
|
||||
public:
|
||||
// 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
|
||||
// dispatch to the callable in 'foreach' should be completely predictable by branch target
|
||||
// caches in modern CPUs, while it is basically unpredictable for VNVisitor.
|
||||
template <typename Callable>
|
||||
void foreach(Callable&& f) {
|
||||
using T_Node = typename FunctionArgNoPointerNoCV<Callable, 0>::type;
|
||||
static_assert(vlstd::is_invocable<Callable, T_Node*>::value
|
||||
template <typename T_Callable>
|
||||
void foreach(T_Callable&& f) {
|
||||
using T_Node = typename FunctionArgNoPointerNoCV<T_Callable, 0>::type;
|
||||
static_assert(vlstd::is_invocable<T_Callable, 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'");
|
||||
foreachImpl<T_Node>(this, f, /* visitNext: */ false);
|
||||
}
|
||||
|
||||
// Same as above, but for 'const' nodes
|
||||
template <typename Callable>
|
||||
void foreach(Callable&& f) const {
|
||||
using T_Node = typename FunctionArgNoPointerNoCV<Callable, 0>::type;
|
||||
static_assert(vlstd::is_invocable<Callable, const T_Node*>::value
|
||||
&& std::is_base_of<AstNode, T_Node>::value,
|
||||
"Callable 'f' must have a signature compatible with 'void(const T_Node*)', "
|
||||
"with 'T_Node' being a subtype of 'AstNode'");
|
||||
template <typename T_Callable>
|
||||
void foreach(T_Callable&& f) const {
|
||||
using T_Node = typename FunctionArgNoPointerNoCV<T_Callable, 0>::type;
|
||||
static_assert(
|
||||
vlstd::is_invocable<T_Callable, const T_Node*>::value
|
||||
&& std::is_base_of<AstNode, T_Node>::value,
|
||||
"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);
|
||||
}
|
||||
|
||||
// Same as 'foreach' but also traverses 'this->nextp()' transitively
|
||||
template <typename Callable>
|
||||
void foreachAndNext(Callable&& f) {
|
||||
using T_Node = typename FunctionArgNoPointerNoCV<Callable, 0>::type;
|
||||
static_assert(vlstd::is_invocable<Callable, T_Node*>::value
|
||||
template <typename T_Callable>
|
||||
void foreachAndNext(T_Callable&& f) {
|
||||
using T_Node = typename FunctionArgNoPointerNoCV<T_Callable, 0>::type;
|
||||
static_assert(vlstd::is_invocable<T_Callable, 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'");
|
||||
foreachImpl<T_Node>(this, f, /* visitNext: */ true);
|
||||
}
|
||||
|
||||
// Same as above, but for 'const' nodes
|
||||
template <typename Callable>
|
||||
void foreachAndNext(Callable&& f) const {
|
||||
using T_Node = typename FunctionArgNoPointerNoCV<Callable, 0>::type;
|
||||
static_assert(vlstd::is_invocable<Callable, const T_Node*>::value
|
||||
&& std::is_base_of<AstNode, T_Node>::value,
|
||||
"Callable 'f' must have a signature compatible with 'void(const T_Node*)', "
|
||||
"with 'T_Node' being a subtype of 'AstNode'");
|
||||
template <typename T_Callable>
|
||||
void foreachAndNext(T_Callable&& f) const {
|
||||
using T_Node = typename FunctionArgNoPointerNoCV<T_Callable, 0>::type;
|
||||
static_assert(
|
||||
vlstd::is_invocable<T_Callable, const T_Node*>::value
|
||||
&& std::is_base_of<AstNode, T_Node>::value,
|
||||
"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);
|
||||
}
|
||||
|
||||
@ -2718,50 +2720,50 @@ public:
|
||||
// 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
|
||||
// be determined.
|
||||
template <typename Callable>
|
||||
bool exists(Callable&& p) {
|
||||
using T_Node = typename FunctionArgNoPointerNoCV<Callable, 0>::type;
|
||||
static_assert(vlstd::is_invocable_r<bool, Callable, T_Node*>::value
|
||||
template <typename T_Callable>
|
||||
bool exists(T_Callable&& p) {
|
||||
using T_Node = typename FunctionArgNoPointerNoCV<T_Callable, 0>::type;
|
||||
static_assert(vlstd::is_invocable_r<bool, T_Callable, T_Node*>::value
|
||||
&& std::is_base_of<AstNode, T_Node>::value,
|
||||
"Predicate 'p' must have a signature compatible with 'bool(T_Node*)', "
|
||||
"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
|
||||
template <typename Callable>
|
||||
bool exists(Callable&& p) const {
|
||||
using T_Node = typename FunctionArgNoPointerNoCV<Callable, 0>::type;
|
||||
static_assert(vlstd::is_invocable_r<bool, Callable, const T_Node*>::value
|
||||
template <typename T_Callable>
|
||||
bool exists(T_Callable&& p) const {
|
||||
using T_Node = typename FunctionArgNoPointerNoCV<T_Callable, 0>::type;
|
||||
static_assert(vlstd::is_invocable_r<bool, T_Callable, const T_Node*>::value
|
||||
&& std::is_base_of<AstNode, T_Node>::value,
|
||||
"Predicate 'p' must have a signature compatible with 'bool(const T_Node*)', "
|
||||
"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
|
||||
// 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
|
||||
// in some arbitrary order and is terminated as soon as the result can be determined.
|
||||
template <typename Callable>
|
||||
bool forall(Callable&& p) {
|
||||
using T_Node = typename FunctionArgNoPointerNoCV<Callable, 0>::type;
|
||||
static_assert(vlstd::is_invocable_r<bool, Callable, T_Node*>::value
|
||||
template <typename T_Callable>
|
||||
bool forall(T_Callable&& p) {
|
||||
using T_Node = typename FunctionArgNoPointerNoCV<T_Callable, 0>::type;
|
||||
static_assert(vlstd::is_invocable_r<bool, T_Callable, T_Node*>::value
|
||||
&& std::is_base_of<AstNode, T_Node>::value,
|
||||
"Predicate 'p' must have a signature compatible with 'bool(T_Node*)', "
|
||||
"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
|
||||
template <typename Callable>
|
||||
bool forall(Callable&& p) const {
|
||||
using T_Node = typename FunctionArgNoPointerNoCV<Callable, 0>::type;
|
||||
static_assert(vlstd::is_invocable_r<bool, Callable, const T_Node*>::value
|
||||
template <typename T_Callable>
|
||||
bool forall(T_Callable&& p) const {
|
||||
using T_Node = typename FunctionArgNoPointerNoCV<T_Callable, 0>::type;
|
||||
static_assert(vlstd::is_invocable_r<bool, T_Callable, const T_Node*>::value
|
||||
&& std::is_base_of<AstNode, T_Node>::value,
|
||||
"Predicate 'p' must have a signature compatible with 'bool(const T_Node*)', "
|
||||
"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 {
|
||||
@ -2834,8 +2836,8 @@ constexpr bool AstNode::isLeaf<AstVarXRef>() {
|
||||
}
|
||||
|
||||
// foreach implementation
|
||||
template <typename T_Arg, typename Callable>
|
||||
void AstNode::foreachImpl(ConstCorrectAstNode<T_Arg>* nodep, const Callable& f, bool visitNext) {
|
||||
template <typename T_Arg, typename T_Callable>
|
||||
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
|
||||
// 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
|
||||
@ -2915,8 +2917,8 @@ void AstNode::foreachImpl(ConstCorrectAstNode<T_Arg>* nodep, const Callable& f,
|
||||
}
|
||||
|
||||
// predicate implementation
|
||||
template <typename T_Arg, bool Default, typename Callable>
|
||||
bool AstNode::predicateImpl(ConstCorrectAstNode<T_Arg>* nodep, const Callable& p) {
|
||||
template <typename T_Arg, bool N_Default, typename T_Callable>
|
||||
bool AstNode::predicateImpl(ConstCorrectAstNode<T_Arg>* nodep, const T_Callable& p) {
|
||||
// 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 Node = ConstCorrectAstNode<T_Arg>;
|
||||
@ -2951,7 +2953,7 @@ bool AstNode::predicateImpl(ConstCorrectAstNode<T_Arg>* nodep, const Callable& p
|
||||
// Type test this node
|
||||
if (AstNode::privateTypeTest<T_Arg_NonConst>(currp)) {
|
||||
// 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
|
||||
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
|
||||
if (visit(nodep)) return !Default;
|
||||
if (visit(nodep)) return !N_Default;
|
||||
|
||||
// Visit the rest of the tree
|
||||
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();
|
||||
|
||||
// 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) {
|
||||
|
@ -2401,13 +2401,13 @@ public:
|
||||
// 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
|
||||
// not be found by this.
|
||||
template <typename Callable>
|
||||
void foreachMember(const Callable& f) {
|
||||
using T_Node = typename FunctionArgNoPointerNoCV<Callable, 1>::type;
|
||||
template <typename T_Callable>
|
||||
void foreachMember(const T_Callable& f) {
|
||||
using T_Node = typename FunctionArgNoPointerNoCV<T_Callable, 1>::type;
|
||||
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,
|
||||
"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'");
|
||||
if (AstClassExtends* const cextendsp = this->extendsp()) {
|
||||
cextendsp->classp()->foreachMember(f);
|
||||
@ -2417,13 +2417,14 @@ public:
|
||||
}
|
||||
}
|
||||
// Same as above, but stops after first match
|
||||
template <typename Callable>
|
||||
bool existsMember(const Callable& p) const {
|
||||
using T_Node = typename FunctionArgNoPointerNoCV<Callable, 1>::type;
|
||||
static_assert(vlstd::is_invocable_r<bool, Callable, const AstClass*, const T_Node*>::value
|
||||
&& std::is_base_of<AstNode, T_Node>::value,
|
||||
"Predicate 'p' must have a signature compatible with 'bool(const AstClass*, "
|
||||
"const T_Node*)', with 'T_Node' being a subtype of 'AstNode'");
|
||||
template <typename T_Callable>
|
||||
bool existsMember(const T_Callable& p) const {
|
||||
using T_Node = typename FunctionArgNoPointerNoCV<T_Callable, 1>::type;
|
||||
static_assert(
|
||||
vlstd::is_invocable_r<bool, T_Callable, const AstClass*, const T_Node*>::value
|
||||
&& std::is_base_of<AstNode, T_Node>::value,
|
||||
"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 (cextendsp->classp()->existsMember(p)) return true;
|
||||
}
|
||||
|
@ -27,22 +27,22 @@
|
||||
#include <utility>
|
||||
#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 {
|
||||
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");
|
||||
|
||||
private:
|
||||
std::deque<T_Data> m_allocated;
|
||||
|
||||
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();
|
||||
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();
|
||||
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();
|
||||
return user.to<T_Data*>();
|
||||
} else {
|
||||
@ -52,11 +52,11 @@ private:
|
||||
}
|
||||
|
||||
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});
|
||||
} else if VL_CONSTEXPR_CXX17 (T_UserN == 2) {
|
||||
} else if VL_CONSTEXPR_CXX17 (N_UserN == 2) {
|
||||
nodep->user2u(VNUser{userp});
|
||||
} else if VL_CONSTEXPR_CXX17 (T_UserN == 3) {
|
||||
} else if VL_CONSTEXPR_CXX17 (N_UserN == 3) {
|
||||
nodep->user3u(VNUser{userp});
|
||||
} else {
|
||||
nodep->user4u(VNUser{userp});
|
||||
@ -65,11 +65,11 @@ private:
|
||||
|
||||
protected:
|
||||
AstUserAllocatorBase() {
|
||||
if VL_CONSTEXPR_CXX17 (T_UserN == 1) {
|
||||
if VL_CONSTEXPR_CXX17 (N_UserN == 1) {
|
||||
VNUser1InUse::check();
|
||||
} else if VL_CONSTEXPR_CXX17 (T_UserN == 2) {
|
||||
} else if VL_CONSTEXPR_CXX17 (N_UserN == 2) {
|
||||
VNUser2InUse::check();
|
||||
} else if VL_CONSTEXPR_CXX17 (T_UserN == 3) {
|
||||
} else if VL_CONSTEXPR_CXX17 (N_UserN == 3) {
|
||||
VNUser3InUse::check();
|
||||
} else {
|
||||
VNUser4InUse::check();
|
||||
|
@ -534,17 +534,17 @@ class DelayedVisitor final : public VNVisitor {
|
||||
}
|
||||
|
||||
// Scheme::ValueQueuePartial/Scheme::ValueQueueWhole
|
||||
template <bool Partial>
|
||||
template <bool N_Partial>
|
||||
void prepareSchemeValueQueue(AstVarScope* vscp, VarScopeInfo& vscpInfo) {
|
||||
UASSERT_OBJ(Partial ? vscpInfo.m_scheme == Scheme::ValueQueuePartial
|
||||
: vscpInfo.m_scheme == Scheme::ValueQueueWhole,
|
||||
UASSERT_OBJ(N_Partial ? vscpInfo.m_scheme == Scheme::ValueQueuePartial
|
||||
: vscpInfo.m_scheme == Scheme::ValueQueueWhole,
|
||||
vscp, "Inconsisten<t NBA s>cheme");
|
||||
FileLine* const flp = vscp->fileline();
|
||||
AstScope* const scopep = vscp->scopep();
|
||||
|
||||
// Create the commit queue variable
|
||||
auto* const cqDTypep
|
||||
= new AstNBACommitQueueDType{flp, vscp->dtypep()->skipRefp(), Partial};
|
||||
= new AstNBACommitQueueDType{flp, vscp->dtypep()->skipRefp(), N_Partial};
|
||||
v3Global.rootp()->typeTablep()->addTypesp(cqDTypep);
|
||||
const std::string name = "__VdlyCommitQueue" + vscp->varp()->shortName();
|
||||
AstVarScope* const queueVscp = createTemp(flp, scopep, name, cqDTypep);
|
||||
|
38
src/V3Dfg.h
38
src/V3Dfg.h
@ -427,52 +427,52 @@ public:
|
||||
// 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 {
|
||||
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:
|
||||
DfgVertexWithArity(DfgGraph& dfg, VDfgType type, FileLine* flp, AstNodeDType* dtypep)
|
||||
: DfgVertex{dfg, type, flp, dtypep} {
|
||||
// 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;
|
||||
|
||||
public:
|
||||
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 {
|
||||
return {m_srcs.data(), Arity};
|
||||
return {m_srcs.data(), N_Arity};
|
||||
}
|
||||
|
||||
template <size_t Index>
|
||||
template <size_t N_Index>
|
||||
DfgEdge* sourceEdge() {
|
||||
static_assert(Index < Arity, "Source index out of range");
|
||||
return &m_srcs[Index];
|
||||
static_assert(N_Index < N_Arity, "Source index out of range");
|
||||
return &m_srcs[N_Index];
|
||||
}
|
||||
|
||||
template <size_t Index>
|
||||
template <size_t N_Index>
|
||||
const DfgEdge* sourceEdge() const {
|
||||
static_assert(Index < Arity, "Source index out of range");
|
||||
return &m_srcs[Index];
|
||||
static_assert(N_Index < N_Arity, "Source index out of range");
|
||||
return &m_srcs[N_Index];
|
||||
}
|
||||
|
||||
template <size_t Index>
|
||||
template <size_t N_Index>
|
||||
DfgVertex* source() const {
|
||||
static_assert(Index < Arity, "Source index out of range");
|
||||
return m_srcs[Index].sourcep();
|
||||
static_assert(N_Index < N_Arity, "Source index out of range");
|
||||
return m_srcs[N_Index].sourcep();
|
||||
}
|
||||
|
||||
template <size_t Index>
|
||||
template <size_t N_Index>
|
||||
void relinkSource(DfgVertex* newSourcep) {
|
||||
static_assert(Index < Arity, "Source index out of range");
|
||||
UASSERT_OBJ(m_srcs[Index].sinkp() == this, this, "Inconsistent");
|
||||
m_srcs[Index].relinkSource(newSourcep);
|
||||
static_assert(N_Index < N_Arity, "Source index out of range");
|
||||
UASSERT_OBJ(m_srcs[N_Index].sinkp() == this, this, "Inconsistent");
|
||||
m_srcs[N_Index].relinkSource(newSourcep);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -37,9 +37,9 @@ namespace {
|
||||
|
||||
// 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
|
||||
template <typename Vertex, typename Node>
|
||||
Vertex* makeVertex(const Node* nodep, DfgGraph& dfg) {
|
||||
return new Vertex{dfg, nodep->fileline(), DfgVertex::dtypeFor(nodep)};
|
||||
template <typename T_Vertex, typename T_Node>
|
||||
T_Vertex* makeVertex(const T_Node* nodep, DfgGraph& dfg) {
|
||||
return new T_Vertex{dfg, nodep->fileline(), DfgVertex::dtypeFor(nodep)};
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
@ -157,8 +157,8 @@ public:
|
||||
};
|
||||
};
|
||||
|
||||
template <typename Key, typename Val>
|
||||
using Cache = std::unordered_map<Key, Val, typename Key::Hash, typename Key::Equal>;
|
||||
template <typename T_Key, typename T_Val>
|
||||
using Cache = std::unordered_map<T_Key, T_Val, typename T_Key::Hash, typename T_Key::Equal>;
|
||||
|
||||
using CacheSel = Cache<KeySel, DfgSel*>;
|
||||
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
|
||||
template <typename Vertex, typename Cache, typename... Operands>
|
||||
inline Vertex* getOrCreate(DfgGraph& dfg, FileLine* flp, AstNodeDType* dtypep, Cache& cache,
|
||||
template <typename Vertex, typename T_Cache, typename... Operands>
|
||||
inline Vertex* getOrCreate(DfgGraph& dfg, FileLine* flp, AstNodeDType* dtypep, T_Cache& cache,
|
||||
Operands... operands) {
|
||||
typename Cache::mapped_type& entrypr = getEntry(cache, dtypep, operands...);
|
||||
typename T_Cache::mapped_type& entrypr = getEntry(cache, dtypep, operands...);
|
||||
if (!entrypr) {
|
||||
Vertex* const newp = new Vertex{dfg, flp, dtypep};
|
||||
setOperands(newp, operands...);
|
||||
|
@ -40,9 +40,9 @@ namespace {
|
||||
|
||||
// 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
|
||||
template <typename Node, typename Vertex, typename... Ops>
|
||||
Node* makeNode(const Vertex* vtxp, Ops... ops) {
|
||||
Node* const nodep = new Node{vtxp->fileline(), ops...};
|
||||
template <typename T_Node, typename T_Vertex, typename... Ops>
|
||||
T_Node* makeNode(const T_Vertex* vtxp, Ops... ops) {
|
||||
T_Node* const nodep = new T_Node{vtxp->fileline(), ops...};
|
||||
UASSERT_OBJ(nodep->width() == static_cast<int>(vtxp->width()), vtxp,
|
||||
"Incorrect width in AstNode created from DfgVertex "
|
||||
<< vtxp->typeName() << ": " << nodep->width() << " vs " << vtxp->width());
|
||||
|
@ -146,8 +146,8 @@ public:
|
||||
void emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* modp, bool cLinkage = false);
|
||||
void emitVarDecl(const AstVar* nodep, bool asRef = false);
|
||||
void emitVarAccessors(const AstVar* nodep);
|
||||
template <typename F>
|
||||
static void forModCUse(const AstNodeModule* modp, VUseType useType, F action) {
|
||||
template <typename T_Callable>
|
||||
static void forModCUse(const AstNodeModule* modp, VUseType useType, T_Callable action) {
|
||||
for (AstNode* itemp = modp->stmtsp(); itemp; itemp = itemp->nextp()) {
|
||||
if (AstCUse* const usep = VN_CAST(itemp, CUse)) {
|
||||
if (usep->useType().containsAny(useType)) {
|
||||
|
@ -36,8 +36,8 @@ class CMakeEmitter final {
|
||||
// STATIC FUNCTIONS
|
||||
|
||||
// Concatenate all strings in 'strs' with ' ' between them.
|
||||
template <typename List>
|
||||
static string cmake_list(const List& strs) {
|
||||
template <typename T_List>
|
||||
static string cmake_list(const T_List& strs) {
|
||||
string s;
|
||||
for (auto it = strs.begin(); it != strs.end(); ++it) {
|
||||
s += '"';
|
||||
|
@ -32,25 +32,25 @@ struct FunctionTraits final
|
||||
: public FunctionTraits<decltype(&std::remove_reference<T>::type::operator())> {};
|
||||
|
||||
// Specialization for pointers to member function
|
||||
template <typename ClassType, typename ReturnType, typename... Args>
|
||||
struct FunctionTraits<ReturnType (ClassType::*)(Args...) const> VL_NOT_FINAL {
|
||||
template <typename T_ClassType, typename T_ReturnType, typename... Args>
|
||||
struct FunctionTraits<T_ReturnType (T_ClassType::*)(Args...) const> VL_NOT_FINAL {
|
||||
// Number of arguments
|
||||
static constexpr size_t arity = sizeof...(Args);
|
||||
|
||||
// Type of result
|
||||
using result_type = ReturnType;
|
||||
using result_type = T_ReturnType;
|
||||
|
||||
// Type of arguments
|
||||
template <std::size_t I>
|
||||
template <std::size_t N>
|
||||
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 {
|
||||
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 type = typename std::remove_cv<T_ArgNoPtr>::type;
|
||||
};
|
||||
|
@ -79,12 +79,12 @@ void V3GraphVertex::rerouteEdges(V3Graph* graphp) {
|
||||
unlinkEdges(graphp);
|
||||
}
|
||||
|
||||
template <GraphWay::en T_Way>
|
||||
template <GraphWay::en N_Way>
|
||||
V3GraphEdge* V3GraphVertex::findConnectingEdgep(V3GraphVertex* waywardp) {
|
||||
// O(edges) linear search. Searches search both nodes' edge lists in
|
||||
// parallel. The lists probably aren't _both_ huge, so this is
|
||||
// unlikely to blow up even on fairly nasty graphs.
|
||||
constexpr GraphWay way{T_Way};
|
||||
constexpr GraphWay way{N_Way};
|
||||
constexpr GraphWay inv = way.invert();
|
||||
auto& aEdges = this->edges<way>();
|
||||
auto aIt = aEdges.begin();
|
||||
|
@ -187,9 +187,9 @@ public:
|
||||
uint64_t user() const { return m_user; }
|
||||
V3GraphVertex* fromp() const { return m_fromp; }
|
||||
V3GraphVertex* top() const { return m_top; }
|
||||
template <GraphWay::en T_Way>
|
||||
template <GraphWay::en N_Way>
|
||||
V3GraphVertex* furtherp() const {
|
||||
return T_Way == GraphWay::FORWARD ? top() : fromp();
|
||||
return N_Way == GraphWay::FORWARD ? top() : fromp();
|
||||
}
|
||||
// STATIC ACCESSORS
|
||||
static bool followNotCutable(const V3GraphEdge* edgep) { return !edgep->m_cutable; }
|
||||
@ -301,9 +301,9 @@ public:
|
||||
void* userp() const VL_MT_STABLE { return m_userp; }
|
||||
V3GraphEdge::IList& inEdges() { return m_ins; }
|
||||
const V3GraphEdge::IList& inEdges() const { return m_ins; }
|
||||
template <GraphWay::en T_Way>
|
||||
template <GraphWay::en N_Way>
|
||||
inline auto& edges();
|
||||
template <GraphWay::en T_Way>
|
||||
template <GraphWay::en N_Way>
|
||||
inline const auto& edges() const;
|
||||
bool inEmpty() const { return m_ins.empty(); }
|
||||
bool inSize1() const { return m_ins.hasSingleElement(); }
|
||||
@ -320,7 +320,7 @@ public:
|
||||
void rerouteEdges(V3Graph* graphp) VL_MT_DISABLED;
|
||||
// Find the edge connecting this vertex to the given vertex.
|
||||
// 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;
|
||||
};
|
||||
|
||||
|
@ -53,9 +53,9 @@ struct GraphPCNode final {
|
||||
//######################################################################
|
||||
// GraphPathChecker implementation
|
||||
|
||||
template <GraphWay::en T_Way>
|
||||
template <GraphWay::en N_Way>
|
||||
void GraphPathChecker::initHalfCriticalPaths(bool checkOnly) {
|
||||
constexpr GraphWay way{T_Way};
|
||||
constexpr GraphWay way{N_Way};
|
||||
constexpr GraphWay rev = way.invert();
|
||||
GraphStreamUnordered order(m_graphp, way);
|
||||
while (const V3GraphVertex* const vertexp = order.nextp()) {
|
||||
|
@ -53,7 +53,7 @@ public:
|
||||
private:
|
||||
bool pathExistsInternal(const V3GraphVertex* ap, const V3GraphVertex* bp,
|
||||
unsigned* costp = nullptr) VL_MT_DISABLED;
|
||||
template <GraphWay::en T_Way>
|
||||
template <GraphWay::en N_Way>
|
||||
void initHalfCriticalPaths(bool checkOnly) VL_MT_DISABLED;
|
||||
void incGeneration() { ++m_generation; }
|
||||
|
||||
|
@ -264,9 +264,9 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
template <uint8_t T_Way> //
|
||||
template <uint8_t N_Way> //
|
||||
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
|
||||
for (V3GraphVertex& vertex : graphp->vertices()) {
|
||||
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) {
|
||||
constexpr GraphWay way{T_Way};
|
||||
constexpr GraphWay way{N_Way};
|
||||
for (const V3GraphEdge& edge : resultp->edges<way>()) {
|
||||
V3GraphVertex* const vertexp = edge.furtherp<way>();
|
||||
#if VL_DEBUG
|
||||
|
18
src/V3List.h
18
src/V3List.h
@ -89,7 +89,7 @@ class V3List final {
|
||||
|
||||
// Iterator class template for V3List. This is just enough to support range based for loops
|
||||
// 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 {
|
||||
static_assert(std::is_same<T_IteratorElement, 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>
|
||||
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
|
||||
|
||||
@ -109,7 +109,7 @@ class V3List final {
|
||||
|
||||
VL_ATTR_ALWINLINE
|
||||
static T_Base* step(T_Base* currp) {
|
||||
if VL_CONSTEXPR_CXX17 (T_Reverse) {
|
||||
if VL_CONSTEXPR_CXX17 (N_Reverse) {
|
||||
return toLinks(currp).m_prevp;
|
||||
} else {
|
||||
return toLinks(currp).m_nextp;
|
||||
@ -145,8 +145,8 @@ class V3List final {
|
||||
bool operator!=(const IteratorType& other) const { return m_currp != other.m_currp; }
|
||||
// Convert to const iterator
|
||||
VL_ATTR_ALWINLINE
|
||||
operator SimpleItertatorImpl<const T_IteratorElement, T_Reverse>() const {
|
||||
return SimpleItertatorImpl<const T_IteratorElement, T_Reverse>{m_currp};
|
||||
operator SimpleItertatorImpl<const T_IteratorElement, N_Reverse>() const {
|
||||
return SimpleItertatorImpl<const T_IteratorElement, N_Reverse>{m_currp};
|
||||
}
|
||||
};
|
||||
|
||||
@ -221,10 +221,10 @@ class V3List final {
|
||||
};
|
||||
|
||||
public:
|
||||
using iterator = SimpleItertatorImpl<T_Element, /* T_Reverse: */ false>;
|
||||
using const_iterator = SimpleItertatorImpl<const T_Element, /* T_Reverse: */ false>;
|
||||
using reverse_iterator = SimpleItertatorImpl<T_Element, /* T_Reverse: */ true>;
|
||||
using const_reverse_iterator = SimpleItertatorImpl<const T_Element, /* T_Reverse: */ true>;
|
||||
using iterator = SimpleItertatorImpl<T_Element, /* N_Reverse: */ false>;
|
||||
using const_iterator = SimpleItertatorImpl<const T_Element, /* N_Reverse: */ false>;
|
||||
using reverse_iterator = SimpleItertatorImpl<T_Element, /* N_Reverse: */ true>;
|
||||
using const_reverse_iterator = SimpleItertatorImpl<const T_Element, /* N_Reverse: */ true>;
|
||||
|
||||
// CONSTRUCTOR
|
||||
V3List() = default;
|
||||
|
@ -37,14 +37,14 @@ struct V3OptionParser::Impl final {
|
||||
VALUE // "-opt val"
|
||||
};
|
||||
// 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 {
|
||||
bool m_undocumented = false; // This option is not documented
|
||||
public:
|
||||
bool isValueNeeded() const override final { return MODE == en::VALUE; }
|
||||
bool isFOnOffAllowed() const override final { return MODE == en::FONOFF; }
|
||||
bool isOnOffAllowed() const override final { return MODE == en::ONOFF; }
|
||||
bool isPartialMatchAllowed() const override final { return ALLOW_PARTIAL_MATCH; }
|
||||
bool isValueNeeded() const override final { return N_Mode == en::VALUE; }
|
||||
bool isFOnOffAllowed() const override final { return N_Mode == en::FONOFF; }
|
||||
bool isOnOffAllowed() const override final { return N_Mode == en::ONOFF; }
|
||||
bool isPartialMatchAllowed() const override final { return N_Allow_Partial_Match; }
|
||||
bool isUndocumented() const override { return m_undocumented; }
|
||||
void undocumented() override { m_undocumented = true; }
|
||||
};
|
||||
@ -52,9 +52,9 @@ struct V3OptionParser::Impl final {
|
||||
// Actual action classes
|
||||
template <typename T>
|
||||
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
|
||||
template <typename BOOL>
|
||||
template <typename N_Bool>
|
||||
class ActionOnOff; // "-opt" and "-no-opt" for bool-ish
|
||||
class ActionCbCall; // Callback without argument for "-opt"
|
||||
class ActionCbFOnOff; // Callback for "-fopt" and "-fno-opt"
|
||||
@ -171,10 +171,10 @@ V3OptionParser::ActionIfs* V3OptionParser::find(const char* optp) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename ACT, typename ARG>
|
||||
V3OptionParser::ActionIfs& V3OptionParser::add(const std::string& opt, ARG arg) {
|
||||
template <typename T_Act, typename T_Arg>
|
||||
V3OptionParser::ActionIfs& V3OptionParser::add(const std::string& opt, T_Arg arg) {
|
||||
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[0] == '-' || opt[0] == '+', opt << " does not start with either '-' or '+'");
|
||||
UASSERT(!(opt[0] == '-' && opt[1] == '-'), "Option must have single '-', but " << opt);
|
||||
|
@ -65,8 +65,8 @@ private:
|
||||
|
||||
// METHODS
|
||||
ActionIfs* find(const char* optp) VL_MT_DISABLED;
|
||||
template <typename ACT, typename ARG>
|
||||
ActionIfs& add(const string& opt, ARG arg) VL_MT_DISABLED;
|
||||
template <typename T_Act, typename T_Arg>
|
||||
ActionIfs& add(const string& opt, T_Arg arg) VL_MT_DISABLED;
|
||||
// Returns true if strp starts with "-fno"
|
||||
static bool hasPrefixFNo(const char* strp) VL_MT_DISABLED;
|
||||
// Returns true if strp starts with "-no"
|
||||
|
@ -268,7 +268,7 @@ static_assert(!std::is_polymorphic<SiblingMC>::value, "Should not have a vtable"
|
||||
class MTaskEdge final : public V3GraphEdge, public MergeCandidate {
|
||||
VL_RTTI_IMPL(MTaskEdge, V3GraphEdge)
|
||||
friend class LogicMTask;
|
||||
template <GraphWay::en T_Way>
|
||||
template <GraphWay::en N_Way>
|
||||
friend class PropagateCp;
|
||||
|
||||
// MEMBERS
|
||||
@ -280,7 +280,7 @@ public:
|
||||
// CONSTRUCTORS
|
||||
MTaskEdge(V3Graph* graphp, LogicMTask* fromp, LogicMTask* top, int weight);
|
||||
// METHODS
|
||||
template <GraphWay::en T_Way>
|
||||
template <GraphWay::en N_Way>
|
||||
inline LogicMTask* furtherMTaskp() const;
|
||||
inline LogicMTask* fromMTaskp() const;
|
||||
inline LogicMTask* toMTaskp() const;
|
||||
@ -307,7 +307,7 @@ private:
|
||||
|
||||
class LogicMTask final : public V3GraphVertex {
|
||||
VL_RTTI_IMPL(LogicMTask, V3GraphVertex)
|
||||
template <GraphWay::en T_Way>
|
||||
template <GraphWay::en N_Way>
|
||||
friend class PropagateCp;
|
||||
|
||||
public:
|
||||
@ -419,28 +419,28 @@ public:
|
||||
#endif
|
||||
}
|
||||
|
||||
template <GraphWay::en T_Way>
|
||||
template <GraphWay::en N_Way>
|
||||
void addRelativeEdge(MTaskEdge* edgep) {
|
||||
constexpr GraphWay way{T_Way};
|
||||
constexpr GraphWay way{N_Way};
|
||||
constexpr GraphWay inv = way.invert();
|
||||
// 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
|
||||
const uint32_t cp = relativep->stepCost() + relativep->critPathCost(inv);
|
||||
//
|
||||
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) {
|
||||
constexpr GraphWay way{T_Way};
|
||||
constexpr GraphWay way{N_Way};
|
||||
// Make heap node insertable, ruining the heap it is currently in.
|
||||
edgep->m_edgeHeapNode[way].yank();
|
||||
// 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) {
|
||||
constexpr GraphWay way{T_Way};
|
||||
constexpr GraphWay way{N_Way};
|
||||
// Remove from the edge heap
|
||||
m_edgeHeap[way].remove(&edgep->m_edgeHeapNode[way]);
|
||||
}
|
||||
@ -456,12 +456,12 @@ public:
|
||||
}
|
||||
bool hasRelativeMTask(LogicMTask* relativep) const { return m_edgeSet.count(relativep); }
|
||||
|
||||
template <GraphWay::en T_Way>
|
||||
template <GraphWay::en N_Way>
|
||||
void checkRelativesCp() const {
|
||||
constexpr GraphWay way{T_Way};
|
||||
for (const V3GraphEdge& edge : edges<T_Way>()) {
|
||||
constexpr GraphWay way{N_Way};
|
||||
for (const V3GraphEdge& edge : edges<N_Way>()) {
|
||||
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 cp = relativep->critPathCost(way.invert()) + relativep->stepCost();
|
||||
partCheckCachedScoreVsActual(cachedCp, cp);
|
||||
@ -479,14 +479,14 @@ public:
|
||||
|
||||
void setCritPathCost(GraphWay way, uint32_t cost) { m_critPathCost[way] = cost; }
|
||||
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 {
|
||||
const GraphWay way{T_Way};
|
||||
const GraphWay way{N_Way};
|
||||
const GraphWay inv = way.invert();
|
||||
// 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', 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'"););
|
||||
const EdgeHeap& edgeHeap = m_edgeHeap[inv];
|
||||
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);
|
||||
}
|
||||
|
||||
template <GraphWay::en T_Way>
|
||||
template <GraphWay::en N_Way>
|
||||
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::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
|
||||
// vertex.
|
||||
template <GraphWay::en T_Way>
|
||||
template <GraphWay::en N_Way>
|
||||
static void partInitHalfCriticalPaths(V3Graph& mTaskGraph, bool checkOnly) {
|
||||
constexpr GraphWay way{T_Way};
|
||||
constexpr GraphWay way{N_Way};
|
||||
constexpr GraphWay rev = way.invert();
|
||||
GraphStreamUnordered order{&mTaskGraph, way};
|
||||
for (const V3GraphVertex* vertexp; (vertexp = order.nextp());) {
|
||||
@ -776,7 +776,7 @@ static void partCheckCriticalPaths(V3Graph& mTaskGraph) {
|
||||
// ######################################################################
|
||||
// PropagateCp
|
||||
|
||||
template <GraphWay::en T_Way>
|
||||
template <GraphWay::en N_Way>
|
||||
class PropagateCp final {
|
||||
// Propagate increasing critical path (CP) costs through a graph.
|
||||
//
|
||||
@ -862,7 +862,7 @@ private:
|
||||
|
||||
public:
|
||||
void cpHasIncreased(V3GraphVertex* vxp, uint32_t newInclusiveCp) {
|
||||
constexpr GraphWay way{T_Way};
|
||||
constexpr GraphWay way{N_Way};
|
||||
constexpr GraphWay inv{way.invert()};
|
||||
|
||||
// For *vxp, whose CP-inclusive has just increased to
|
||||
@ -871,7 +871,7 @@ public:
|
||||
for (V3GraphEdge& graphEdge : vxp->edges<way>()) {
|
||||
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];
|
||||
if (newInclusiveCp > edgeHeapNode.key().m_score) {
|
||||
relativep->m_edgeHeap[inv].increaseKey(&edgeHeapNode, newInclusiveCp);
|
||||
@ -899,7 +899,7 @@ public:
|
||||
}
|
||||
|
||||
void go() {
|
||||
constexpr GraphWay way{T_Way};
|
||||
constexpr GraphWay way{N_Way};
|
||||
constexpr GraphWay inv{way.invert()};
|
||||
|
||||
// m_pending maps each pending vertex to the amount that it wayward
|
||||
@ -982,7 +982,7 @@ public:
|
||||
|
||||
partInitCriticalPaths(graph);
|
||||
|
||||
PropagateCp<T_Way> prop{true};
|
||||
PropagateCp<N_Way> prop{true};
|
||||
|
||||
// Seed the propagator with every input node;
|
||||
// This should result in the complete graph getting all CP's assigned.
|
||||
@ -1316,9 +1316,9 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
template <GraphWay::en T_Way>
|
||||
template <GraphWay::en N_Way>
|
||||
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
|
||||
// with otherp. Set 'result.propagate' if mtaskp's wayward
|
||||
// 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) {
|
||||
constexpr GraphWay way{T_Way};
|
||||
constexpr GraphWay way{N_Way};
|
||||
// Need at least 2 edges
|
||||
auto& edges = mtaskp->edges<way>();
|
||||
if (!edges.hasMultipleElements()) return;
|
||||
@ -1575,7 +1575,7 @@ private:
|
||||
// Just make a few pairs.
|
||||
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)
|
||||
std::sort(sortRecs.begin(), sortRecs.begin() + n);
|
||||
for (size_t i = 0; i < end; i += 2) {
|
||||
|
@ -934,14 +934,14 @@ class CaptureVisitor final : public VNVisitor {
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename NodeT>
|
||||
void fixupClassOrPackage(AstNode* memberp, NodeT refp) {
|
||||
template <typename T_Node>
|
||||
void fixupClassOrPackage(AstNode* memberp, T_Node refp) {
|
||||
AstNodeModule* const declClassp = VN_AS(memberp->user2p(), NodeModule);
|
||||
if (declClassp != m_targetp) refp->classOrPackagep(declClassp);
|
||||
}
|
||||
|
||||
template <typename NodeT>
|
||||
bool isReferenceToInnerMember(NodeT nodep) {
|
||||
template <typename T_Node>
|
||||
bool isReferenceToInnerMember(T_Node nodep) {
|
||||
return VN_IS(nodep->fromp(), LambdaArgRef);
|
||||
}
|
||||
|
||||
|
@ -233,8 +233,8 @@ class TimingSuspendableVisitor final : public VNVisitor {
|
||||
if (passFlag(parentp, depp, flag)) propagateFlags(depVxp, flag);
|
||||
}
|
||||
}
|
||||
template <typename Predicate>
|
||||
void propagateFlagsIf(DepVtx* const vxp, NodeFlag flag, Predicate p) {
|
||||
template <typename T_Predicate>
|
||||
void propagateFlagsIf(DepVtx* const vxp, NodeFlag flag, T_Predicate p) {
|
||||
auto* const parentp = vxp->nodep();
|
||||
for (V3GraphEdge& edge : vxp->outEdges()) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
template <typename Predicate>
|
||||
void propagateFlagsReversedIf(DepVtx* const vxp, NodeFlag flag, Predicate p) {
|
||||
template <typename T_Predicate>
|
||||
void propagateFlagsReversedIf(DepVtx* const vxp, NodeFlag flag, T_Predicate p) {
|
||||
auto* const parentp = vxp->nodep();
|
||||
for (V3GraphEdge& edge : vxp->inEdges()) {
|
||||
auto* const depVxp = static_cast<DepVtx*>(edge.fromp());
|
||||
|
Loading…
Reference in New Issue
Block a user