Support for assignments to concatenations with impure RHS (#6002)

This commit is contained in:
Ryszard Rozak 2025-05-13 01:19:38 +02:00 committed by GitHub
parent ac2313ecb7
commit 91c52a4972
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 71 additions and 5 deletions

View File

@ -2077,20 +2077,41 @@ class ConstVisitor final : public VNVisitor {
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
return true;
}
} else if (m_doV && VN_IS(nodep->lhsp(), Concat) && nodep->isPure()) {
} else if (m_doV && VN_IS(nodep->lhsp(), Concat)) {
bool need_temp = false;
if (m_warn && !VN_IS(nodep, AssignDly)) { // Is same var on LHS and RHS?
bool need_temp_pure = !nodep->rhsp()->isPure();
if (m_warn && !VN_IS(nodep, AssignDly)
&& !need_temp_pure) { // Is same var on LHS and RHS?
// Note only do this (need user4) when m_warn, which is
// done as unique visitor
// If the rhs is not pure, we need a temporary variable anyway
const VNUser4InUse m_inuser4;
nodep->lhsp()->foreach([](const AstVarRef* nodep) {
if (nodep->varp()) nodep->varp()->user4(1);
UASSERT_OBJ(nodep->varp(), nodep, "Unlinked VarRef");
nodep->varp()->user4(1);
});
nodep->rhsp()->foreach([&need_temp](const AstVarRef* nodep) {
if (nodep->varp() && nodep->varp()->user4()) need_temp = true;
UASSERT_OBJ(nodep->varp(), nodep, "Unlinked VarRef");
if (nodep->varp()->user4()) need_temp = true;
});
}
if (need_temp) {
if (need_temp_pure) {
// if the RHS is impure we need to create a temporary variable for it, because
// further handling involves copying of the RHS.
UINFO(4, " ASSITEMPPURE " << nodep << endl);
// ASSIGN(CONCAT(lc1,lc2),rhs) -> ASSIGN(temp,rhs),
// ASSIGN(lc1,SEL(temp,{size1})),
// ASSIGN(lc2,SEL(temp,{size2}))
AstNodeExpr* const rhsp = nodep->rhsp()->unlinkFrBack();
AstVar* const tempPurep = new AstVar{rhsp->fileline(), VVarType::BLOCKTEMP,
m_concswapNames.get(rhsp), rhsp->dtypep()};
m_modp->addStmtsp(tempPurep);
AstNodeAssign* const asnp = nodep->cloneType(
new AstVarRef{rhsp->fileline(), tempPurep, VAccess::WRITE}, rhsp);
nodep->addHereThisAsNext(asnp);
nodep->rhsp(new AstVarRef{rhsp->fileline(), tempPurep, VAccess::READ});
} else if (need_temp) {
// The first time we constify, there may be the same variable on the LHS
// and RHS. In that case, we must use temporaries, or {a,b}={b,a} will break.
UINFO(4, " ASSITEMP " << nodep << endl);

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,27 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2025 by Antmicro.
// SPDX-License-Identifier: CC0-1.0
int global_variable = 0;
function int side_effect;
global_variable++;
return 1;
endfunction
module t (/*AUTOARG*/);
reg [15:0] x;
reg [15:0] y;
initial begin
{x, y} = side_effect() + 2;
if (y != 3) $stop;
if (x != 0) $stop;
if (global_variable != 1) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule