From f775feb7f04206163dc4623afe3405b201b34324 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 12 Dec 2021 20:43:15 -0500 Subject: [PATCH] Fix foreach on dotted reference. --- src/V3AstNodes.h | 2 ++ src/V3LinkDot.cpp | 14 ++++++++-- src/V3LinkParse.cpp | 1 + test_regress/t/t_foreach_bad.out | 4 --- test_regress/t/t_foreach_class.pl | 21 ++++++++++++++ test_regress/t/t_foreach_class.v | 46 +++++++++++++++++++++++++++++++ 6 files changed, 82 insertions(+), 6 deletions(-) create mode 100755 test_regress/t/t_foreach_class.pl create mode 100644 test_regress/t/t_foreach_class.v diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index ac6a829a5..b67e03b22 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -1726,6 +1726,7 @@ public: virtual bool same(const AstNode* samep) const override { return true; } virtual bool maybePointedTo() const override { return false; } AstNode* fromp() const { return op1p(); } + void fromp(AstNode* nodep) { setOp1p(nodep); } AstNode* elementsp() const { return op2p(); } }; @@ -3137,6 +3138,7 @@ public: } virtual void dump(std::ostream& str) const override; AstNode* lhsp() const { return op1p(); } + void rhsp(AstNode* nodep) { setOp2p(nodep); } AstNode* rhsp() const { return op2p(); } bool colon() const { return m_colon; } }; diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index d54b5d487..3abd6608d 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1280,16 +1280,25 @@ class LinkDotFindVisitor final : public AstNVisitor { m_curSymp = m_statep->insertBlock(m_curSymp, "__Vforeach" + cvtToStr(m_modWithNum), nodep, m_classOrPackagep); m_curSymp->fallbackp(oldCurSymp); - + // DOT(x, SELLOOPVARS(var, loops)) -> SELLOOPVARS(DOT(x, var), loops) + if (AstDot* const dotp = VN_CAST(nodep->arrayp(), Dot)) { + if (AstSelLoopVars* const loopvarsp = VN_CAST(dotp->rhsp(), SelLoopVars)) { + AstNode* const fromp = loopvarsp->fromp()->unlinkFrBack(); + loopvarsp->unlinkFrBack(); + dotp->replaceWith(loopvarsp); + dotp->rhsp(fromp); + loopvarsp->fromp(dotp); + } + } const auto loopvarsp = VN_CAST(nodep->arrayp(), SelLoopVars); if (!loopvarsp) { AstNode* const warnp = nodep->arrayp() ? nodep->arrayp() : nodep; warnp->v3warn(E_UNSUPPORTED, "Unsupported (or syntax error): Foreach on this array's construct"); + nodep->dumpTree(cout, "-FIXME-us "); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); return; } - for (AstNode *nextp, *argp = loopvarsp->elementsp(); argp; argp = nextp) { nextp = argp->nextp(); AstVar* argrefp = nullptr; @@ -1310,6 +1319,7 @@ class LinkDotFindVisitor final : public AstNVisitor { argp->v3error("'foreach' loop variable expects simple variable name"); } } + iterateChildren(nodep); } } diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index c48d0b251..1b3b4a349 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -444,6 +444,7 @@ private: VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); return; } + iterateChildren(nodep); } virtual void visit(AstNodeModule* nodep) override { diff --git a/test_regress/t/t_foreach_bad.out b/test_regress/t/t_foreach_bad.out index 5a8333651..799c765f5 100644 --- a/test_regress/t/t_foreach_bad.out +++ b/test_regress/t/t_foreach_bad.out @@ -1,8 +1,4 @@ %Error: t/t_foreach_bad.v:14:7: Syntax error; foreach missing bracketed loop variable (IEEE 1800-2017 12.7.3) 14 | foreach (array); | ^~~~~~~ -%Error-UNSUPPORTED: t/t_foreach_bad.v:16:21: Unsupported (or syntax error): Foreach on this array's construct - 16 | foreach (array.array[a]); - | ^ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Error: Exiting due to diff --git a/test_regress/t/t_foreach_class.pl b/test_regress/t/t_foreach_class.pl new file mode 100755 index 000000000..b46d46042 --- /dev/null +++ b/test_regress/t/t_foreach_class.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_foreach_class.v b/test_regress/t/t_foreach_class.v new file mode 100644 index 000000000..0f53bb3f4 --- /dev/null +++ b/test_regress/t/t_foreach_class.v @@ -0,0 +1,46 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2016 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.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); + +class Cls; + int q[$]; + function new(); + q.push_back(1); + q.push_back(2); + q.push_back(3); + endfunction +endclass + +module t (/*AUTOARG*/); + + int two[5:6]; + + if (1) begin : named + Cls c; + end + + function [63:0] crc(input [63:0] sum, input [31:0] a, input [31:0] b, input [31:0] c, input [31:0] d); + crc = {sum[62:0],sum[63]} ^ {20'b0,a[7:0], 4'h0,b[7:0], 4'h0,c[7:0], 4'h0,d[7:0]}; + endfunction + + bit [63:0] sum; + + initial begin + named.c = new; + sum = 0; + foreach (named.c.q[i]) begin + foreach (two[j]) begin + // $display(i, j); + sum = crc(sum, i, named.c.q[i], j, 0); + end + end + `checkh(sum, 64'h000000a02d0fc000); + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule