diff --git a/src/V3Task.cpp b/src/V3Task.cpp index b527ff445..f8473cebc 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -32,6 +32,7 @@ #include "V3EmitCBase.h" #include "V3Graph.h" #include "V3Stats.h" +#include "V3UniqueNames.h" #include @@ -393,6 +394,8 @@ class TaskVisitor final : public VNVisitor { // STATE TaskStateVisitor* const m_statep; // Common state between visitors + V3UniqueNames m_initArrayTmpNames; // For generating unique temporary variable names for + // arguments being AstInitArray AstNodeModule* m_modp = nullptr; // Current module AstTopScope* const m_topScopep = v3Global.rootp()->topScopep(); // The AstTopScope AstScope* m_scopep = nullptr; // Current scope @@ -1441,6 +1444,29 @@ class TaskVisitor final : public VNVisitor { UINFOTREE(9, newp, "", "newfunc"); m_insStmtp->addHereThisAsNext(newp); } + void processPins(AstNodeFTaskRef* nodep) { + // Create a fresh variable for each concat array present in pins list + for (AstNode* pinp = nodep->pinsp(); pinp; pinp = pinp->nextp()) { + AstArg* const argp = VN_AS(pinp, Arg); + AstInitArray* const arrayp = VN_CAST(argp->exprp(), InitArray); + if (!arrayp) continue; + + FileLine* const flp = arrayp->fileline(); + const std::string tempName = m_initArrayTmpNames.get(argp); + AstVar* const substp = new AstVar{flp, VVarType::VAR, tempName, arrayp->dtypep()}; + substp->funcLocal(true); + AstVarScope* const substvscp = createVarScope(substp, tempName); + + AstAssign* const assignp + = new AstAssign{flp, new AstVarRef{arrayp->fileline(), substvscp, VAccess::WRITE}, + arrayp->unlinkFrBack()}; + + AstExprStmt* const exprstmtp = new AstExprStmt{ + flp, substp, new AstVarRef{arrayp->fileline(), substvscp, VAccess::READ}}; + exprstmtp->stmtsp()->addNext(assignp); + argp->exprp(exprstmtp); + } + } // VISITORS void visit(AstNodeModule* nodep) override { @@ -1497,6 +1523,7 @@ class TaskVisitor final : public VNVisitor { AstNode* beginp; AstCNew* cnewp = nullptr; if (m_statep->ftaskNoInline(nodep->taskp())) { + processPins(nodep); // This may share VarScope's with a public task, if any. Yuk. beginp = createNonInlinedFTask(nodep, namePrefix, outvscp, cnewp /*ref*/); } else { @@ -1672,7 +1699,8 @@ class TaskVisitor final : public VNVisitor { public: // CONSTRUCTORS TaskVisitor(AstNetlist* nodep, TaskStateVisitor* statep) - : m_statep{statep} { + : m_statep{statep} + , m_initArrayTmpNames{"__VInitArrayTemp"} { iterate(nodep); } ~TaskVisitor() { diff --git a/test_regress/t/t_concat_init_array_functions.py b/test_regress/t/t_concat_init_array_functions.py new file mode 100755 index 000000000..d4f986441 --- /dev/null +++ b/test_regress/t/t_concat_init_array_functions.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 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 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.compile() + +test.execute() + +test.passes() diff --git a/test_regress/t/t_concat_init_array_functions.v b/test_regress/t/t_concat_init_array_functions.v new file mode 100755 index 000000000..a02d10965 --- /dev/null +++ b/test_regress/t/t_concat_init_array_functions.v @@ -0,0 +1,50 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Simple test for unpacked concatenation arrays used as function arguments. +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2026 by Antmicro. +// SPDX-License-Identifier: CC0-1.0 +// + +class A; + int r1[2]; + int r2; +endclass + +class B; + virtual function int B_virt_func(int r[3], p[4]); + return r[0] + r[1] + r[2] + p[0] + p[1] + p[2] + p[3]; + endfunction +endclass + +function int func_1_concat(int r[4]); +// verilator no_inline_task + return r[0] + r[1] + r[2] + r[3]; +endfunction + +function int func_2_concat(int r[3], int p[4]); +// verilator no_inline_task + return r[0] + r[1] + r[2] + p[0] + p[1] + p[2] + p[3]; +endfunction + +module t; + int s; + A a = new; + B b = new; + initial begin + a.r1 = {1,2}; + a.r2 = 5; + s = func_1_concat({a.r1, a.r1}); + if (s != 6) $stop; + + s = func_2_concat({a.r1, a.r2}, {a.r1, a.r1}); + if (s != 14) $stop; + + s = b.B_virt_func({a.r1, a.r2}, {a.r1, a.r1}); + if (s != 14) $stop; + + $write("*-* All finished *-*\n"); + $finish; + end +endmodule