Deprecate isolate_assignments attribute

As per discussion. Remove the unsound V3SplitAs pass. The
isolate_assignments attribute/directive is now parsed and ignored in the
frontend for compatibility but otherwise have no effect.

Fixes #7144
This commit is contained in:
Geza Lore 2026-06-13 09:07:12 +01:00
parent 7af22422c7
commit 368a38b89a
21 changed files with 44 additions and 354 deletions

View File

@ -187,6 +187,10 @@ The grammar of control commands is as follows:
.. option:: isolate_assignments -module "<modulename>" [-task "<taskname>"] -var "<signame>" .. option:: isolate_assignments -module "<modulename>" [-task "<taskname>"] -var "<signame>"
Deprecated and has no effect (ignored).
In versions before 5.050:
Used to indicate that the assignments to this signal in any blocks Used to indicate that the assignments to this signal in any blocks
should be isolated into new blocks. Same as should be isolated into new blocks. Same as
:option:`/*verilator&32;isolate_assignments*/` metacomment. :option:`/*verilator&32;isolate_assignments*/` metacomment.

View File

@ -341,6 +341,10 @@ or "`ifdef`"'s may break other tools.
.. option:: /*verilator&32;isolate_assignments*/ .. option:: /*verilator&32;isolate_assignments*/
Deprecated and has no effect (ignored).
In versions before 5.050:
Used after a signal declaration to indicate the assignments to this Used after a signal declaration to indicate the assignments to this
signal in any blocks should be isolated into new blocks. When large signal in any blocks should be isolated into new blocks. When large
combinatorial block results in a :option:`UNOPTFLAT` warning, attaching combinatorial block results in a :option:`UNOPTFLAT` warning, attaching

View File

@ -2366,11 +2366,6 @@ List Of Warnings
the conflict. If you run with :vlopt:`--report-unoptflat`, Verilator will the conflict. If you run with :vlopt:`--report-unoptflat`, Verilator will
suggest possible candidates for :option:`/*verilator&32;split_var*/`. suggest possible candidates for :option:`/*verilator&32;split_var*/`.
The UNOPTFLAT warning may also occur where outputs from a block of logic
are independent, but occur in the same always block. To fix this, use
the :option:`/*verilator&32;isolate_assignments*/` metacomment described
above.
Before version 5.000, the UNOPTFLAT warning may also have been due to Before version 5.000, the UNOPTFLAT warning may also have been due to
clock enables, identified from the reported path going through a clock clock enables, identified from the reported path going through a clock
gating instance. To fix these, the clock_enable meta comment was used. gating instance. To fix these, the clock_enable meta comment was used.

View File

@ -175,7 +175,6 @@ set(HEADERS
V3Simulate.h V3Simulate.h
V3Slice.h V3Slice.h
V3Split.h V3Split.h
V3SplitAs.h
V3SplitVar.h V3SplitVar.h
V3StackCount.h V3StackCount.h
V3Stats.h V3Stats.h
@ -350,7 +349,6 @@ set(COMMON_SOURCES
V3Scoreboard.cpp V3Scoreboard.cpp
V3Slice.cpp V3Slice.cpp
V3Split.cpp V3Split.cpp
V3SplitAs.cpp
V3SplitVar.cpp V3SplitVar.cpp
V3StackCount.cpp V3StackCount.cpp
V3Stats.cpp V3Stats.cpp

View File

@ -333,7 +333,6 @@ RAW_OBJS_PCH_ASTNOMT = \
V3Scoreboard.o \ V3Scoreboard.o \
V3Slice.o \ V3Slice.o \
V3Split.o \ V3Split.o \
V3SplitAs.o \
V3SplitVar.o \ V3SplitVar.o \
V3StackCount.o \ V3StackCount.o \
V3Subst.o \ V3Subst.o \

View File

@ -342,7 +342,6 @@ public:
VAR_PUBLIC_FLAT, // V3LinkParse moves to AstVar::sigPublic VAR_PUBLIC_FLAT, // V3LinkParse moves to AstVar::sigPublic
VAR_PUBLIC_FLAT_RD, // V3LinkParse moves to AstVar::sigPublic VAR_PUBLIC_FLAT_RD, // V3LinkParse moves to AstVar::sigPublic
VAR_PUBLIC_FLAT_RW, // V3LinkParse moves to AstVar::sigPublic VAR_PUBLIC_FLAT_RW, // V3LinkParse moves to AstVar::sigPublic
VAR_ISOLATE_ASSIGNMENTS, // V3LinkParse moves to AstVar::attrIsolateAssign
VAR_SC_BIGUINT, // V3LinkParse moves to AstVar::attrScBigUint VAR_SC_BIGUINT, // V3LinkParse moves to AstVar::attrScBigUint
VAR_SC_BV, // V3LinkParse moves to AstVar::attrScBv VAR_SC_BV, // V3LinkParse moves to AstVar::attrScBv
VAR_SFORMAT, // V3LinkParse moves to AstVar::attrSFormat VAR_SFORMAT, // V3LinkParse moves to AstVar::attrSFormat
@ -364,7 +363,7 @@ public:
"TYPEID", "TYPENAME", "TYPEID", "TYPENAME",
"VAR_BASE", "VAR_FORCEABLE", "VAR_FSM_ARC_INCLUDE_COND", "VAR_FSM_RESET_ARC", "VAR_BASE", "VAR_FORCEABLE", "VAR_FSM_ARC_INCLUDE_COND", "VAR_FSM_RESET_ARC",
"VAR_FSM_STATE", "VAR_PORT_DTYPE", "VAR_PUBLIC", "VAR_PUBLIC_FLAT", "VAR_FSM_STATE", "VAR_PORT_DTYPE", "VAR_PUBLIC", "VAR_PUBLIC_FLAT",
"VAR_PUBLIC_FLAT_RD", "VAR_PUBLIC_FLAT_RW", "VAR_ISOLATE_ASSIGNMENTS", "VAR_PUBLIC_FLAT_RD", "VAR_PUBLIC_FLAT_RW",
"VAR_SC_BIGUINT", "VAR_SC_BV", "VAR_SFORMAT", "VAR_SPLIT_VAR" "VAR_SC_BIGUINT", "VAR_SC_BV", "VAR_SFORMAT", "VAR_SPLIT_VAR"
}; };
// clang-format on // clang-format on

