Fix eliminating assignments to DPI-read vaiables (#7158)

This commit is contained in:
Geza Lore 2026-02-28 15:09:01 +00:00 committed by GitHub
parent face700f29
commit 2ceea267e5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 96 additions and 5 deletions

View File

@ -1933,6 +1933,7 @@ class AstVar final : public AstNode {
bool m_isLatched : 1; // Not assigned in all control paths of combo always
bool m_isForceable : 1; // May be forced/released externally from user C code
bool m_isForcedByCode : 1; // May be forced/released from AstAssignForce/AstRelease
bool m_isReadByDpi : 1; // This variable can be read by a DPI Export
bool m_isWrittenByDpi : 1; // This variable can be written by a DPI Export
bool m_isWrittenBySuspendable : 1; // This variable can be written by a suspendable process
bool m_ignorePostRead : 1; // Ignore reads in 'Post' blocks during ordering
@ -1987,6 +1988,7 @@ class AstVar final : public AstNode {
m_isLatched = false;
m_isForceable = false;
m_isForcedByCode = false;
m_isReadByDpi = false;
m_isWrittenByDpi = false;
m_isWrittenBySuspendable = false;
m_ignorePostRead = false;
@ -2152,6 +2154,8 @@ public:
void setForceable() { m_isForceable = true; }
void setForcedByCode() { m_isForcedByCode = true; }
bool isForced() const { return m_isForceable || m_isForcedByCode; }
bool isReadByDpi() const { return m_isReadByDpi; }
void setReadByDpi() { m_isReadByDpi = true; }
bool isWrittenByDpi() const { return m_isWrittenByDpi; }
void setWrittenByDpi() { m_isWrittenByDpi = true; }
bool isWrittenBySuspendable() const { return m_isWrittenBySuspendable; }

View File

@ -2880,6 +2880,8 @@ void AstVar::dump(std::ostream& str) const {
if (isSigPublic()) str << " [P]";
if (isSigUserRdPublic()) str << " [PRD]";
if (isSigUserRWPublic()) str << " [PWR]";
if (isReadByDpi()) str << " [DPIRD]";
if (isWrittenByDpi()) str << " [DPIWR]";
if (isInternal()) str << " [INTERNAL]";
if (isLatched()) str << " [LATCHED]";
if (isUsedLoopIdx()) str << " [LOOPIDX]";
@ -2927,6 +2929,8 @@ void AstVar::dumpJson(std::ostream& str) const {
if (dtypep()) dumpJsonStr(str, "dtypeName", dtypep()->name());
dumpJsonBoolFuncIf(str, isSigUserRdPublic);
dumpJsonBoolFuncIf(str, isSigUserRWPublic);
dumpJsonBoolFuncIf(str, isReadByDpi);
dumpJsonBoolFuncIf(str, isWrittenByDpi);
dumpJsonBoolFuncIf(str, isGParam);
dumpJsonBoolFuncIf(str, isParam);
dumpJsonBoolFuncIf(str, attrScBv);

View File

@ -129,6 +129,7 @@ public:
const AstVar* const varp = vscp->varp();
// We don't optimize any public sigs
if (varp->isSigPublic()) return;
if (varp->isReadByDpi()) return;
if (varp->sensIfacep()) return;
// Check the var entry, and remove if appropriate
AstNodeStmt* const oldassp = entr.assignp();

View File

@ -1428,15 +1428,22 @@ class TaskVisitor final : public VNVisitor {
// Mark non-local variables written by the exported function
bool writesNonLocals = false;
cfuncp->foreach([&writesNonLocals](AstVarRef* refp) {
if (refp->access().isReadOnly()) return; // Ignore read reference
AstVar* const varp = refp->varScopep()->varp();
// We are ignoring function locals as they should not be referenced anywhere
// outside the enclosing AstCFunc, hence they are irrelevant for code ordering.
if (varp->isFuncLocal()) return;
// Mark it as written by DPI export
varp->setWrittenByDpi();
// Remember we had some
writesNonLocals = true;
// Check if written
if (refp->access().isWriteOrRW()) {
// Mark it as written by DPI export
varp->setWrittenByDpi();
// Remember we had some
writesNonLocals = true;
}
// Check if read
if (refp->access().isReadOrRW()) {
// Mark it as read by DPI export
varp->setReadByDpi();
}
});
// If this DPI export writes some non-local variables, set the DPI Export Trigger flag

View File

@ -0,0 +1,22 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
//
// 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-FileCopyrightText: 2026-2026 Wilson Snyder
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
//
//*************************************************************************
#include "svdpi.h"
#include <iostream>
extern "C" int getDpi();
extern "C" int getViaDpi() {
const int value = getDpi();
std::cout << "getDpi " << value << std::endl;
return value;
}

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# 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-FileCopyrightText: 2026 Wilson Snyder
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
import vltest_bootstrap
test.scenarios('vlt_all')
test.compile(verilator_flags2=["--binary", "--stats", test.top_filename.replace(".v", ".cpp")])
test.execute()
test.passes()

View File

@ -0,0 +1,35 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain.
// SPDX-FileCopyrightText: 2026 Wilson Snyder
// SPDX-License-Identifier: CC0-1.0
// verilog_format: off
`define stop $stop
`define check(got,exp) do if ((got) !== (exp)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (got), (exp)); `stop; end while(0)
// verilog_format: on
module t;
int dpiGet = 0;
function automatic int getDpi();
return dpiGet;
endfunction
export "DPI-C" function getDpi;
import "DPI-C" context function int getViaDpi(); // calls getDpi()
int tmp1, tmp2, tmp3;
initial begin
dpiGet = 13;
tmp1 = getViaDpi();
dpiGet = 14;
tmp2 = getViaDpi();
dpiGet = 15;
tmp3 = getViaDpi();
`check(tmp1, 13);
`check(tmp2, 14);
`check(tmp3, 15);
end
endmodule