Fix unpacked array concatenation function arguments (#6900)

This commit is contained in:
Pawel Kojma 2026-01-14 22:23:55 +01:00 committed by GitHub
parent 4563501192
commit 3072907ea4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 97 additions and 1 deletions

View File

@ -32,6 +32,7 @@
#include "V3EmitCBase.h"
#include "V3Graph.h"
#include "V3Stats.h"
#include "V3UniqueNames.h"
#include <tuple>
@ -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() {

View File

@ -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()

View File

@ -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