Fix `with` inside a `with`

This commit is contained in:
Wilson Snyder 2025-10-21 00:40:47 -04:00
parent 61de46cea2
commit 14e3448ba6
5 changed files with 102 additions and 71 deletions

View File

@ -1229,8 +1229,8 @@ public:
return out;
}
template <typename T_Func>
T_Value r_or(T_Func with_func) const {
T_Value out = T_Value(0);
WithFuncReturnType<T_Func> r_or(T_Func with_func) const {
WithFuncReturnType<T_Func> out = WithFuncReturnType<T_Func>(0);
for (const auto& i : m_map) out |= with_func(i.first, i.second);
return out;
}
@ -1570,8 +1570,9 @@ public:
return out;
}
template <typename T_Func>
T_Value r_sum(T_Func with_func) const {
T_Value out(0); // Type must have assignment operator
WithFuncReturnType<T_Func> r_sum(T_Func with_func) const {
WithFuncReturnType<T_Func> out
= WithFuncReturnType<T_Func>(0); // Type must have assignment operator
for (const auto& i : m_storage) out += with_func(0, i);
return out;
}
@ -1581,8 +1582,8 @@ public:
return out;
}
template <typename T_Func>
T_Value r_product(T_Func with_func) const {
T_Value out = T_Value(1);
WithFuncReturnType<T_Func> r_product(T_Func with_func) const {
WithFuncReturnType<T_Func> out = WithFuncReturnType<T_Func>(1);
for (const auto& i : m_storage) out *= with_func(0, i);
return out;
}
@ -1593,8 +1594,8 @@ public:
return out;
}
template <typename T_Func>
T_Value r_and(T_Func with_func) const {
T_Value out = ~T_Value(0);
WithFuncReturnType<T_Func> r_and(T_Func with_func) const {
WithFuncReturnType<T_Func> out = ~WithFuncReturnType<T_Func>(0);
for (const auto& i : m_storage) out &= with_func(0, i);
return out;
}
@ -1604,8 +1605,8 @@ public:
return out;
}
template <typename T_Func>
T_Value r_or(T_Func with_func) const {
T_Value out = T_Value(0);
WithFuncReturnType<T_Func> r_or(T_Func with_func) const {
WithFuncReturnType<T_Func> out = WithFuncReturnType<T_Func>(0);
for (const auto& i : m_storage) out |= with_func(0, i);
return out;
}
@ -1615,8 +1616,8 @@ public:
return out;
}
template <typename T_Func>
T_Value r_xor(T_Func with_func) const {
T_Value out = T_Value(0);
WithFuncReturnType<T_Func> r_xor(T_Func with_func) const {
WithFuncReturnType<T_Func> out = WithFuncReturnType<T_Func>(0);
for (const auto& i : m_storage) out ^= with_func(0, i);
return out;
}

View File

@ -735,7 +735,9 @@ public:
if (auto* const argrefp = nodep->valueArgRefp()) {
putnbs(argrefp, argrefp->dtypep()->cType(argrefp->nameProtect(), false, false));
}
puts(") {\n");
puts(") -> ");
putnbs(nodep, nodep->dtypep()->cType("", false, false));
puts(" {\n");
VL_RESTORER(m_createdScopeHash);
iterateAndNextConstNull(nodep->exprp());
puts("}\n");

View File

@ -1013,7 +1013,7 @@ class LinkDotFindVisitor final : public VNVisitor {
}
void visit(AstTypeTable*) override {} // FindVisitor::
void visit(AstConstPool*) override {} // FindVisitor::
void visit(AstIfaceRefDType* nodep) override {
void visit(AstIfaceRefDType* nodep) override { // FindVisitor::
if (m_statep->forPrimary() && nodep->isVirtual() && nodep->ifacep()
&& !nodep->ifacep()->user3()) {
m_virtIfaces.push_back(nodep->ifacep());
@ -1872,18 +1872,16 @@ class LinkDotFindVisitor final : public VNVisitor {
// Symbol table needs nodep->name() as the index variable's name
// Iteration will pickup the AstVar we made under AstWith
VL_RESTORER(m_curSymp);
{
++m_modWithNum;
m_curSymp = m_statep->insertBlock(m_curSymp, "__Vwith" + cvtToStr(m_modWithNum), nodep,
m_classOrPackagep);
m_curSymp->fallbackp(VL_RESTORER_PREV(m_curSymp));
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->valueArgRefp()->name(), nodep->valueArgRefp(),
nullptr);
iterateChildren(nodep);
}
++m_modWithNum;
m_curSymp = m_statep->insertBlock(m_curSymp, "__Vwith" + cvtToStr(m_modWithNum), nodep,
m_classOrPackagep);
m_curSymp->fallbackp(VL_RESTORER_PREV(m_curSymp));
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->valueArgRefp()->name(), nodep->valueArgRefp(),
nullptr);
iterateChildren(nodep);
}
void visit(AstNode* nodep) override { iterateChildren(nodep); } // FindVisitor::
@ -1982,7 +1980,7 @@ class LinkDotFindIfaceVisitor final : public VNVisitor {
}
iterateChildren(nodep);
}
void visit(AstVar* nodep) override { // FindVisitor::
void visit(AstVar* nodep) override { // FindIfaceVisitor::
VL_RESTORER(m_declp);
m_declp = nodep;
iterateChildren(nodep);
@ -2304,7 +2302,7 @@ private:
void visit(AstWith* nodep) override { // ScopeVisitor::
VSymEnt* const symp = m_statep->insertBlock(m_modSymp, nodep->name(), nodep, nullptr);
symp->fallbackp(m_modSymp);
// No recursion, we don't want to pick up variables
iterateChildren(nodep);
}
void visit(AstAlias* nodep) override { // ScopeVisitor::
// Track aliases
@ -2379,7 +2377,7 @@ private:
// We have stored the link, we don't need these any more
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
void visit(AstNodeGen* nodep) override { // LCOV_EXCL_LINE
void visit(AstNodeGen* nodep) override { // ScopeVisitor:: // LCOV_EXCL_LINE
nodep->v3fatalSrc("Generate constructs should have been reduced out");
}
// For speed, don't recurse things that can't have scope

View File

@ -3972,6 +3972,8 @@ class WidthVisitor final : public VNVisitor {
methodCallLValueRecurse(nodep, ichildp->fromp(), access);
} else if (const AstNodeSel* const ichildp = VN_CAST(childp, NodeSel)) {
methodCallLValueRecurse(nodep, ichildp->fromp(), access);
} else if (VN_IS(childp, LambdaArgRef)) {
// NOP
} else {
UINFO(1, " Related node: " << childp);
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Non-variable on LHS of built-in method '"

View File

@ -6,56 +6,84 @@
// any use, without warranty, 2020 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
// verilog_format: off
`define stop $stop
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
`define checkh(gotv, expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
// verilog_format: on
module t;
initial begin
int tofind;
int aliases[$];
int found[$];
int i;
byte byteq[$] = {2, -1, 127};
initial begin
int tofind;
int aliases[$];
int found[$];
int i;
byte byteq[$] = {2, -1, 127};
byte b[];
logic [7:0] m[2][2];
logic bit_arr[1024];
aliases = '{ 1, 4, 6, 8};
tofind = 6;
found = aliases.find with (item == 1);
`checkh(found.size, 1);
found = aliases.find(j) with (j == tofind);
`checkh(found.size, 1);
// And as function
aliases.find(i) with (i == tofind);
aliases = '{1, 4, 6, 8};
tofind = 6;
found = aliases.find with (item == 1);
`checkh(found.size, 1);
found = aliases.find(j) with (j == tofind);
`checkh(found.size, 1);
// And as function
aliases.find(i) with (i == tofind);
// No parenthesis
tofind = 0;
found = aliases.find with (item == tofind);
`checkh(found.size, 0);
aliases.find with (item == tofind);
// No parenthesis
tofind = 0;
found = aliases.find with (item == tofind);
`checkh(found.size, 0);
aliases.find with (item == tofind);
// bug3387
i = aliases.sum();
`checkh(i, 'h13);
i = byteq.sum() with (int'(item));
`checkh(i, 128);
// bug3387
i = aliases.sum();
`checkh(i, 'h13);
i = byteq.sum() with (int'(item));
`checkh(i, 128);
// Unique (array method)
tofind = 4;
found = aliases.find with (tofind); // "true" match
`checkh(found.size, 4);
found = aliases.find() with (item == tofind);
`checkh(found.size, 1);
found = aliases.find(i) with (i == tofind);
`checkh(found.size, 1);
i = aliases.or(v) with (v);
`checkh(i, 'hf);
i = aliases.and(v) with (v);
`checkh(i, 0);
i = aliases.xor(v) with (v);
`checkh(i, 'hb);
// Unique (array method)
tofind = 4;
found = aliases.find with (tofind); // "true" match
`checkh(found.size, 4);
found = aliases.find() with (item == tofind);
`checkh(found.size, 1);
found = aliases.find(i) with (i == tofind);
`checkh(found.size, 1);
i = aliases.or(v) with (v);
`checkh(i, 'hf);
i = aliases.and(v) with (v);
`checkh(i, 0);
i = aliases.xor(v) with (v);
`checkh(i, 'hb);
$write("*-* All Finished *-*\n");
$finish;
end
// Based roughly on IEEE 1800-2023 7.12.3
// verilator lint_off WIDTHEXPAND
b = {1, 2, 3, 4};
i = b.sum; // = 10 <= 1 + 2 + 3 + 4
`checkd(i, 10);
i = b.product; // = 24 <= 1 * 2 * 3 * 4
`checkd(i, 24);
i = b.xor with (item + 4); // = 12 <= 5 ^ 6 ^ 7 ^ 8
`checkd(i, 12);
m = '{'{5, 10}, '{15, 20}};
i = m.sum with (item.sum with (item)); // = 50 <= 5+10+15+20
`checkd(i, 50);
// Width of the reduction method's result is the dtype of the with's expression
// verilator lint_on WIDTHEXPAND
for (i = 0; i < 1024; ++i) bit_arr[i] = 1'b1;
i = bit_arr.sum with (int'(item)); // forces result to be 32-bit
`checkd(i, 1024);
$write("*-* All Finished *-*\n");
$finish;
end
endmodule