View File

@ -97,7 +97,6 @@ class AstNodeFTask VL_NOT_FINAL : public AstNode {
string m_ifacePortName; // Interface port name for out-of-block definition (IEEE 25.8) string m_ifacePortName; // Interface port name for out-of-block definition (IEEE 25.8)
uint64_t m_dpiOpenParent = 0; // DPI import open array, if !=0, how many callees uint64_t m_dpiOpenParent = 0; // DPI import open array, if !=0, how many callees
bool m_taskPublic : 1; // Public task bool m_taskPublic : 1; // Public task
bool m_attrIsolateAssign : 1; // User isolate_assignments attribute
bool m_classMethod : 1; // Class method bool m_classMethod : 1; // Class method
bool m_didProto : 1; // Did prototype processing bool m_didProto : 1; // Did prototype processing
bool m_prototype : 1; // Just a prototype bool m_prototype : 1; // Just a prototype
@ -130,7 +129,6 @@ protected:
: AstNode{t, fl} : AstNode{t, fl}
, m_name{name} , m_name{name}
, m_taskPublic{false} , m_taskPublic{false}
, m_attrIsolateAssign{false}
, m_classMethod{false} , m_classMethod{false}
, m_didProto{false} , m_didProto{false}
, m_prototype{false} , m_prototype{false}
@ -179,8 +177,6 @@ public:
uint64_t dpiOpenParent() const { return m_dpiOpenParent; } uint64_t dpiOpenParent() const { return m_dpiOpenParent; }
bool taskPublic() const { return m_taskPublic; } bool taskPublic() const { return m_taskPublic; }
void taskPublic(bool flag) { m_taskPublic = flag; } void taskPublic(bool flag) { m_taskPublic = flag; }
bool attrIsolateAssign() const { return m_attrIsolateAssign; }
void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; }
bool classMethod() const { return m_classMethod; } bool classMethod() const { return m_classMethod; }
void classMethod(bool flag) { m_classMethod = flag; } void classMethod(bool flag) { m_classMethod = flag; }
bool didProto() const { return m_didProto; } bool didProto() const { return m_didProto; }
@ -2134,7 +2130,6 @@ class AstVar final : public AstNode {
bool m_funcReturn : 1; // Return variable for a function bool m_funcReturn : 1; // Return variable for a function
bool m_attrScBv : 1; // User force bit vector attribute bool m_attrScBv : 1; // User force bit vector attribute
bool m_attrScBigUint : 1; // User force sc_biguint attribute bool m_attrScBigUint : 1; // User force sc_biguint attribute
bool m_attrIsolateAssign : 1; // User isolate_assignments attribute
bool m_attrSFormat : 1; // User sformat attribute bool m_attrSFormat : 1; // User sformat attribute
bool m_attrSplitVar : 1; // declared with split_var metacomment bool m_attrSplitVar : 1; // declared with split_var metacomment
bool m_attrFsmState : 1; // declared with fsm_state metacomment bool m_attrFsmState : 1; // declared with fsm_state metacomment
@ -2197,7 +2192,6 @@ class AstVar final : public AstNode {
m_funcReturn = false; m_funcReturn = false;
m_attrScBv = false; m_attrScBv = false;
m_attrScBigUint = false; m_attrScBigUint = false;
m_attrIsolateAssign = false;
m_attrSFormat = false; m_attrSFormat = false;
m_attrSplitVar = false; m_attrSplitVar = false;
m_attrFsmState = false; m_attrFsmState = false;
@ -2346,7 +2340,6 @@ public:
void attrFileDescr(bool flag) { m_fileDescr = flag; } void attrFileDescr(bool flag) { m_fileDescr = flag; }
void attrScBv(bool flag) { m_attrScBv = flag; } void attrScBv(bool flag) { m_attrScBv = flag; }
void attrScBigUint(bool flag) { m_attrScBigUint = flag; } void attrScBigUint(bool flag) { m_attrScBigUint = flag; }
void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; }
void attrSFormat(bool flag) { m_attrSFormat = flag; } void attrSFormat(bool flag) { m_attrSFormat = flag; }
void attrSplitVar(bool flag) { m_attrSplitVar = flag; } void attrSplitVar(bool flag) { m_attrSplitVar = flag; }
void attrFsmState(bool flag) { m_attrFsmState = flag; } void attrFsmState(bool flag) { m_attrFsmState = flag; }
@ -2522,7 +2515,6 @@ public:
bool attrFsmRegisterWrapper() const { return m_attrFsmRegisterWrapper; } bool attrFsmRegisterWrapper() const { return m_attrFsmRegisterWrapper; }
bool attrFsmResetArc() const { return m_attrFsmResetArc; } bool attrFsmResetArc() const { return m_attrFsmResetArc; }
bool attrFsmArcInclCond() const { return m_attrFsmArcInclCond; } bool attrFsmArcInclCond() const { return m_attrFsmArcInclCond; }
bool attrIsolateAssign() const { return m_attrIsolateAssign; }
AstIface* sensIfacep() const { return m_sensIfacep; } AstIface* sensIfacep() const { return m_sensIfacep; }
VRandAttr rand() const { return m_rand; } VRandAttr rand() const { return m_rand; }
string verilogKwd() const override; string verilogKwd() const override;
@ -2534,7 +2526,6 @@ public:
// This is getting connected to fromp; keep attributes // This is getting connected to fromp; keep attributes
// Note the method below too // Note the method below too
if (fromp->attrFileDescr()) attrFileDescr(true); if (fromp->attrFileDescr()) attrFileDescr(true);
if (fromp->attrIsolateAssign()) attrIsolateAssign(true);
if (fromp->isContinuously()) isContinuously(true); if (fromp->isContinuously()) isContinuously(true);
} }
void propagateWrapAttrFrom(const AstVar* fromp) { void propagateWrapAttrFrom(const AstVar* fromp) {

View File

@ -3205,7 +3205,6 @@ void AstVar::dump(std::ostream& str) const {
if (noReset()) str << " [!RST]"; if (noReset()) str << " [!RST]";
if (processQueue()) str << " [PROCQ]"; if (processQueue()) str << " [PROCQ]";
if (sampled()) str << " [SAMPLED]"; if (sampled()) str << " [SAMPLED]";
if (attrIsolateAssign()) str << " [aISO]";
if (attrFsmState()) str << " [aFSMSTATE]"; if (attrFsmState()) str << " [aFSMSTATE]";
if (attrFsmResetArc()) str << " [aFSMRESETARC]"; if (attrFsmResetArc()) str << " [aFSMRESETARC]";
if (attrFsmArcInclCond()) str << " [aFSMARCCOND]"; if (attrFsmArcInclCond()) str << " [aFSMARCCOND]";
@ -3240,7 +3239,6 @@ void AstVar::dumpJson(std::ostream& str) const {
dumpJsonBoolFuncIf(str, noReset); dumpJsonBoolFuncIf(str, noReset);
dumpJsonBoolFuncIf(str, processQueue); dumpJsonBoolFuncIf(str, processQueue);
dumpJsonBoolFuncIf(str, sampled); dumpJsonBoolFuncIf(str, sampled);
dumpJsonBoolFuncIf(str, attrIsolateAssign);
dumpJsonBoolFuncIf(str, attrFsmState); dumpJsonBoolFuncIf(str, attrFsmState);
dumpJsonBoolFuncIf(str, attrFsmResetArc); dumpJsonBoolFuncIf(str, attrFsmResetArc);
dumpJsonBoolFuncIf(str, attrFsmArcInclCond); dumpJsonBoolFuncIf(str, attrFsmArcInclCond);

View File

@ -182,7 +182,6 @@ class V3ControlFTask final {
V3ControlVarResolver m_params; // Parameters in function/task V3ControlVarResolver m_params; // Parameters in function/task
V3ControlVarResolver m_ports; // Ports in function/task V3ControlVarResolver m_ports; // Ports in function/task
V3ControlVarResolver m_vars; // Variables in function/task V3ControlVarResolver m_vars; // Variables in function/task
bool m_isolate = false; // Isolate function return
bool m_noinline = false; // Don't inline function/task bool m_noinline = false; // Don't inline function/task
bool m_public = false; // Public function/task bool m_public = false; // Public function/task
@ -190,7 +189,6 @@ public:
V3ControlFTask() = default; V3ControlFTask() = default;
void update(const V3ControlFTask& f) { void update(const V3ControlFTask& f) {
// Don't overwrite true with false // Don't overwrite true with false
if (f.m_isolate) m_isolate = true;
if (f.m_noinline) m_noinline = true; if (f.m_noinline) m_noinline = true;
if (f.m_public) m_public = true; if (f.m_public) m_public = true;
m_params.update(f.m_params); m_params.update(f.m_params);
@ -203,7 +201,6 @@ public:
V3ControlVarResolver& ports() { return m_ports; } V3ControlVarResolver& ports() { return m_ports; }
V3ControlVarResolver& vars() { return m_vars; } V3ControlVarResolver& vars() { return m_vars; }
void setIsolate(bool set) { m_isolate = set; }
void setNoInline(bool set) { m_noinline = set; } void setNoInline(bool set) { m_noinline = set; }
void setPublic(bool set) { m_public = set; } void setPublic(bool set) { m_public = set; }
@ -212,8 +209,6 @@ public:
ftaskp->addStmtsp(new AstPragma{ftaskp->fileline(), VPragmaType::NO_INLINE_TASK}); ftaskp->addStmtsp(new AstPragma{ftaskp->fileline(), VPragmaType::NO_INLINE_TASK});
if (m_public) if (m_public)
ftaskp->addStmtsp(new AstPragma{ftaskp->fileline(), VPragmaType::PUBLIC_TASK}); ftaskp->addStmtsp(new AstPragma{ftaskp->fileline(), VPragmaType::PUBLIC_TASK});
// Only functions can have isolate (return value)
if (VN_IS(ftaskp, Func)) ftaskp->attrIsolateAssign(m_isolate);
} }
}; };
@ -981,13 +976,7 @@ void V3Control::addVarAttr(FileLine* fl, const string& module, const string& fta
// Semantics: Most of the attributes operate on signals // Semantics: Most of the attributes operate on signals
if (pattern.empty()) { if (pattern.empty()) {
if (attr == VAttrType::VAR_ISOLATE_ASSIGNMENTS) { if (attr == VAttrType::VAR_PUBLIC) {
if (ftask.empty()) {
fl->v3error("isolate_assignments only applies to signals or functions/tasks");
} else {
V3ControlResolver::s().modules().at(module).ftasks().at(ftask).setIsolate(true);
}
} else if (attr == VAttrType::VAR_PUBLIC) {
if (ftask.empty()) { if (ftask.empty()) {
// public module, this is the only exception from var here // public module, this is the only exception from var here
V3ControlResolver::s().modules().at(module).addModulePragma( V3ControlResolver::s().modules().at(module).addModulePragma(

View File

@ -1727,7 +1727,6 @@ class LinkDotFindVisitor final : public VNVisitor {
newvarp->lifetime(VLifetime::AUTOMATIC_EXPLICIT); newvarp->lifetime(VLifetime::AUTOMATIC_EXPLICIT);
newvarp->funcReturn(true); newvarp->funcReturn(true);
newvarp->trace(false); // Not user visible newvarp->trace(false); // Not user visible
newvarp->attrIsolateAssign(nodep->attrIsolateAssign());
nodep->fvarp(newvarp); nodep->fvarp(newvarp);
// Explicit insert required, as the var name shadows the upper level's task name // Explicit insert required, as the var name shadows the upper level's task name
m_statep->insertSym(m_curSymp, newvarp->name(), newvarp, nullptr /*classOrPackagep*/); m_statep->insertSym(m_curSymp, newvarp->name(), newvarp, nullptr /*classOrPackagep*/);

View File

@ -606,10 +606,6 @@ class LinkParseVisitor final : public VNVisitor {
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable"); UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
m_varp->sigUserRWPublic(true); m_varp->sigUserRWPublic(true);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
} else if (nodep->attrType() == VAttrType::VAR_ISOLATE_ASSIGNMENTS) {
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
m_varp->attrIsolateAssign(true);
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
} else if (nodep->attrType() == VAttrType::VAR_SFORMAT) { } else if (nodep->attrType() == VAttrType::VAR_SFORMAT) {
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable"); UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
m_varp->attrSFormat(true); m_varp->attrSFormat(true);

View File

@ -351,8 +351,7 @@ std::string reportLoopVars(FileLine* /*warnFl*/, Graph* graphp, SchedAcyclicVarV
if (splittable) { if (splittable) {
ss << V3Error::warnMore() ss << V3Error::warnMore()
<< "... Suggest add /*verilator split_var*/ or /*verilator " << "... Suggest add /*verilator split_var*/ to appropriate variables above.\n";
"isolate_assignments*/ to appropriate variables above.\n";
} }
V3Stats::addStat("Scheduling, split_var, candidates", splittable); V3Stats::addStat("Scheduling, split_var, candidates", splittable);
return ss.str(); return ss.str();

View File

@ -1,195 +0,0 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Break always into separate statements to reduce temps
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// 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: 2003-2026 Wilson Snyder
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
//
//*************************************************************************
// V3SplitAs's Transformations:
//
// Search each ALWAYS for a VARREF lvalue with a /*isolate_assignments*/ attribute
// If found, color statements with both, assignment to that varref, or other assignments.
// Replicate the Always, and remove mis-colored duplicate code.
//
//*************************************************************************
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
#include "V3SplitAs.h"
#include "V3Stats.h"
VL_DEFINE_DEBUG_FUNCTIONS;
//######################################################################
// Find all split variables in a block
class SplitAsFindVisitor final : public VNVisitorConst {
// STATE - across all visitors
AstVarScope* m_splitVscp = nullptr; // Variable we want to split
// METHODS
void visit(AstVarRef* nodep) override {
if (nodep->access().isWriteOrRW() && !m_splitVscp && nodep->varp()->attrIsolateAssign()) {
m_splitVscp = nodep->varScopep();
}
}
void visit(AstExprStmt* nodep) override {
// A function call inside the splitting assignment
// We need to presume the whole call is preserved (if the upper statement is)
// This will break if the m_splitVscp is a "ref" argument to the function,
// but little we can do.
}
void visit(AstNode* nodep) override { iterateChildrenConst(nodep); }
public:
// CONSTRUCTORS
explicit SplitAsFindVisitor(AstAlways* nodep) { iterateConst(nodep); }
~SplitAsFindVisitor() override = default;
// METHODS
AstVarScope* splitVscp() const { return m_splitVscp; }
};
//######################################################################
// Remove nodes not containing proper references
class SplitAsCleanVisitor final : public VNVisitor {
// STATE - across all visitors
const AstVarScope* const m_splitVscp; // Variable we want to split
const bool m_modeMatch; // Remove matching Vscp, else non-matching
// STATE - for current visit position (use VL_RESTORER)
bool m_keepStmt = false; // Current Statement must be preserved
bool m_matches = false; // Statement below has matching lvalue reference
// METHODS
void visit(AstVarRef* nodep) override {
if (nodep->access().isWriteOrRW()) {
if (nodep->varScopep() == m_splitVscp) {
UINFO(6, " CL VAR " << nodep);
m_matches = true;
}
}
}
void visit(AstNodeStmt* nodep) override {
UINFO(6, " CL STMT " << nodep);
const bool oldKeep = m_keepStmt;
{
VL_RESTORER(m_matches);
m_matches = false;
m_keepStmt = false;
iterateChildren(nodep);
if (m_keepStmt || (m_modeMatch ? m_matches : !m_matches)) {
UINFO(6, " Keep STMT " << nodep);
m_keepStmt = true;
} else {
UINFO(6, " Delete STMT " << nodep);
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
}
}
// If something below matches, the upper statement remains too.
m_keepStmt = oldKeep || m_keepStmt;
UINFO(9, " upKeep=" << m_keepStmt << " STMT " << nodep);
}
void visit(AstExprStmt* nodep) override {
// A function call inside the splitting assignment
// We need to presume the whole call is preserved (if the upper statement is)
// This will break if the m_splitVscp is a "ref" argument to the function,
// but little we can do.
}
void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
SplitAsCleanVisitor(AstAlways* nodep, AstVarScope* vscp, bool modeMatch)
: m_splitVscp{vscp}
, m_modeMatch{modeMatch} {
iterate(nodep);
}
~SplitAsCleanVisitor() override = default;
};
//######################################################################
// SplitAs class functions
class SplitAsVisitor final : public VNVisitor {
// NODE STATE
// AstAlways::user() -> bool. True if already processed
const VNUser1InUse m_inuser1;
// STATE - across all visitors
VDouble0 m_statSplits; // Statistic tracking
// METHODS
void splitAlways(AstAlways* nodep, AstVarScope* splitVscp) {
UINFOTREE(9, nodep, "", "in");
// Duplicate it and link in
// Below cloneTree should perhaps be cloneTreePure, but given
// isolate_assignments is required to hit this code, we presume the user
// knows what they are asking for
AstAlways* const newp = nodep->cloneTree(false);
newp->user1(true); // So we don't clone it again
nodep->addNextHere(newp);
{ // Delete stuff we don't want in old
const SplitAsCleanVisitor visitor{nodep, splitVscp, false};
UINFOTREE(9, nodep, "", "out0");
}
{ // Delete stuff we don't want in new
const SplitAsCleanVisitor visitor{newp, splitVscp, true};
UINFOTREE(9, newp, "", "out1");
}
}
void visit(AstAlways* nodep) override {
// Are there any lvalue references below this?
// There could be more than one. So, we process the first one found first.
const AstVarScope* lastSplitVscp = nullptr;
while (!nodep->user1()) {
// Find any splittable variables
const SplitAsFindVisitor visitor{nodep};
AstVarScope* const splitVscp = visitor.splitVscp();
// Now isolate the always
if (splitVscp) {
UINFO(3, "Split " << nodep);
UINFO(3, " For " << splitVscp);
// If we did this last time! Something's stuck!
UASSERT_OBJ(splitVscp != lastSplitVscp, nodep,
"Infinite loop in isolate_assignments removal for: "
<< splitVscp->prettyNameQ());
lastSplitVscp = splitVscp;
splitAlways(nodep, splitVscp);
++m_statSplits;
} else {
nodep->user1(true);
}
}
}
void visit(AstNodeExpr*) override {} // Accelerate
void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:
// CONSTRUCTORS
explicit SplitAsVisitor(AstNetlist* nodep) { iterate(nodep); }
~SplitAsVisitor() override {
V3Stats::addStat("Optimizations, isolate_assignments blocks", m_statSplits);
}
};
//######################################################################
// SplitAs class functions
void V3SplitAs::splitAsAll(AstNetlist* nodep) {
UINFO(2, __FUNCTION__ << ":");
{ SplitAsVisitor{nodep}; } // Destruct before checking
V3Global::dumpCheckGlobalTree("splitas", 0, dumpTreeEitherLevel() >= 3);
}

View File

@ -1,32 +0,0 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Break always into separate statements to reduce temps
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// 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: 2003-2026 Wilson Snyder
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
//
//*************************************************************************
#ifndef VERILATOR_V3SPLITAS_H_
#define VERILATOR_V3SPLITAS_H_
#include "config_build.h"
#include "verilatedos.h"
class AstNetlist;
//============================================================================
class V3SplitAs final {
public:
static void splitAsAll(AstNetlist* nodep) VL_MT_DISABLED;
};
#endif // Guard

View File

@ -98,7 +98,6 @@
#include "V3Scoreboard.h" #include "V3Scoreboard.h"
#include "V3Slice.h" #include "V3Slice.h"
#include "V3Split.h" #include "V3Split.h"
#include "V3SplitAs.h"
#include "V3SplitVar.h" #include "V3SplitVar.h"
#include "V3Stats.h" #include "V3Stats.h"
#include "V3String.h" #include "V3String.h"
@ -421,7 +420,6 @@ static void process() {
// Split single ALWAYS blocks into multiple blocks for better ordering chances // Split single ALWAYS blocks into multiple blocks for better ordering chances
if (v3Global.opt.fSplit()) V3Split::splitAll(v3Global.rootp()); if (v3Global.opt.fSplit()) V3Split::splitAll(v3Global.rootp());
V3SplitAs::splitAsAll(v3Global.rootp());
// Create tracing sample points, before we start eliminating signals // Create tracing sample points, before we start eliminating signals
if (v3Global.opt.trace()) V3TraceDecl::traceDeclAll(v3Global.rootp()); if (v3Global.opt.trace()) V3TraceDecl::traceDeclAll(v3Global.rootp());

View File

@ -3121,7 +3121,7 @@ sigAttr<nodep>:
| yVL_PUBLIC_FLAT { $$ = new AstAttrOf{$1, VAttrType::VAR_PUBLIC_FLAT}; v3Global.dpi(true); } | yVL_PUBLIC_FLAT { $$ = new AstAttrOf{$1, VAttrType::VAR_PUBLIC_FLAT}; v3Global.dpi(true); }
| yVL_PUBLIC_FLAT_RD { $$ = new AstAttrOf{$1, VAttrType::VAR_PUBLIC_FLAT_RD}; v3Global.dpi(true); } | yVL_PUBLIC_FLAT_RD { $$ = new AstAttrOf{$1, VAttrType::VAR_PUBLIC_FLAT_RD}; v3Global.dpi(true); }
| yVL_PUBLIC_FLAT_RW attr_event_controlE { $$ = new AstAttrOf{$1, VAttrType::VAR_PUBLIC_FLAT_RW}; v3Global.dpi(true); DEL($2); } | yVL_PUBLIC_FLAT_RW attr_event_controlE { $$ = new AstAttrOf{$1, VAttrType::VAR_PUBLIC_FLAT_RW}; v3Global.dpi(true); DEL($2); }
| yVL_ISOLATE_ASSIGNMENTS { $$ = new AstAttrOf{$1, VAttrType::VAR_ISOLATE_ASSIGNMENTS}; } | yVL_ISOLATE_ASSIGNMENTS { $$ = nullptr; /* Historical, now has no effect */ }
| yVL_SC_BIGUINT { $$ = new AstAttrOf{$1, VAttrType::VAR_SC_BIGUINT}; } | yVL_SC_BIGUINT { $$ = new AstAttrOf{$1, VAttrType::VAR_SC_BIGUINT}; }
| yVL_SC_BV { $$ = new AstAttrOf{$1, VAttrType::VAR_SC_BV}; } | yVL_SC_BV { $$ = new AstAttrOf{$1, VAttrType::VAR_SC_BV}; }
| yVL_SFORMAT { $$ = new AstAttrOf{$1, VAttrType::VAR_SFORMAT}; } | yVL_SFORMAT { $$ = new AstAttrOf{$1, VAttrType::VAR_SFORMAT}; }
@ -4657,12 +4657,12 @@ task_prototype<nodeFTaskp>: // ==IEEE: task_prototype
function_declaration<nodeFTaskp>: // IEEE: function_declaration + function_body_declaration function_declaration<nodeFTaskp>: // IEEE: function_declaration + function_body_declaration
yFUNCTION dynamic_override_specifiersE lifetimeE funcId funcIsolateE tfGuts yENDFUNCTION endLabelE yFUNCTION dynamic_override_specifiersE lifetimeE funcId funcIsolateE tfGuts yENDFUNCTION endLabelE
{ $$ = $4; $4->attrIsolateAssign($5); $$->addStmtsp($6); { $$ = $4; $$->addStmtsp($6);
$$->baseOverride($2); $$->baseOverride($2);
$$->lifetime($3); $$->lifetime($3);
GRAMMARP->endLabel($<fl>8, $$, $8); } GRAMMARP->endLabel($<fl>8, $$, $8); }
| yFUNCTION dynamic_override_specifiersE lifetimeE funcIdNew funcIsolateE tfNewGuts yENDFUNCTION endLabelE | yFUNCTION dynamic_override_specifiersE lifetimeE funcIdNew funcIsolateE tfNewGuts yENDFUNCTION endLabelE
{ $$ = $4; $4->attrIsolateAssign($5); $$->addStmtsp($6); { $$ = $4; $$->addStmtsp($6);
$$->baseOverride($2); $$->baseOverride($2);
$$->lifetime($3); $$->lifetime($3);
GRAMMARP->endLabel($<fl>8, $$, $8); } GRAMMARP->endLabel($<fl>8, $$, $8); }
@ -8553,8 +8553,7 @@ vltVarAttrSpecE<strp>:
; ;
vltVarAttrFront<attrtypeen>: vltVarAttrFront<attrtypeen>:
yVLT_ISOLATE_ASSIGNMENTS { $$ = VAttrType::VAR_ISOLATE_ASSIGNMENTS; } yVLT_FORCEABLE { $$ = VAttrType::VAR_FORCEABLE; }
| yVLT_FORCEABLE { $$ = VAttrType::VAR_FORCEABLE; }
| yVLT_PUBLIC { $$ = VAttrType::VAR_PUBLIC; v3Global.dpi(true); } | yVLT_PUBLIC { $$ = VAttrType::VAR_PUBLIC; v3Global.dpi(true); }
| yVLT_PUBLIC_FLAT { $$ = VAttrType::VAR_PUBLIC_FLAT; v3Global.dpi(true); } | yVLT_PUBLIC_FLAT { $$ = VAttrType::VAR_PUBLIC_FLAT; v3Global.dpi(true); }
| yVLT_PUBLIC_FLAT_RD { $$ = VAttrType::VAR_PUBLIC_FLAT_RD; v3Global.dpi(true); } | yVLT_PUBLIC_FLAT_RD { $$ = VAttrType::VAR_PUBLIC_FLAT_RD; v3Global.dpi(true); }
@ -8568,6 +8567,7 @@ vltVarAttrFront<attrtypeen>:
vltVarAttrFrontDeprecated: vltVarAttrFrontDeprecated:
yVLT_CLOCK_ENABLE { } yVLT_CLOCK_ENABLE { }
| yVLT_CLOCKER { } | yVLT_CLOCKER { }
| yVLT_ISOLATE_ASSIGNMENTS { }
| yVLT_NO_CLOCKER { } | yVLT_NO_CLOCKER { }
; ;

View File

@ -9,37 +9,14 @@
import vltest_bootstrap import vltest_bootstrap
test.scenarios('simulator') # Note: This test is historical for the isolate_assignments attribute, which
# was deprecated and has no effect today. This test ensures it still parses
# in SystemVerilog and Verilator control files for backward compatibility.
test.scenarios('vlt')
test.top_filename = "t/t_unopt_combo.v" test.top_filename = "t/t_unopt_combo.v"
out_filename = test.obj_dir + "/V" + test.name + ".tree.json" test.compile(verilator_flags2=["+define+ISOLATE"])
test.compile(verilator_flags2=[
"--no-json-edit-nums", "+define+ISOLATE", "--stats", "-fno-dfg", "-fno-lift-expr"
])
if test.vlt_all:
test.file_grep(test.stats, r'Optimizations, isolate_assignments blocks\s+4')
test.file_grep(
out_filename,
r'{"type":"VAR","name":"t.b",.*"loc":"\w,23:[^"]*",.*"origName":"b",.*"attrIsolateAssign":true,.*"dtypeName":"logic"'
)
test.file_grep(
out_filename,
r'{"type":"VAR","name":"__Vfunc_t.file.get_31_16__0__Vfuncout",.*"loc":"\w,99:[^"]*",.*"origName":"__Vfunc_t__DOT__file__DOT__get_31_16__0__Vfuncout",.*"attrIsolateAssign":true,.*"dtypeName":"logic"'
)
test.file_grep(
out_filename,
r'{"type":"VAR","name":"__Vfunc_t.file.get_31_16__0__t_crc",.*"loc":"\w,100:[^"]*",.*"origName":"__Vfunc_t__DOT__file__DOT__get_31_16__0__t_crc",.*"attrIsolateAssign":true,.*"dtypeName":"logic"'
)
test.file_grep(
out_filename,
r'{"type":"VAR","name":"__Vtask_t.file.set_b_d__1__t_crc",.*"loc":"\w,112:[^"]*",.*"origName":"__Vtask_t__DOT__file__DOT__set_b_d__1__t_crc",.*"attrIsolateAssign":true,.*"dtypeName":"logic"'
)
test.file_grep(
out_filename,
r'{"type":"VAR","name":"__Vtask_t.file.set_b_d__1__t_c",.*"loc":"\w,113:[^"]*",.*"origName":"__Vtask_t__DOT__file__DOT__set_b_d__1__t_c",.*"attrIsolateAssign":true,.*"dtypeName":"logic"'
)
test.execute() test.execute()

View File

@ -9,38 +9,14 @@
import vltest_bootstrap import vltest_bootstrap
test.scenarios('simulator') # Note: This test is historical for the isolate_assignments attribute, which
# was deprecated and has no effect today. This test ensures it still parses
# in SystemVerilog and Verilator control files for backward compatibility.
test.scenarios('vlt')
test.top_filename = "t/t_unopt_combo.v" test.top_filename = "t/t_unopt_combo.v"
out_filename = test.obj_dir + "/V" + test.name + ".tree.json" test.compile(verilator_flags2=[test.t_dir + "/t_unopt_combo_isolate.vlt"])
test.compile(verilator_flags2=[
"--no-json-edit-nums", "--stats", test.t_dir +
"/t_unopt_combo_isolate.vlt", "-fno-dfg", "-fno-lift-expr"
])
if test.vlt_all:
test.file_grep(test.stats, r'Optimizations, isolate_assignments blocks\s+4')
test.file_grep(
out_filename,
r'{"type":"VAR","name":"t.b",.*"loc":"\w,23:[^"]*",.*"origName":"b",.*"attrIsolateAssign":true,.*"dtypeName":"logic"'
)
test.file_grep(
out_filename,
r'{"type":"VAR","name":"__Vfunc_t.file.get_31_16__0__Vfuncout",.*"loc":"\w,104:[^"]*",.*"origName":"__Vfunc_t__DOT__file__DOT__get_31_16__0__Vfuncout",.*"attrIsolateAssign":true,.*"dtypeName":"logic"'
)
test.file_grep(
out_filename,
r'{"type":"VAR","name":"__Vfunc_t.file.get_31_16__0__t_crc",.*"loc":"\w,105:[^"]*",.*"origName":"__Vfunc_t__DOT__file__DOT__get_31_16__0__t_crc",.*"attrIsolateAssign":true,.*"dtypeName":"logic"'
)
test.file_grep(
out_filename,
r'{"type":"VAR","name":"__Vtask_t.file.set_b_d__1__t_crc",.*"loc":"\w,115:[^"]*",.*"origName":"__Vtask_t__DOT__file__DOT__set_b_d__1__t_crc",.*"attrIsolateAssign":true,.*"dtypeName":"logic"'
)
test.file_grep(
out_filename,
r'{"type":"VAR","name":"__Vtask_t.file.set_b_d__1__t_c",.*"loc":"\w,116:[^"]*",.*"origName":"__Vtask_t__DOT__file__DOT__set_b_d__1__t_c",.*"attrIsolateAssign":true,.*"dtypeName":"logic"'
)
test.execute() test.execute()

View File

@ -10,5 +10,5 @@
t/t_unoptflat_simple_2.v:16:14: t.x, width 3, circular fanout 2, can split_var t/t_unoptflat_simple_2.v:16:14: t.x, width 3, circular fanout 2, can split_var
... Candidates with the highest fanout: ... Candidates with the highest fanout:
t/t_unoptflat_simple_2.v:16:14: t.x, width 3, circular fanout 2, can split_var t/t_unoptflat_simple_2.v:16:14: t.x, width 3, circular fanout 2, can split_var
... Suggest add /*verilator split_var*/ or /*verilator isolate_assignments*/ to appropriate variables above. ... Suggest add /*verilator split_var*/ to appropriate variables above.
%Error: Exiting due to %Error: Exiting due to

View File

@ -2,28 +2,25 @@
9 | public -module "t" @(posedge clk) 9 | public -module "t" @(posedge clk)
| ^ | ^
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: t/t_vlt_syntax_bad.vlt:11:1: isolate_assignments only applies to signals or functions/tasks %Error: t/t_vlt_syntax_bad.vlt:11:1: Argument -match only supported for lint_off
11 | isolate_assignments -module "t" 11 | tracing_off --file "*" -match "nothing"
| ^~~~~~~~~~~~~~~~~~~
%Error: t/t_vlt_syntax_bad.vlt:13:1: Argument -match only supported for lint_off
13 | tracing_off --file "*" -match "nothing"
| ^~~~~~~~~~~ | ^~~~~~~~~~~
%Error: t/t_vlt_syntax_bad.vlt:13:1: Argument -scope only supported for tracing_on/off
13 | lint_off --rule UNOPTFLAT -scope "top*"
| ^~~~~~~~
%Error: t/t_vlt_syntax_bad.vlt:14:1: Argument -scope only supported for tracing_on/off_off
14 | lint_off --rule UNOPTFLAT -scope "top*" -levels 0
| ^~~~~~~~
%Error: t/t_vlt_syntax_bad.vlt:15:1: Argument -scope only supported for tracing_on/off %Error: t/t_vlt_syntax_bad.vlt:15:1: Argument -scope only supported for tracing_on/off
15 | lint_off --rule UNOPTFLAT -scope "top*" 15 | lint_on --rule UNOPTFLAT -scope "top*"
| ^~~~~~~~ | ^~~~~~~
%Error: t/t_vlt_syntax_bad.vlt:16:1: Argument -scope only supported for tracing_on/off_off %Error: t/t_vlt_syntax_bad.vlt:16:1: Argument -scope only supported for tracing_on/off_off
16 | lint_off --rule UNOPTFLAT -scope "top*" -levels 0 16 | lint_on --rule UNOPTFLAT -scope "top*" -levels 0
| ^~~~~~~~
%Error: t/t_vlt_syntax_bad.vlt:17:1: Argument -scope only supported for tracing_on/off
17 | lint_on --rule UNOPTFLAT -scope "top*"
| ^~~~~~~ | ^~~~~~~
%Error: t/t_vlt_syntax_bad.vlt:18:1: Argument -scope only supported for tracing_on/off_off %Error: t/t_vlt_syntax_bad.vlt:18:1: forceable missing -module
18 | lint_on --rule UNOPTFLAT -scope "top*" -levels 0 18 | forceable -module "" -var "net_*"
| ^~~~~~~
%Error: t/t_vlt_syntax_bad.vlt:20:1: forceable missing -module
20 | forceable -module "" -var "net_*"
| ^~~~~~~~~ | ^~~~~~~~~
%Error: t/t_vlt_syntax_bad.vlt:22:1: missing -var %Error: t/t_vlt_syntax_bad.vlt:20:1: missing -var
22 | forceable -module "top" -var "" 20 | forceable -module "top" -var ""
| ^~~~~~~~~ | ^~~~~~~~~
%Error: Exiting due to %Error: Exiting due to

View File

@ -7,8 +7,6 @@
`verilator_config `verilator_config
public -module "t" @(posedge clk) public -module "t" @(posedge clk)
// only signals/functions/tasks
isolate_assignments -module "t"
// -match not supported // -match not supported
tracing_off --file "*" -match "nothing" tracing_off --file "*" -match "nothing"
// -scope not supported // -scope not supported