From 5c9a804e8b214917f0773f46fe1697860dc3f71f Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Fri, 2 Oct 2026 21:19:10 +0200 Subject: [PATCH] Internals: Add range Left/Right/Lo/Hi iterable sequences (#8585) --- src/V3AstAttr.h | 36 ++++++++++++++++++++++++++++++++++++ src/V3AstNodeOther.h | 8 ++++++++ src/V3Const.cpp | 6 +----- src/V3Coverage.cpp | 4 ++-- src/V3LinkParse.cpp | 6 ++---- src/V3Param.cpp | 10 ++-------- src/V3TraceDecl.cpp | 6 ++---- src/V3Width.cpp | 6 +++--- 8 files changed, 56 insertions(+), 26 deletions(-) diff --git a/src/V3AstAttr.h b/src/V3AstAttr.h index b3680a428..efe5bb6de 100644 --- a/src/V3AstAttr.h +++ b/src/V3AstAttr.h @@ -1815,6 +1815,34 @@ inline std::ostream& operator<<(std::ostream& os, const VLifetime& rhs) { class VNumRange final { public: + // Iterable sequence of integers + class Sequence final { + class Iterator final { + int m_index; // Current index + const int m_inc; // Step, +1 or -1 + public: + Iterator(int index, int inc) + : m_index{index} + , m_inc{inc} {} + int operator*() const { return m_index; } + Iterator& operator++() { + m_index += m_inc; + return *this; + } + bool operator!=(const Iterator& that) const { return m_index != that.m_index; } + }; + const int m_begin; // First index + const int m_end; // One past the last index + const int m_inc; // Step, +1 or -1 + public: + Sequence(int first, int last, int inc) + : m_begin{first} + , m_end{last + inc} + , m_inc{inc} {} + Iterator begin() const { return Iterator{m_begin, m_inc}; } + Iterator end() const { return Iterator{m_end, m_inc}; } + }; + int m_left = 0; // Left side of range (pre-':') int m_right = 0; // Right side of range (post-':') bool m_ranged = false; // Has a range @@ -1854,6 +1882,14 @@ public: return m_left > m_right ? m_right : m_left; } // How to show a declaration int leftToRightInc() const { return ascending() ? 1 : -1; } + // Iterate indices from left() to right() inclusive: 'for (int i : range.seqLeftToRight())' + Sequence seqLeftToRight() const { return {m_left, m_right, leftToRightInc()}; } + // Iterate indices from right() to left() inclusive: 'for (int i : range.seqRightToLeft())' + Sequence seqRightToLeft() const { return {m_right, m_left, -leftToRightInc()}; } + // Iterate indices from lo() to hi() inclusive: 'for (int i : range.seqLoToHi())' + Sequence seqLoToHi() const { return {lo(), hi(), 1}; } + // Iterate indices from hi() to lo() inclusive: 'for (int i : range.seqHiToLo())' + Sequence seqHiToLo() const { return {hi(), lo(), -1}; } int elements() const VL_MT_SAFE { return hi() - lo() + 1; } bool ranged() const { return m_ranged; } bool ascending() const { return m_left < m_right; } diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 926832331..1e2e07b20 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -3420,6 +3420,14 @@ public: } int elementsConst() const VL_MT_STABLE { return hiConst() - loConst() + 1; } bool ascending() const { return leftConst() < rightConst(); } + // Iterate indices from left to right inclusive, see VNumRange::seqLeftToRight() + VNumRange::Sequence seqLeftToRight() const { + return VNumRange{leftConst(), rightConst()}.seqLeftToRight(); + } + // Iterate indices from right to left inclusive, see VNumRange::seqRightToLeft() + VNumRange::Sequence seqRightToLeft() const { + return VNumRange{leftConst(), rightConst()}.seqRightToLeft(); + } void dump(std::ostream& str) const override; void dumpJson(std::ostream& str) const override; virtual string emitC() { V3ERROR_NA_RETURN(""); } diff --git a/src/V3Const.cpp b/src/V3Const.cpp index c1c85570c..99c95e3ae 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -1015,14 +1015,10 @@ class ConstVisitor final : public VNVisitor { const bool packReal) { const AstNodeDType* const dtypep = fromp->dtypep()->skipRefp(); if (const AstUnpackArrayDType* const unpackDtypep = VN_CAST(dtypep, UnpackArrayDType)) { - const int left = unpackDtypep->left(); - const int right = unpackDtypep->right(); - const int step = left <= right ? 1 : -1; - for (int idx = left;; idx += step) { + for (const int idx : unpackDtypep->declRange().seqLeftToRight()) { AstArraySel* const selp = new AstArraySel{fromp->fileline(), fromp->cloneTreePure(false), idx}; collectFixedAggregateTerms(selp, termps, packReal); - if (idx == right) break; } VL_DO_DANGLING(pushDeletep(fromp), fromp); } else if (const AstNodeUOrStructDType* const sdtypep diff --git a/src/V3Coverage.cpp b/src/V3Coverage.cpp index f84b8ff83..ce20099ed 100644 --- a/src/V3Coverage.cpp +++ b/src/V3Coverage.cpp @@ -461,7 +461,7 @@ class CoverageVisitor final : public VNVisitor { if (const AstBasicDType* const basicp = VN_CAST(dtypep, BasicDType)) { toggleVarBottom(above, varp, basicp->nrange()); } else if (const AstUnpackArrayDType* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) { - for (int index_docs = adtypep->lo(); index_docs <= adtypep->hi(); ++index_docs) { + for (const int index_docs : adtypep->declRange().seqLoToHi()) { const int index_code = index_docs - adtypep->lo(); ToggleEnt newent{above.m_comment + "["s + cvtToStr(index_docs) + "]", new AstArraySel{varp->fileline(), @@ -472,7 +472,7 @@ class CoverageVisitor final : public VNVisitor { newent.cleanup(); } } else if (const AstPackArrayDType* const adtypep = VN_CAST(dtypep, PackArrayDType)) { - for (int index_docs = adtypep->lo(); index_docs <= adtypep->hi(); ++index_docs) { + for (const int index_docs : adtypep->declRange().seqLoToHi()) { const AstNodeDType* const subtypep = adtypep->subDTypep()->skipRefp(); const int index_code = index_docs - adtypep->lo(); ToggleEnt newent{above.m_comment + "["s + cvtToStr(index_docs) + "]", diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 55b2a92c8..c9ac97600 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -335,13 +335,10 @@ class LinkParseVisitor final : public VNVisitor { // We check this rule in the parser, so shouldn't fire nodep->v3error("Enum ranges must be integral, per spec"); } // LCOV_EXCL_STOP - const int left = nodep->rangep()->leftConst(); - const int right = nodep->rangep()->rightConst(); - const int increment = (left > right) ? -1 : 1; uint32_t offset_from_init = 0; AstEnumItem* addp = nullptr; FileLine* const flp = nodep->fileline(); - for (int i = left; i != (right + increment); i += increment, ++offset_from_init) { + for (const int i : nodep->rangep()->seqLeftToRight()) { const string name = nodep->name() + cvtToStr(i); AstNodeExpr* valuep = nullptr; if (nodep->valuep()) { @@ -351,6 +348,7 @@ class LinkParseVisitor final : public VNVisitor { new AstConst{flp, AstConst::Unsized32{}, offset_from_init}}; } addp = AstNode::addNext(addp, new AstEnumItem{flp, name, nullptr, valuep}); + ++offset_from_init; } nodep->replaceWith(addp); VL_DO_DANGLING(nodep->deleteTree(), nodep); diff --git a/src/V3Param.cpp b/src/V3Param.cpp index ed96f930d..cfbecfdbb 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -2966,10 +2966,7 @@ class ParamVisitor final : public VNVisitor { // Enumerate the current dimension given by 'arrp' // Each element is added right after 'portp', so go from right to left, // to end with an enumeration from the left index to the right index. - const int left = arrp->left(); - const int right = arrp->right(); - const int step = arrp->declRange().ascending() ? 1 : -1; - for (int n = right; n != left - step; n -= step) { + for (const int n : arrp->declRange().seqRightToLeft()) { const std::string s = suffix + "__BRA__" + AstNode::encodeNumber(n) + "__KET__"; expandIfaceArrayPortDimensions(portp, arrp->subDTypep(), s); } @@ -3011,12 +3008,9 @@ class ParamVisitor final : public VNVisitor { // Enumerate the current dimension given by 'rangep' // Each element is added right after 'arrayedCellp', so go from right to left, // to end with an enumeration from the left index to the right index. - const int left = rangep->leftConst(); - const int right = rangep->rightConst(); - const int step = rangep->ascending() ? 1 : -1; idx = (idx + 1) * rangep->elementsConst(); const AstRange* const subRangep = VN_AS(rangep->nextp(), Range); - for (int n = right; n != left - step; n -= step) { + for (const int n : rangep->seqRightToLeft()) { const std::string s = suffix + "__BRA__" + AstNode::encodeNumber(n) + "__KET__"; expandCellArrayDimensions(arrayedCellp, ifaceVarp, subRangep, s, --idx); } diff --git a/src/V3TraceDecl.cpp b/src/V3TraceDecl.cpp index 20c23bddd..dc1fe5d22 100644 --- a/src/V3TraceDecl.cpp +++ b/src/V3TraceDecl.cpp @@ -558,8 +558,7 @@ class TraceDeclVisitor final : public VNVisitor { } else { AstNodeDType* const subtypep = nodep->subDTypep()->skipRefToEnump(); // Always iterate left index to right index - const int inc = nodep->rangep()->ascending() ? 1 : -1; - for (int i = nodep->left(); i != nodep->right() + inc; i += inc) { + for (const int i : nodep->declRange().seqLeftToRight()) { VL_RESTORER(m_traValuep); m_traName = '[' + std::to_string(i) + ']'; m_traValuep = m_traValuep->cloneTree(false); @@ -583,8 +582,7 @@ class TraceDeclVisitor final : public VNVisitor { nodep->left(), nodep->right(), !newFunc}); // Always iterate left index to right index - const int inc = nodep->rangep()->ascending() ? 1 : -1; - for (int i = nodep->left(); i != nodep->right() + inc; i += inc) { + for (const int i : nodep->declRange().seqLeftToRight()) { VL_RESTORER(m_traValuep); m_traName = '[' + std::to_string(i) + ']'; const int lsb = (i - nodep->lo()) * subtypep->width(); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 31c0c5e83..f7aee4920 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -6349,7 +6349,7 @@ class WidthVisitor final : public VNVisitor { PatVecMap patmap = patVectorMap(nodep, range); UINFO(9, "ent " << range.hi() << " to " << range.lo()); AstNodeExpr* newp = nullptr; - for (int ent = range.hi(); ent >= range.lo(); --ent) { + for (const int ent : range.seqHiToLo()) { AstPatMember* newpatp = nullptr; AstPatMember* patp = nullptr; const auto it = patmap.find(ent); @@ -9646,7 +9646,7 @@ class WidthVisitor final : public VNVisitor { AstInitArray* newp = new AstInitArray{ constp->fileline(), lhsDTypep, new AstConst{constp->fileline(), AstConst::WidthedValue{}, 8, 0}}; - for (int aindex = arrayp->lo(); aindex <= arrayp->hi(); ++aindex) { + for (const int aindex : arrayp->declRange().seqLoToHi()) { int cindex = arrayp->declRange().ascending() ? (arrayp->hi() - aindex) : (aindex - arrayp->lo()); V3Number selected{constp, 8}; @@ -10828,7 +10828,7 @@ class WidthVisitor final : public VNVisitor { // as the element variables are in that order, indexed from lo AstInitArray* const initp = new AstInitArray{flp, arrp, nullptr}; const VNumRange range = arrp->declRange(); - for (int n = 0, i = range.left(); n < range.elements(); ++n, i += range.leftToRightInc()) { + for (const int i : range.seqLeftToRight()) { const std::string s = name + "__BRA__" + AstNode::encodeNumber(i) + "__KET__"; initp->addIndexValuep( i - range.lo(), newIfaceArrayInit(refp, arrp->subDTypep(), s, suffix, elemVarpr));