diff --git a/Changes b/Changes index 2655ecdfa..68b2adad0 100644 --- a/Changes +++ b/Changes @@ -7,6 +7,8 @@ The contributors that suggested a given feature are shown in []. Thanks! *** Support $random and $urandom seeds. +*** Support 'with item.index'. + **** Fix trace signal names getting hashed (#2643). [Barbara Gigerl] **** Fix unpacked array parameters near functions (#2639). [Anderson Ignacio da Silva] diff --git a/include/verilated_heavy.h b/include/verilated_heavy.h index 3346cd2be..c5409364a 100644 --- a/include/verilated_heavy.h +++ b/include/verilated_heavy.h @@ -250,14 +250,18 @@ public: void sort() { std::sort(m_deque.begin(), m_deque.end()); } template void sort(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) { return with_func(a) < with_func(b); }); + std::sort(m_deque.begin(), m_deque.end(), [=](const T_Value& a, const T_Value& b) { + // index number is meaninless with sort, as it changes + return with_func(0, a) < with_func(0, b); + }); } void rsort() { std::sort(m_deque.rbegin(), m_deque.rend()); } template void rsort(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) { return with_func(a) < with_func(b); }); + std::sort(m_deque.rbegin(), m_deque.rend(), [=](const T_Value& a, const T_Value& b) { + // index number is meaninless with sort, as it changes + return with_func(0, a) < with_func(0, b); + }); } void reverse() { std::reverse(m_deque.begin(), m_deque.end()); } void shuffle() { std::shuffle(m_deque.begin(), m_deque.end(), VlURNG()); } @@ -289,39 +293,54 @@ public: } template VlQueue find(Func with_func) const { VlQueue out; - for (const auto& i : m_deque) - if (with_func(i)) out.push_back(i); + IData index = 0; + for (const auto& i : m_deque) { + if (with_func(index, i)) out.push_back(i); + ++index; + } return out; } template VlQueue find_index(Func with_func) const { VlQueue out; IData index = 0; for (const auto& i : m_deque) { - if (with_func(i)) out.push_back(index); + if (with_func(index, i)) out.push_back(index); ++index; } return out; } template VlQueue find_first(Func with_func) const { - const auto it = std::find_if(m_deque.begin(), m_deque.end(), with_func); - if (it == m_deque.end()) return VlQueue{}; - return VlQueue::cons(*it); + // Can't use std::find_if as need index number + IData index = 0; + for (const auto& i : m_deque) { + if (with_func(index, i)) return VlQueue::cons(i); + ++index; + } + return VlQueue{}; } template VlQueue find_first_index(Func with_func) const { - const auto it = std::find_if(m_deque.begin(), m_deque.end(), with_func); - if (it == m_deque.end()) return VlQueue{}; - return VlQueue::cons(std::distance(m_deque.begin(), it)); + IData index = 0; + for (const auto& i : m_deque) { + if (with_func(index, i)) return VlQueue::cons(index); + ++index; + } + return VlQueue{}; } template VlQueue find_last(Func with_func) const { - const auto it = std::find_if(m_deque.rbegin(), m_deque.rend(), with_func); - if (it == m_deque.rend()) return VlQueue{}; - return VlQueue::cons(*it); + IData index = m_deque.size() - 1; + for (auto it = m_deque.rbegin(); it != m_deque.rend(); ++it) { + if (with_func(index, *it)) return VlQueue::cons(*it); + --index; + } + return VlQueue{}; } template VlQueue find_last_index(Func with_func) const { - const auto it = std::find_if(m_deque.rbegin(), m_deque.rend(), with_func); - if (it == m_deque.rend()) return VlQueue{}; - // Return index must be relative to beginning - return VlQueue::cons(m_deque.size() - 1 - std::distance(m_deque.rbegin(), it)); + IData index = m_deque.size() - 1; + for (auto it = m_deque.rbegin(); it != m_deque.rend(); ++it) { + if (with_func(index, *it)) return VlQueue::cons(index); + --index; + } + return VlQueue{}; } // Reduction operators @@ -343,7 +362,8 @@ public: } template T_Value r_sum(Func with_func) const { T_Value out(0); // Type must have assignment operator - for (const auto& i : m_deque) out += with_func(i); + IData index = 0; + for (const auto& i : m_deque) out += with_func(index++, i); return out; } T_Value r_product() const { @@ -357,9 +377,11 @@ public: template T_Value r_product(Func with_func) const { if (m_deque.empty()) return T_Value(0); auto it = m_deque.begin(); - T_Value out{with_func(*it)}; + IData index = 0; + T_Value out{with_func(index, *it)}; ++it; - for (; it != m_deque.end(); ++it) out *= with_func(*it); + ++index; + for (; it != m_deque.end(); ++it) out *= with_func(index++, *it); return out; } T_Value r_and() const { @@ -373,9 +395,11 @@ public: template T_Value r_and(Func with_func) const { if (m_deque.empty()) return T_Value(0); auto it = m_deque.begin(); - T_Value out{with_func(*it)}; + IData index = 0; + T_Value out{with_func(index, *it)}; ++it; - for (; it != m_deque.end(); ++it) out &= with_func(*it); + ++index; + for (; it != m_deque.end(); ++it) out &= with_func(index, *it); return out; } T_Value r_or() const { @@ -385,7 +409,8 @@ public: } template T_Value r_or(Func with_func) const { T_Value out(0); // Type must have assignment operator - for (const auto& i : m_deque) out |= with_func(i); + IData index = 0; + for (const auto& i : m_deque) out |= with_func(index++, i); return out; } T_Value r_xor() const { @@ -395,7 +420,8 @@ public: } template T_Value r_xor(Func with_func) const { T_Value out(0); // Type must have assignment operator - for (const auto& i : m_deque) out ^= with_func(i); + IData index = 0; + for (const auto& i : m_deque) out ^= with_func(index++, i); return out; } @@ -588,19 +614,19 @@ public: template VlQueue find(Func with_func) const { VlQueue out; for (const auto& i : m_map) - if (with_func(i.second)) out.push_back(i.second); + if (with_func(i.first, i.second)) out.push_back(i.second); return out; } template VlQueue find_index(Func with_func) const { VlQueue out; for (const auto& i : m_map) - if (with_func(i.second)) out.push_back(i.first); + if (with_func(i.first, i.second)) out.push_back(i.first); return out; } template VlQueue find_first(Func with_func) const { const auto it = std::find_if(m_map.begin(), m_map.end(), [=](const std::pair& i) { - return with_func(i.second); + return with_func(i.first, i.second); }); if (it == m_map.end()) return VlQueue{}; return VlQueue::cons(it->second); @@ -608,7 +634,7 @@ public: template VlQueue find_first_index(Func with_func) const { const auto it = std::find_if(m_map.begin(), m_map.end(), [=](const std::pair& i) { - return with_func(i.second); + return with_func(i.first, i.second); }); if (it == m_map.end()) return VlQueue{}; return VlQueue::cons(it->first); @@ -616,7 +642,7 @@ public: template VlQueue find_last(Func with_func) const { const auto it = std::find_if(m_map.rbegin(), m_map.rend(), [=](const std::pair& i) { - return with_func(i.second); + return with_func(i.first, i.second); }); if (it == m_map.rend()) return VlQueue{}; return VlQueue::cons(it->second); @@ -624,7 +650,7 @@ public: template VlQueue find_last_index(Func with_func) const { const auto it = std::find_if(m_map.rbegin(), m_map.rend(), [=](const std::pair& i) { - return with_func(i.second); + return with_func(i.first, i.second); }); if (it == m_map.rend()) return VlQueue{}; return VlQueue::cons(it->first); @@ -657,7 +683,7 @@ public: } template T_Value r_sum(Func with_func) const { T_Value out(0); // Type must have assignment operator - for (const auto& i : m_map) out += with_func(i.second); + for (const auto& i : m_map) out += with_func(i.first, i.second); return out; } T_Value r_product() const { @@ -671,9 +697,9 @@ public: template T_Value r_product(Func with_func) const { if (m_map.empty()) return T_Value(0); auto it = m_map.begin(); - T_Value out{with_func(it->second)}; + T_Value out{with_func(it->first, it->second)}; ++it; - for (; it != m_map.end(); ++it) out *= with_func(it->second); + for (; it != m_map.end(); ++it) out *= with_func(it->first, it->second); return out; } T_Value r_and() const { @@ -687,9 +713,9 @@ public: template T_Value r_and(Func with_func) const { if (m_map.empty()) return T_Value(0); auto it = m_map.begin(); - T_Value out{with_func(it->second)}; + T_Value out{with_func(it->first, it->second)}; ++it; - for (; it != m_map.end(); ++it) out &= with_func(it->second); + for (; it != m_map.end(); ++it) out &= with_func(it->first, it->second); return out; } T_Value r_or() const { @@ -699,7 +725,7 @@ public: } template T_Value r_or(Func with_func) const { T_Value out(0); // Type must have assignment operator - for (const auto& i : m_map) out |= with_func(i.second); + for (const auto& i : m_map) out |= with_func(i.first, i.second); return out; } T_Value r_xor() const { @@ -709,7 +735,7 @@ public: } template T_Value r_xor(Func with_func) const { T_Value out(0); // Type must have assignment operator - for (const auto& i : m_map) out ^= with_func(i.second); + for (const auto& i : m_map) out ^= with_func(i.first, i.second); return out; } diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index f8632dc49..9384f4e08 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -3107,11 +3107,13 @@ class AstLambdaArgRef final : public AstNodeMath { // optimizations and AstVar's are painful to remove. private: string m_name; // Name of variable + bool m_index; // Index, not value public: - AstLambdaArgRef(FileLine* fl, const string& name) + AstLambdaArgRef(FileLine* fl, const string& name, bool index) : ASTGEN_SUPER(fl) - , m_name{name} {} + , m_name{name} + , m_index(index) {} ASTNODE_NODE_FUNCS(LambdaArgRef) virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } @@ -3122,31 +3124,37 @@ public: virtual int instrCount() const override { return widthInstrs(); } virtual string name() const override { return m_name; } // * = Var name virtual void name(const string& name) override { m_name = name; } + bool index() const { return m_index; } }; class AstWith final : public AstNodeStmt { // Used as argument to method, then to AstCMethodHard // dtypep() contains the with lambda's return dtype // Parents: funcref (similar to AstArg) - // Children: VAR that declares the index variable + // Children: LambdaArgRef that declares the item variable + // Children: LambdaArgRef that declares the item.index variable // Children: math (equation establishing the with) public: - AstWith(FileLine* fl, AstLambdaArgRef* argrefp, AstNode* exprp) + AstWith(FileLine* fl, AstLambdaArgRef* indexArgRefp, AstLambdaArgRef* valueArgRefp, + AstNode* exprp) : ASTGEN_SUPER(fl) { - addOp1p(argrefp); - addNOp2p(exprp); + addOp1p(indexArgRefp); + addOp2p(valueArgRefp); + addNOp3p(exprp); } ASTNODE_NODE_FUNCS(With) virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } virtual bool hasDType() const override { return true; } virtual const char* broken() const override { - BROKEN_RTN(!argrefp()); // varp needed to know lambda's arg dtype + BROKEN_RTN(!indexArgRefp()); // varp needed to know lambda's arg dtype + BROKEN_RTN(!valueArgRefp()); // varp needed to know lambda's arg dtype return nullptr; } // - AstLambdaArgRef* argrefp() const { return VN_CAST(op1p(), LambdaArgRef); } - AstNode* exprp() const { return op2p(); } + AstLambdaArgRef* indexArgRefp() const { return VN_CAST(op1p(), LambdaArgRef); } + AstLambdaArgRef* valueArgRefp() const { return VN_CAST(op2p(), LambdaArgRef); } + AstNode* exprp() const { return op3p(); } }; //###################################################################### diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 465036379..35b1c4162 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -430,8 +430,12 @@ public: virtual void visit(AstWith* nodep) override { // With uses a C++11 lambda putbs("[=]("); - if (auto* argrefp = nodep->argrefp()) { - putbs(argrefp->dtypep()->cType(nodep->argrefp()->nameProtect(), false, false)); + if (auto* argrefp = nodep->indexArgRefp()) { + putbs(argrefp->dtypep()->cType(argrefp->nameProtect(), false, false)); + puts(","); + } + if (auto* argrefp = nodep->valueArgRefp()) { + putbs(argrefp->dtypep()->cType(argrefp->nameProtect(), false, false)); } // Probably fragile, V3Task may need to convert to a AstCReturn puts(") { return "); diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index d84b344db..e93d0815a 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1281,9 +1281,10 @@ class LinkDotFindVisitor final : public AstNVisitor { VL_DO_DANGLING(argp->unlinkFrBackWithNext()->deleteTree(), argp); } // Type depends on the method used, let V3Width figure it out later - auto* argrefp = new AstLambdaArgRef(argFl, name); - auto* newp - = new AstWith(nodep->fileline(), argrefp, nodep->exprp()->unlinkFrBackWithNext()); + auto* indexArgRefp = new AstLambdaArgRef(argFl, name + "__DOT__index", true); + auto* valueArgRefp = new AstLambdaArgRef(argFl, name, false); + auto* newp = new AstWith(nodep->fileline(), indexArgRefp, valueArgRefp, + nodep->exprp()->unlinkFrBackWithNext()); funcrefp->addPinsp(newp); nodep->replaceWith(funcrefp->unlinkFrBack()); VL_DO_DANGLING(nodep->deleteTree(), nodep); @@ -1298,9 +1299,11 @@ class LinkDotFindVisitor final : public AstNVisitor { m_curSymp = m_statep->insertBlock(m_curSymp, "__Vwith" + cvtToStr(m_modWithNum), nodep, m_packagep); m_curSymp->fallbackp(oldCurSymp); - UASSERT_OBJ(nodep->argrefp(), nodep, "Missing lambda argref"); + UASSERT_OBJ(nodep->indexArgRefp(), nodep, "Missing lambda argref"); + UASSERT_OBJ(nodep->valueArgRefp(), nodep, "Missing lambda argref"); // Insert argref's name into symbol table - m_statep->insertSym(m_curSymp, nodep->argrefp()->name(), nodep->argrefp(), nullptr); + m_statep->insertSym(m_curSymp, nodep->valueArgRefp()->name(), nodep->valueArgRefp(), + nullptr); } } @@ -2034,6 +2037,7 @@ private: && (VN_IS(nodep->lhsp(), CellRef) || VN_IS(nodep->lhsp(), CellArrayRef))) { m_ds.m_unlinkedScopep = nodep->lhsp(); } + if (VN_IS(nodep->lhsp(), LambdaArgRef)) { m_ds.m_unlinkedScopep = nodep->lhsp(); } if (!m_ds.m_dotErr) { // Once something wrong, give up // Top 'final' dot RHS is final RHS, else it's a // DOT(DOT(x,*here*),real-rhs) which we consider a RHS @@ -2089,7 +2093,16 @@ private: nodep->v3warn(E_UNSUPPORTED, "Unsupported: super"); m_ds.m_dotErr = true; } - if (m_ds.m_dotPos == DP_MEMBER) { + if (m_ds.m_dotPos == DP_FINAL && VN_IS(m_ds.m_unlinkedScopep, LambdaArgRef) + && nodep->name() == "index") { + // 'with' statement's 'item.index' + iterateChildren(nodep); + auto newp = new AstLambdaArgRef(nodep->fileline(), + m_ds.m_unlinkedScopep->name() + "__DOT__index", true); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + return; + } else if (m_ds.m_dotPos == DP_MEMBER) { // Found a Var, everything following is membership. {scope}.{var}.HERE {member} AstNode* varEtcp = m_ds.m_dotp->lhsp()->unlinkFrBack(); AstNode* newp @@ -2301,7 +2314,7 @@ private: } } else if (AstLambdaArgRef* argrefp = VN_CAST(foundp->nodep(), LambdaArgRef)) { if (allowVar) { - AstNode* newp = new AstLambdaArgRef(nodep->fileline(), argrefp->name()); + AstNode* newp = new AstLambdaArgRef(nodep->fileline(), argrefp->name(), false); nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); ok = true; @@ -2730,6 +2743,11 @@ private: } m_ds.m_dotSymp = m_curSymp = oldCurSymp; } + virtual void visit(AstLambdaArgRef* nodep) override { + UINFO(5, " " << nodep << endl); + // No checknodot(nodep), visit(AstScope) will check for LambdaArgRef + iterateChildren(nodep); + } virtual void visit(AstClass* nodep) override { UINFO(5, " " << nodep << endl); checkNoDot(nodep); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 32590cf9d..a79bb2834 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -201,7 +201,7 @@ private: AstCell* m_cellp = nullptr; // Current cell for arrayed instantiations AstNodeFTask* m_ftaskp = nullptr; // Current function/task AstNodeProcedure* m_procedurep = nullptr; // Current final/always - AstLambdaArgRef* m_lambdaArgRefp = nullptr; // Argument to above lambda + AstWith* m_withp = nullptr; // Current 'with' statement AstFunc* m_funcp = nullptr; // Current function AstAttrOf* m_attrp = nullptr; // Current attribute bool m_doGenerate; // Do errors later inside generate statement @@ -2373,10 +2373,12 @@ private: } } AstWith* methodWithArgument(AstMethodCall* nodep, bool required, bool arbReturn, - AstNodeDType* returnDtp, AstNodeDType* argDtp) { + AstNodeDType* returnDtp, AstNodeDType* indexDtp, + AstNodeDType* valueDtp) { UASSERT_OBJ(arbReturn || returnDtp, nodep, "Null return type"); if (AstWith* withp = VN_CAST(nodep->pinsp(), With)) { - withp->argrefp()->dtypep(argDtp); + withp->indexArgRefp()->dtypep(indexDtp); + withp->valueArgRefp()->dtypep(valueDtp); userIterate(withp, WidthVP(returnDtp, BOTH).p()); withp->unlinkFrBack(); return withp; @@ -2570,7 +2572,7 @@ private: || nodep->name() == "sum" || nodep->name() == "product") { // All value return AstWith* withp = methodWithArgument(nodep, false, false, adtypep->subDTypep(), - adtypep->subDTypep()); + adtypep->keyDTypep(), adtypep->subDTypep()); methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), @@ -2592,7 +2594,7 @@ private: } else if (nodep->name() == "find" || nodep->name() == "find_first" || nodep->name() == "find_last") { AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(), - adtypep->subDTypep()); + adtypep->keyDTypep(), adtypep->subDTypep()); methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), @@ -2602,7 +2604,7 @@ private: } else if (nodep->name() == "find_index" || nodep->name() == "find_first_index" || nodep->name() == "find_last_index") { AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(), - adtypep->subDTypep()); + adtypep->keyDTypep(), adtypep->subDTypep()); methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), @@ -2663,7 +2665,7 @@ private: || nodep->name() == "sum" || nodep->name() == "product") { // All value return AstWith* withp = methodWithArgument(nodep, false, false, adtypep->subDTypep(), - adtypep->subDTypep()); + nodep->findUInt32DType(), adtypep->subDTypep()); methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), @@ -2674,7 +2676,8 @@ private: || nodep->name() == "sort" || nodep->name() == "rsort") { AstWith* withp = nullptr; if (nodep->name() == "sort" || nodep->name() == "rsort") { - withp = methodWithArgument(nodep, false, true, nullptr, adtypep->subDTypep()); + withp = methodWithArgument(nodep, false, true, nullptr, nodep->findUInt32DType(), + adtypep->subDTypep()); } methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); @@ -2696,7 +2699,7 @@ private: } else if (nodep->name() == "find" || nodep->name() == "find_first" || nodep->name() == "find_last" || nodep->name() == "find_index") { AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(), - adtypep->subDTypep()); + nodep->findUInt32DType(), adtypep->subDTypep()); methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), @@ -2706,7 +2709,7 @@ private: } else if (nodep->name() == "find_index" || nodep->name() == "find_first_index" || nodep->name() == "find_last_index") { AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(), - adtypep->subDTypep()); + nodep->findUInt32DType(), adtypep->subDTypep()); methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), @@ -2794,7 +2797,7 @@ private: } else if (nodep->name() == "and" || nodep->name() == "or" || nodep->name() == "xor" || nodep->name() == "sum" || nodep->name() == "product") { AstWith* withp = methodWithArgument(nodep, false, false, adtypep->subDTypep(), - adtypep->subDTypep()); + nodep->findUInt32DType(), adtypep->subDTypep()); methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), @@ -2805,7 +2808,8 @@ private: || nodep->name() == "sort" || nodep->name() == "rsort") { AstWith* withp = nullptr; if (nodep->name() == "sort" || nodep->name() == "rsort") { - withp = methodWithArgument(nodep, false, true, nullptr, adtypep->subDTypep()); + withp = methodWithArgument(nodep, false, true, nullptr, nodep->findUInt32DType(), + adtypep->subDTypep()); } methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); @@ -2827,7 +2831,7 @@ private: } else if (nodep->name() == "find" || nodep->name() == "find_first" || nodep->name() == "find_last") { AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(), - adtypep->subDTypep()); + nodep->findUInt32DType(), adtypep->subDTypep()); methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), @@ -2837,7 +2841,7 @@ private: } else if (nodep->name() == "find_index" || nodep->name() == "find_first_index" || nodep->name() == "find_last_index") { AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(), - adtypep->subDTypep()); + nodep->findUInt32DType(), adtypep->subDTypep()); methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), @@ -4422,10 +4426,11 @@ private: virtual void visit(AstWith* nodep) override { // Should otherwise be underneath a method call AstNodeDType* vdtypep = m_vup->dtypeNullSkipRefp(); - VL_RESTORER(m_lambdaArgRefp); + VL_RESTORER(m_withp); { - m_lambdaArgRefp = nodep->argrefp(); - userIterateChildren(nodep->argrefp(), nullptr); + m_withp = nodep; + userIterateChildren(nodep->indexArgRefp(), nullptr); + userIterateChildren(nodep->valueArgRefp(), nullptr); if (vdtypep) { userIterateAndNext(nodep->exprp(), WidthVP(nodep->dtypep(), PRELIM).p()); } else { // 'sort with' allows arbitrary type @@ -4437,8 +4442,12 @@ private: } } virtual void visit(AstLambdaArgRef* nodep) override { - UASSERT_OBJ(m_lambdaArgRefp, nodep, "LambdaArgRef not underneath with lambda"); - nodep->dtypeFrom(m_lambdaArgRefp); + UASSERT_OBJ(m_withp, nodep, "LambdaArgRef not underneath 'with' lambda"); + if (nodep->index()) { + nodep->dtypeFrom(m_withp->indexArgRefp()); + } else { + nodep->dtypeFrom(m_withp->valueArgRefp()); + } } virtual void visit(AstNetlist* nodep) override { // Iterate modules backwards, in bottom-up order. That's faster diff --git a/test_regress/t/t_assoc_method.v b/test_regress/t/t_assoc_method.v index 29c8372e1..684e90c68 100644 --- a/test_regress/t/t_assoc_method.v +++ b/test_regress/t/t_assoc_method.v @@ -67,6 +67,11 @@ module t (/*AUTOARG*/); qi = q.find_last_index with (item == 20); v = $sformatf("%p", qi); `checks(v, "'{}"); + qi = q.find_index with (item.index == 12); + v = $sformatf("%p", qi); `checks(v, "'{'hc} "); + qi = q.find with (item.index == 12); + v = $sformatf("%p", qi); `checks(v, "'{'h2} "); + qv = q.min; v = $sformatf("%p", qv); `checks(v, "'{'h1} "); qv = q.max; diff --git a/test_regress/t/t_dynarray_method.v b/test_regress/t/t_dynarray_method.v index 21a778dc5..3142782b5 100644 --- a/test_regress/t/t_dynarray_method.v +++ b/test_regress/t/t_dynarray_method.v @@ -100,6 +100,9 @@ module t (/*AUTOARG*/); qi = d.find_last_index with (item == 20); `checkh(qi.size, 0); + qi = d.find_index with (item.index == 2); + v = $sformatf("%p", qi); `checks(v, "'{'h2} "); + qv = d.min; v = $sformatf("%p", qv); `checks(v, "'{'h1} "); qv = d.max; diff --git a/test_regress/t/t_queue_method.v b/test_regress/t/t_queue_method.v index d5429c88d..3e8dfbf1a 100644 --- a/test_regress/t/t_queue_method.v +++ b/test_regress/t/t_queue_method.v @@ -95,6 +95,11 @@ module t (/*AUTOARG*/); qi = q.find_last_index with (item == 20); `checkh(qi.size, 0); + qi = q.find_index with (item.index == 2); + v = $sformatf("%p", qi); `checks(v, "'{'h2} "); + qi = q.find_index with (item.index == item); + v = $sformatf("%p", qi); `checks(v, "'{'h2, 'h3, 'h4} "); + qv = q.min; v = $sformatf("%p", qv); `checks(v, "'{'h1} "); qv = q.max;