Support 'with item.index'.

This commit is contained in:
Wilson Snyder 2020-11-23 23:18:58 -05:00
parent 103ba1fb6d
commit e85a2e860e
9 changed files with 157 additions and 77 deletions

View File

@ -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]

View File

@ -250,14 +250,18 @@ public:
void sort() { std::sort(m_deque.begin(), m_deque.end()); }
template <typename Func> 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 <typename Func> 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 <typename Func> 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 <typename Func> VlQueue<IData> find_index(Func with_func) const {
VlQueue<IData> 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 <typename Func> 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 <typename Func> VlQueue<IData> 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<IData>{};
return VlQueue<IData>::cons(std::distance(m_deque.begin(), it));
IData index = 0;
for (const auto& i : m_deque) {
if (with_func(index, i)) return VlQueue<IData>::cons(index);
++index;
}
return VlQueue<IData>{};
}
template <typename Func> 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 <typename Func> VlQueue<IData> 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<IData>{};
// Return index must be relative to beginning
return VlQueue<IData>::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<IData>::cons(index);
--index;
}
return VlQueue<IData>{};
}
// Reduction operators
@ -343,7 +362,8 @@ public:
}
template <typename Func> 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 <typename Func> 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 <typename Func> 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 <typename Func> 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 <typename Func> 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 <typename Func> VlQueue<T_Value> find(Func with_func) const {
VlQueue<T_Value> 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 <typename Func> VlQueue<T_Key> find_index(Func with_func) const {
VlQueue<T_Key> 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 <typename Func> VlQueue<T_Value> find_first(Func with_func) const {
const auto it
= std::find_if(m_map.begin(), m_map.end(), [=](const std::pair<T_Key, T_Value>& i) {
return with_func(i.second);
return with_func(i.first, i.second);
});
if (it == m_map.end()) return VlQueue<T_Value>{};
return VlQueue<T_Value>::cons(it->second);
@ -608,7 +634,7 @@ public:
template <typename Func> VlQueue<T_Key> find_first_index(Func with_func) const {
const auto it
= std::find_if(m_map.begin(), m_map.end(), [=](const std::pair<T_Key, T_Value>& i) {
return with_func(i.second);
return with_func(i.first, i.second);
});
if (it == m_map.end()) return VlQueue<T_Value>{};
return VlQueue<T_Key>::cons(it->first);
@ -616,7 +642,7 @@ public:
template <typename Func> VlQueue<T_Value> find_last(Func with_func) const {
const auto it
= std::find_if(m_map.rbegin(), m_map.rend(), [=](const std::pair<T_Key, T_Value>& i) {
return with_func(i.second);
return with_func(i.first, i.second);
});
if (it == m_map.rend()) return VlQueue<T_Value>{};
return VlQueue<T_Value>::cons(it->second);
@ -624,7 +650,7 @@ public:
template <typename Func> VlQueue<T_Key> find_last_index(Func with_func) const {
const auto it
= std::find_if(m_map.rbegin(), m_map.rend(), [=](const std::pair<T_Key, T_Value>& i) {
return with_func(i.second);
return with_func(i.first, i.second);
});
if (it == m_map.rend()) return VlQueue<T_Value>{};
return VlQueue<T_Key>::cons(it->first);
@ -657,7 +683,7 @@ public:
}
template <typename Func> 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 <typename Func> 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 <typename Func> 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 <typename Func> 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 <typename Func> 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;
}

View File

@ -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(); }
};
//######################################################################

View File

@ -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 ");

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;