From 14e3448ba63a3fbbdb8f090877637d1916a9e866 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 21 Oct 2025 00:40:47 -0400 Subject: [PATCH] Fix `with` inside a `with` --- include/verilated_types.h | 25 +++++---- src/V3EmitCFunc.h | 4 +- src/V3LinkDot.cpp | 30 +++++----- src/V3Width.cpp | 2 + test_regress/t/t_with.v | 112 ++++++++++++++++++++++++-------------- 5 files changed, 102 insertions(+), 71 deletions(-) diff --git a/include/verilated_types.h b/include/verilated_types.h index f0e514e4f..a2e39b6cc 100644 --- a/include/verilated_types.h +++ b/include/verilated_types.h @@ -1229,8 +1229,8 @@ public: return out; } template - T_Value r_or(T_Func with_func) const { - T_Value out = T_Value(0); + WithFuncReturnType r_or(T_Func with_func) const { + WithFuncReturnType out = WithFuncReturnType(0); for (const auto& i : m_map) out |= with_func(i.first, i.second); return out; } @@ -1570,8 +1570,9 @@ public: return out; } template - T_Value r_sum(T_Func with_func) const { - T_Value out(0); // Type must have assignment operator + WithFuncReturnType r_sum(T_Func with_func) const { + WithFuncReturnType out + = WithFuncReturnType(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 - T_Value r_product(T_Func with_func) const { - T_Value out = T_Value(1); + WithFuncReturnType r_product(T_Func with_func) const { + WithFuncReturnType out = WithFuncReturnType(1); for (const auto& i : m_storage) out *= with_func(0, i); return out; } @@ -1593,8 +1594,8 @@ public: return out; } template - T_Value r_and(T_Func with_func) const { - T_Value out = ~T_Value(0); + WithFuncReturnType r_and(T_Func with_func) const { + WithFuncReturnType out = ~WithFuncReturnType(0); for (const auto& i : m_storage) out &= with_func(0, i); return out; } @@ -1604,8 +1605,8 @@ public: return out; } template - T_Value r_or(T_Func with_func) const { - T_Value out = T_Value(0); + WithFuncReturnType r_or(T_Func with_func) const { + WithFuncReturnType out = WithFuncReturnType(0); for (const auto& i : m_storage) out |= with_func(0, i); return out; } @@ -1615,8 +1616,8 @@ public: return out; } template - T_Value r_xor(T_Func with_func) const { - T_Value out = T_Value(0); + WithFuncReturnType r_xor(T_Func with_func) const { + WithFuncReturnType out = WithFuncReturnType(0); for (const auto& i : m_storage) out ^= with_func(0, i); return out; } diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index 328bbba58..22b94af43 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -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"); diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index d0b9ca48e..51c4b211b 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -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 diff --git a/src/V3Width.cpp b/src/V3Width.cpp index aef3ca013..2a0852c32 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -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 '" diff --git a/test_regress/t/t_with.v b/test_regress/t/t_with.v index fc2dd928a..d3f62df58 100644 --- a/test_regress/t/t_with.v +++ b/test_regress/t/t_with.v @@ -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