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 $random and $urandom seeds.
*** Support 'with item.index'.
**** Fix trace signal names getting hashed (#2643). [Barbara Gigerl] **** Fix trace signal names getting hashed (#2643). [Barbara Gigerl]
**** Fix unpacked array parameters near functions (#2639). [Anderson Ignacio da Silva] **** 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()); } void sort() { std::sort(m_deque.begin(), m_deque.end()); }
template <typename Func> void sort(Func with_func) { template <typename Func> void sort(Func with_func) {
// with_func returns arbitrary type to use for the sort comparison // with_func returns arbitrary type to use for the sort comparison
std::sort(m_deque.begin(), m_deque.end(), std::sort(m_deque.begin(), m_deque.end(), [=](const T_Value& a, const T_Value& b) {
[=](const T_Value& a, const T_Value& b) { return with_func(a) < with_func(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()); } void rsort() { std::sort(m_deque.rbegin(), m_deque.rend()); }
template <typename Func> void rsort(Func with_func) { template <typename Func> void rsort(Func with_func) {
// with_func returns arbitrary type to use for the sort comparison // with_func returns arbitrary type to use for the sort comparison
std::sort(m_deque.rbegin(), m_deque.rend(), std::sort(m_deque.rbegin(), m_deque.rend(), [=](const T_Value& a, const T_Value& b) {
[=](const T_Value& a, const T_Value& b) { return with_func(a) < with_func(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 reverse() { std::reverse(m_deque.begin(), m_deque.end()); }
void shuffle() { std::shuffle(m_deque.begin(), m_deque.end(), VlURNG()); } 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 { template <typename Func> VlQueue find(Func with_func) const {
VlQueue out; VlQueue out;
for (const auto& i : m_deque) IData index = 0;
if (with_func(i)) out.push_back(i); for (const auto& i : m_deque) {
if (with_func(index, i)) out.push_back(i);
++index;
}
return out; return out;
} }
template <typename Func> VlQueue<IData> find_index(Func with_func) const { template <typename Func> VlQueue<IData> find_index(Func with_func) const {
VlQueue<IData> out; VlQueue<IData> out;
IData index = 0; IData index = 0;
for (const auto& i : m_deque) { for (const auto& i : m_deque) {
if (with_func(i)) out.push_back(index); if (with_func(index, i)) out.push_back(index);
++index; ++index;
} }
return out; return out;
} }
template <typename Func> VlQueue find_first(Func with_func) const { template <typename Func> VlQueue find_first(Func with_func) const {
const auto it = std::find_if(m_deque.begin(), m_deque.end(), with_func); // Can't use std::find_if as need index number
if (it == m_deque.end()) return VlQueue{}; IData index = 0;
return VlQueue::cons(*it); 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 { 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); IData index = 0;
if (it == m_deque.end()) return VlQueue<IData>{}; for (const auto& i : m_deque) {
return VlQueue<IData>::cons(std::distance(m_deque.begin(), it)); if (with_func(index, i)) return VlQueue<IData>::cons(index);
++index;
}
return VlQueue<IData>{};
} }
template <typename Func> VlQueue find_last(Func with_func) const { template <typename Func> VlQueue find_last(Func with_func) const {
const auto it = std::find_if(m_deque.rbegin(), m_deque.rend(), with_func); IData index = m_deque.size() - 1;
if (it == m_deque.rend()) return VlQueue{}; for (auto it = m_deque.rbegin(); it != m_deque.rend(); ++it) {
return VlQueue::cons(*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 { 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); IData index = m_deque.size() - 1;
if (it == m_deque.rend()) return VlQueue<IData>{}; for (auto it = m_deque.rbegin(); it != m_deque.rend(); ++it) {
// Return index must be relative to beginning if (with_func(index, *it)) return VlQueue<IData>::cons(index);
return VlQueue<IData>::cons(m_deque.size() - 1 - std::distance(m_deque.rbegin(), it)); --index;
}
return VlQueue<IData>{};
} }
// Reduction operators // Reduction operators
@ -343,7 +362,8 @@ public:
} }
template <typename Func> T_Value r_sum(Func with_func) const { template <typename Func> T_Value r_sum(Func with_func) const {
T_Value out(0); // Type must have assignment operator 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; return out;
} }
T_Value r_product() const { T_Value r_product() const {
@ -357,9 +377,11 @@ public:
template <typename Func> T_Value r_product(Func with_func) const { template <typename Func> T_Value r_product(Func with_func) const {
if (m_deque.empty()) return T_Value(0); if (m_deque.empty()) return T_Value(0);
auto it = m_deque.begin(); auto it = m_deque.begin();
T_Value out{with_func(*it)}; IData index = 0;
T_Value out{with_func(index, *it)};
++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; return out;
} }
T_Value r_and() const { T_Value r_and() const {
@ -373,9 +395,11 @@ public:
template <typename Func> T_Value r_and(Func with_func) const { template <typename Func> T_Value r_and(Func with_func) const {
if (m_deque.empty()) return T_Value(0); if (m_deque.empty()) return T_Value(0);
auto it = m_deque.begin(); auto it = m_deque.begin();
T_Value out{with_func(*it)}; IData index = 0;
T_Value out{with_func(index, *it)};
++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; return out;
} }
T_Value r_or() const { T_Value r_or() const {
@ -385,7 +409,8 @@ public:
} }
template <typename Func> T_Value r_or(Func with_func) const { template <typename Func> T_Value r_or(Func with_func) const {
T_Value out(0); // Type must have assignment operator 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; return out;
} }
T_Value r_xor() const { T_Value r_xor() const {
@ -395,7 +420,8 @@ public:
} }
template <typename Func> T_Value r_xor(Func with_func) const { template <typename Func> T_Value r_xor(Func with_func) const {
T_Value out(0); // Type must have assignment operator 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; return out;
} }
@ -588,19 +614,19 @@ public:
template <typename Func> VlQueue<T_Value> find(Func with_func) const { template <typename Func> VlQueue<T_Value> find(Func with_func) const {
VlQueue<T_Value> out; VlQueue<T_Value> out;
for (const auto& i : m_map) for (const auto& i : m_map)
if (with_func(i.second)) out.push_back(i.second); if (with_func(i.first, i.second)) out.push_back(i.second);
return out; return out;
} }
template <typename Func> VlQueue<T_Key> find_index(Func with_func) const { template <typename Func> VlQueue<T_Key> find_index(Func with_func) const {
VlQueue<T_Key> out; VlQueue<T_Key> out;
for (const auto& i : m_map) for (const auto& i : m_map)
if (with_func(i.second)) out.push_back(i.first); if (with_func(i.first, i.second)) out.push_back(i.first);
return out; return out;
} }
template <typename Func> VlQueue<T_Value> find_first(Func with_func) const { template <typename Func> VlQueue<T_Value> find_first(Func with_func) const {
const auto it const auto it
= std::find_if(m_map.begin(), m_map.end(), [=](const std::pair<T_Key, T_Value>& i) { = 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>{}; if (it == m_map.end()) return VlQueue<T_Value>{};
return VlQueue<T_Value>::cons(it->second); 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 { template <typename Func> VlQueue<T_Key> find_first_index(Func with_func) const {
const auto it const auto it
= std::find_if(m_map.begin(), m_map.end(), [=](const std::pair<T_Key, T_Value>& i) { = 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>{}; if (it == m_map.end()) return VlQueue<T_Value>{};
return VlQueue<T_Key>::cons(it->first); return VlQueue<T_Key>::cons(it->first);
@ -616,7 +642,7 @@ public:
template <typename Func> VlQueue<T_Value> find_last(Func with_func) const { template <typename Func> VlQueue<T_Value> find_last(Func with_func) const {
const auto it const auto it
= std::find_if(m_map.rbegin(), m_map.rend(), [=](const std::pair<T_Key, T_Value>& i) { = 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>{}; if (it == m_map.rend()) return VlQueue<T_Value>{};
return VlQueue<T_Value>::cons(it->second); 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 { template <typename Func> VlQueue<T_Key> find_last_index(Func with_func) const {
const auto it const auto it
= std::find_if(m_map.rbegin(), m_map.rend(), [=](const std::pair<T_Key, T_Value>& i) { = 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>{}; if (it == m_map.rend()) return VlQueue<T_Value>{};
return VlQueue<T_Key>::cons(it->first); return VlQueue<T_Key>::cons(it->first);
@ -657,7 +683,7 @@ public:
} }
template <typename Func> T_Value r_sum(Func with_func) const { template <typename Func> T_Value r_sum(Func with_func) const {
T_Value out(0); // Type must have assignment operator 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; return out;
} }
T_Value r_product() const { T_Value r_product() const {
@ -671,9 +697,9 @@ public:
template <typename Func> T_Value r_product(Func with_func) const { template <typename Func> T_Value r_product(Func with_func) const {
if (m_map.empty()) return T_Value(0); if (m_map.empty()) return T_Value(0);
auto it = m_map.begin(); auto it = m_map.begin();
T_Value out{with_func(it->second)}; T_Value out{with_func(it->first, it->second)};
++it; ++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; return out;
} }
T_Value r_and() const { T_Value r_and() const {
@ -687,9 +713,9 @@ public:
template <typename Func> T_Value r_and(Func with_func) const { template <typename Func> T_Value r_and(Func with_func) const {
if (m_map.empty()) return T_Value(0); if (m_map.empty()) return T_Value(0);
auto it = m_map.begin(); auto it = m_map.begin();
T_Value out{with_func(it->second)}; T_Value out{with_func(it->first, it->second)};
++it; ++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; return out;
} }
T_Value r_or() const { T_Value r_or() const {
@ -699,7 +725,7 @@ public:
} }
template <typename Func> T_Value r_or(Func with_func) const { template <typename Func> T_Value r_or(Func with_func) const {
T_Value out(0); // Type must have assignment operator 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; return out;
} }
T_Value r_xor() const { T_Value r_xor() const {
@ -709,7 +735,7 @@ public:
} }
template <typename Func> T_Value r_xor(Func with_func) const { template <typename Func> T_Value r_xor(Func with_func) const {
T_Value out(0); // Type must have assignment operator 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; return out;
} }

View File

@ -3107,11 +3107,13 @@ class AstLambdaArgRef final : public AstNodeMath {
// optimizations and AstVar's are painful to remove. // optimizations and AstVar's are painful to remove.
private: private:
string m_name; // Name of variable string m_name; // Name of variable
bool m_index; // Index, not value
public: public:
AstLambdaArgRef(FileLine* fl, const string& name) AstLambdaArgRef(FileLine* fl, const string& name, bool index)
: ASTGEN_SUPER(fl) : ASTGEN_SUPER(fl)
, m_name{name} {} , m_name{name}
, m_index(index) {}
ASTNODE_NODE_FUNCS(LambdaArgRef) ASTNODE_NODE_FUNCS(LambdaArgRef)
virtual V3Hash sameHash() const override { return V3Hash(); } virtual V3Hash sameHash() const override { return V3Hash(); }
virtual bool same(const AstNode* samep) const override { return true; } virtual bool same(const AstNode* samep) const override { return true; }
@ -3122,31 +3124,37 @@ public:
virtual int instrCount() const override { return widthInstrs(); } virtual int instrCount() const override { return widthInstrs(); }
virtual string name() const override { return m_name; } // * = Var name virtual string name() const override { return m_name; } // * = Var name
virtual void name(const string& name) override { m_name = name; } virtual void name(const string& name) override { m_name = name; }
bool index() const { return m_index; }
}; };
class AstWith final : public AstNodeStmt { class AstWith final : public AstNodeStmt {
// Used as argument to method, then to AstCMethodHard // Used as argument to method, then to AstCMethodHard
// dtypep() contains the with lambda's return dtype // dtypep() contains the with lambda's return dtype
// Parents: funcref (similar to AstArg) // 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) // Children: math (equation establishing the with)
public: public:
AstWith(FileLine* fl, AstLambdaArgRef* argrefp, AstNode* exprp) AstWith(FileLine* fl, AstLambdaArgRef* indexArgRefp, AstLambdaArgRef* valueArgRefp,
AstNode* exprp)
: ASTGEN_SUPER(fl) { : ASTGEN_SUPER(fl) {
addOp1p(argrefp); addOp1p(indexArgRefp);
addNOp2p(exprp); addOp2p(valueArgRefp);
addNOp3p(exprp);
} }
ASTNODE_NODE_FUNCS(With) ASTNODE_NODE_FUNCS(With)
virtual V3Hash sameHash() const override { return V3Hash(); } virtual V3Hash sameHash() const override { return V3Hash(); }
virtual bool same(const AstNode* samep) const override { return true; } virtual bool same(const AstNode* samep) const override { return true; }
virtual bool hasDType() const override { return true; } virtual bool hasDType() const override { return true; }
virtual const char* broken() const override { 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; return nullptr;
} }
// //
AstLambdaArgRef* argrefp() const { return VN_CAST(op1p(), LambdaArgRef); } AstLambdaArgRef* indexArgRefp() const { return VN_CAST(op1p(), LambdaArgRef); }
AstNode* exprp() const { return op2p(); } 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 { virtual void visit(AstWith* nodep) override {
// With uses a C++11 lambda // With uses a C++11 lambda
putbs("[=]("); putbs("[=](");
if (auto* argrefp = nodep->argrefp()) { if (auto* argrefp = nodep->indexArgRefp()) {
putbs(argrefp->dtypep()->cType(nodep->argrefp()->nameProtect(), false, false)); 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 // Probably fragile, V3Task may need to convert to a AstCReturn
puts(") { return "); puts(") { return ");

View File

@ -1281,9 +1281,10 @@ class LinkDotFindVisitor final : public AstNVisitor {
VL_DO_DANGLING(argp->unlinkFrBackWithNext()->deleteTree(), argp); VL_DO_DANGLING(argp->unlinkFrBackWithNext()->deleteTree(), argp);
} }
// Type depends on the method used, let V3Width figure it out later // Type depends on the method used, let V3Width figure it out later
auto* argrefp = new AstLambdaArgRef(argFl, name); auto* indexArgRefp = new AstLambdaArgRef(argFl, name + "__DOT__index", true);
auto* newp auto* valueArgRefp = new AstLambdaArgRef(argFl, name, false);
= new AstWith(nodep->fileline(), argrefp, nodep->exprp()->unlinkFrBackWithNext()); auto* newp = new AstWith(nodep->fileline(), indexArgRefp, valueArgRefp,
nodep->exprp()->unlinkFrBackWithNext());
funcrefp->addPinsp(newp); funcrefp->addPinsp(newp);
nodep->replaceWith(funcrefp->unlinkFrBack()); nodep->replaceWith(funcrefp->unlinkFrBack());
VL_DO_DANGLING(nodep->deleteTree(), nodep); 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_curSymp = m_statep->insertBlock(m_curSymp, "__Vwith" + cvtToStr(m_modWithNum), nodep,
m_packagep); m_packagep);
m_curSymp->fallbackp(oldCurSymp); 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 // 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))) { && (VN_IS(nodep->lhsp(), CellRef) || VN_IS(nodep->lhsp(), CellArrayRef))) {
m_ds.m_unlinkedScopep = nodep->lhsp(); 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 if (!m_ds.m_dotErr) { // Once something wrong, give up
// Top 'final' dot RHS is final RHS, else it's a // Top 'final' dot RHS is final RHS, else it's a
// DOT(DOT(x,*here*),real-rhs) which we consider a RHS // DOT(DOT(x,*here*),real-rhs) which we consider a RHS
@ -2089,7 +2093,16 @@ private:
nodep->v3warn(E_UNSUPPORTED, "Unsupported: super"); nodep->v3warn(E_UNSUPPORTED, "Unsupported: super");
m_ds.m_dotErr = true; 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} // Found a Var, everything following is membership. {scope}.{var}.HERE {member}
AstNode* varEtcp = m_ds.m_dotp->lhsp()->unlinkFrBack(); AstNode* varEtcp = m_ds.m_dotp->lhsp()->unlinkFrBack();
AstNode* newp AstNode* newp
@ -2301,7 +2314,7 @@ private:
} }
} else if (AstLambdaArgRef* argrefp = VN_CAST(foundp->nodep(), LambdaArgRef)) { } else if (AstLambdaArgRef* argrefp = VN_CAST(foundp->nodep(), LambdaArgRef)) {
if (allowVar) { if (allowVar) {
AstNode* newp = new AstLambdaArgRef(nodep->fileline(), argrefp->name()); AstNode* newp = new AstLambdaArgRef(nodep->fileline(), argrefp->name(), false);
nodep->replaceWith(newp); nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep); VL_DO_DANGLING(pushDeletep(nodep), nodep);
ok = true; ok = true;
@ -2730,6 +2743,11 @@ private:
} }
m_ds.m_dotSymp = m_curSymp = oldCurSymp; 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 { virtual void visit(AstClass* nodep) override {
UINFO(5, " " << nodep << endl); UINFO(5, " " << nodep << endl);
checkNoDot(nodep); checkNoDot(nodep);

View File

@ -201,7 +201,7 @@ private:
AstCell* m_cellp = nullptr; // Current cell for arrayed instantiations AstCell* m_cellp = nullptr; // Current cell for arrayed instantiations
AstNodeFTask* m_ftaskp = nullptr; // Current function/task AstNodeFTask* m_ftaskp = nullptr; // Current function/task
AstNodeProcedure* m_procedurep = nullptr; // Current final/always 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 AstFunc* m_funcp = nullptr; // Current function
AstAttrOf* m_attrp = nullptr; // Current attribute AstAttrOf* m_attrp = nullptr; // Current attribute
bool m_doGenerate; // Do errors later inside generate statement bool m_doGenerate; // Do errors later inside generate statement
@ -2373,10 +2373,12 @@ private:
} }
} }
AstWith* methodWithArgument(AstMethodCall* nodep, bool required, bool arbReturn, 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"); UASSERT_OBJ(arbReturn || returnDtp, nodep, "Null return type");
if (AstWith* withp = VN_CAST(nodep->pinsp(), With)) { 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()); userIterate(withp, WidthVP(returnDtp, BOTH).p());
withp->unlinkFrBack(); withp->unlinkFrBack();
return withp; return withp;
@ -2570,7 +2572,7 @@ private:
|| nodep->name() == "sum" || nodep->name() == "product") { || nodep->name() == "sum" || nodep->name() == "product") {
// All value return // All value return
AstWith* withp = methodWithArgument(nodep, false, false, adtypep->subDTypep(), AstWith* withp = methodWithArgument(nodep, false, false, adtypep->subDTypep(),
adtypep->subDTypep()); adtypep->keyDTypep(), adtypep->subDTypep());
methodOkArguments(nodep, 0, 0); methodOkArguments(nodep, 0, 0);
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
@ -2592,7 +2594,7 @@ private:
} else if (nodep->name() == "find" || nodep->name() == "find_first" } else if (nodep->name() == "find" || nodep->name() == "find_first"
|| nodep->name() == "find_last") { || nodep->name() == "find_last") {
AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(), AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(),
adtypep->subDTypep()); adtypep->keyDTypep(), adtypep->subDTypep());
methodOkArguments(nodep, 0, 0); methodOkArguments(nodep, 0, 0);
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
@ -2602,7 +2604,7 @@ private:
} else if (nodep->name() == "find_index" || nodep->name() == "find_first_index" } else if (nodep->name() == "find_index" || nodep->name() == "find_first_index"
|| nodep->name() == "find_last_index") { || nodep->name() == "find_last_index") {
AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(), AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(),
adtypep->subDTypep()); adtypep->keyDTypep(), adtypep->subDTypep());
methodOkArguments(nodep, 0, 0); methodOkArguments(nodep, 0, 0);
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
@ -2663,7 +2665,7 @@ private:
|| nodep->name() == "sum" || nodep->name() == "product") { || nodep->name() == "sum" || nodep->name() == "product") {
// All value return // All value return
AstWith* withp = methodWithArgument(nodep, false, false, adtypep->subDTypep(), AstWith* withp = methodWithArgument(nodep, false, false, adtypep->subDTypep(),
adtypep->subDTypep()); nodep->findUInt32DType(), adtypep->subDTypep());
methodOkArguments(nodep, 0, 0); methodOkArguments(nodep, 0, 0);
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
@ -2674,7 +2676,8 @@ private:
|| nodep->name() == "sort" || nodep->name() == "rsort") { || nodep->name() == "sort" || nodep->name() == "rsort") {
AstWith* withp = nullptr; AstWith* withp = nullptr;
if (nodep->name() == "sort" || nodep->name() == "rsort") { 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); methodOkArguments(nodep, 0, 0);
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
@ -2696,7 +2699,7 @@ private:
} else if (nodep->name() == "find" || nodep->name() == "find_first" } else if (nodep->name() == "find" || nodep->name() == "find_first"
|| nodep->name() == "find_last" || nodep->name() == "find_index") { || nodep->name() == "find_last" || nodep->name() == "find_index") {
AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(), AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(),
adtypep->subDTypep()); nodep->findUInt32DType(), adtypep->subDTypep());
methodOkArguments(nodep, 0, 0); methodOkArguments(nodep, 0, 0);
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
@ -2706,7 +2709,7 @@ private:
} else if (nodep->name() == "find_index" || nodep->name() == "find_first_index" } else if (nodep->name() == "find_index" || nodep->name() == "find_first_index"
|| nodep->name() == "find_last_index") { || nodep->name() == "find_last_index") {
AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(), AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(),
adtypep->subDTypep()); nodep->findUInt32DType(), adtypep->subDTypep());
methodOkArguments(nodep, 0, 0); methodOkArguments(nodep, 0, 0);
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
@ -2794,7 +2797,7 @@ private:
} else if (nodep->name() == "and" || nodep->name() == "or" || nodep->name() == "xor" } else if (nodep->name() == "and" || nodep->name() == "or" || nodep->name() == "xor"
|| nodep->name() == "sum" || nodep->name() == "product") { || nodep->name() == "sum" || nodep->name() == "product") {
AstWith* withp = methodWithArgument(nodep, false, false, adtypep->subDTypep(), AstWith* withp = methodWithArgument(nodep, false, false, adtypep->subDTypep(),
adtypep->subDTypep()); nodep->findUInt32DType(), adtypep->subDTypep());
methodOkArguments(nodep, 0, 0); methodOkArguments(nodep, 0, 0);
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
@ -2805,7 +2808,8 @@ private:
|| nodep->name() == "sort" || nodep->name() == "rsort") { || nodep->name() == "sort" || nodep->name() == "rsort") {
AstWith* withp = nullptr; AstWith* withp = nullptr;
if (nodep->name() == "sort" || nodep->name() == "rsort") { 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); methodOkArguments(nodep, 0, 0);
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
@ -2827,7 +2831,7 @@ private:
} else if (nodep->name() == "find" || nodep->name() == "find_first" } else if (nodep->name() == "find" || nodep->name() == "find_first"
|| nodep->name() == "find_last") { || nodep->name() == "find_last") {
AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(), AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(),
adtypep->subDTypep()); nodep->findUInt32DType(), adtypep->subDTypep());
methodOkArguments(nodep, 0, 0); methodOkArguments(nodep, 0, 0);
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
@ -2837,7 +2841,7 @@ private:
} else if (nodep->name() == "find_index" || nodep->name() == "find_first_index" } else if (nodep->name() == "find_index" || nodep->name() == "find_first_index"
|| nodep->name() == "find_last_index") { || nodep->name() == "find_last_index") {
AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(), AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(),
adtypep->subDTypep()); nodep->findUInt32DType(), adtypep->subDTypep());
methodOkArguments(nodep, 0, 0); methodOkArguments(nodep, 0, 0);
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ);
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
@ -4422,10 +4426,11 @@ private:
virtual void visit(AstWith* nodep) override { virtual void visit(AstWith* nodep) override {
// Should otherwise be underneath a method call // Should otherwise be underneath a method call
AstNodeDType* vdtypep = m_vup->dtypeNullSkipRefp(); AstNodeDType* vdtypep = m_vup->dtypeNullSkipRefp();
VL_RESTORER(m_lambdaArgRefp); VL_RESTORER(m_withp);
{ {
m_lambdaArgRefp = nodep->argrefp(); m_withp = nodep;
userIterateChildren(nodep->argrefp(), nullptr); userIterateChildren(nodep->indexArgRefp(), nullptr);
userIterateChildren(nodep->valueArgRefp(), nullptr);
if (vdtypep) { if (vdtypep) {
userIterateAndNext(nodep->exprp(), WidthVP(nodep->dtypep(), PRELIM).p()); userIterateAndNext(nodep->exprp(), WidthVP(nodep->dtypep(), PRELIM).p());
} else { // 'sort with' allows arbitrary type } else { // 'sort with' allows arbitrary type
@ -4437,8 +4442,12 @@ private:
} }
} }
virtual void visit(AstLambdaArgRef* nodep) override { virtual void visit(AstLambdaArgRef* nodep) override {
UASSERT_OBJ(m_lambdaArgRefp, nodep, "LambdaArgRef not underneath with lambda"); UASSERT_OBJ(m_withp, nodep, "LambdaArgRef not underneath 'with' lambda");
nodep->dtypeFrom(m_lambdaArgRefp); if (nodep->index()) {
nodep->dtypeFrom(m_withp->indexArgRefp());
} else {
nodep->dtypeFrom(m_withp->valueArgRefp());
}
} }
virtual void visit(AstNetlist* nodep) override { virtual void visit(AstNetlist* nodep) override {
// Iterate modules backwards, in bottom-up order. That's faster // 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); qi = q.find_last_index with (item == 20);
v = $sformatf("%p", qi); `checks(v, "'{}"); 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; qv = q.min;
v = $sformatf("%p", qv); `checks(v, "'{'h1} "); v = $sformatf("%p", qv); `checks(v, "'{'h1} ");
qv = q.max; qv = q.max;

View File

@ -100,6 +100,9 @@ module t (/*AUTOARG*/);
qi = d.find_last_index with (item == 20); qi = d.find_last_index with (item == 20);
`checkh(qi.size, 0); `checkh(qi.size, 0);
qi = d.find_index with (item.index == 2);
v = $sformatf("%p", qi); `checks(v, "'{'h2} ");
qv = d.min; qv = d.min;
v = $sformatf("%p", qv); `checks(v, "'{'h1} "); v = $sformatf("%p", qv); `checks(v, "'{'h1} ");
qv = d.max; qv = d.max;

View File

@ -95,6 +95,11 @@ module t (/*AUTOARG*/);
qi = q.find_last_index with (item == 20); qi = q.find_last_index with (item == 20);
`checkh(qi.size, 0); `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; qv = q.min;
v = $sformatf("%p", qv); `checks(v, "'{'h1} "); v = $sformatf("%p", qv); `checks(v, "'{'h1} ");
qv = q.max; qv = q.max;