Address disable handling review feedback (#7856)

This commit is contained in:
wsxarcher 2026-07-10 21:37:42 +02:00
parent 7c1de44646
commit e8fd3ae41a
6 changed files with 36 additions and 54 deletions

View File

@ -730,6 +730,7 @@ public:
// ACCESSORS for specific types // ACCESSORS for specific types
// Alas these can't be virtual or they break when passed a nullptr // Alas these can't be virtual or they break when passed a nullptr
bool isDisableQueuePushSelfStmt();
inline bool isClassHandleValue() const; inline bool isClassHandleValue() const;
inline bool isNull() const; inline bool isNull() const;
inline bool isZero() const; inline bool isZero() const;

View File

@ -108,6 +108,21 @@ int AstNodeSel::bitConst() const {
return (constp ? constp->toSInt() : 0); return (constp ? constp->toSInt() : 0);
} }
bool AstNode::isDisableQueuePushSelfStmt() {
// Detect LinkJump-generated registration:
// __VprocessQueue_*.push_back(std::process::self())
AstStmtExpr* const stmtExprp = VN_CAST(this, StmtExpr);
if (!stmtExprp) return false;
AstCMethodHard* const methodp = VN_CAST(stmtExprp->exprp(), CMethodHard);
if (!methodp || methodp->name() != "push_back") return false;
AstNode* const basep = AstArraySel::baseFromp(methodp->fromp(), false);
if (AstVarRef* const refp = VN_CAST(basep, VarRef)) return refp->varp()->processQueue();
if (AstMemberSel* const selp = VN_CAST(basep, MemberSel)) {
return selp->varp() && selp->varp()->processQueue();
}
return false;
}
void AstNodeStmt::dump(std::ostream& str) const { this->AstNode::dump(str); } void AstNodeStmt::dump(std::ostream& str) const { this->AstNode::dump(str); }
void AstNodeStmt::dumpJson(std::ostream& str) const { dumpJsonGen(str); } void AstNodeStmt::dumpJson(std::ostream& str) const { dumpJsonGen(str); }

View File

@ -593,40 +593,18 @@ class ForkVisitor final : public VNVisitor {
const AstConst* const constp = VN_CAST(delayp->lhsp(), Const); const AstConst* const constp = VN_CAST(delayp->lhsp(), Const);
return constp && (constp->toUQuad() == std::numeric_limits<uint64_t>::max()); return constp && (constp->toUQuad() == std::numeric_limits<uint64_t>::max());
} }
static bool isDisableProcessQueueExpr(const AstNodeExpr* const nodep) { static bool isDisableQueuePushSelfPrefix(AstNode* nodep) {
const AstNode* const basep while (AstJumpBlock* const jumpBlockp = VN_CAST(nodep, JumpBlock)) {
= AstArraySel::baseFromp(const_cast<AstNodeExpr*>(nodep), false);
if (const AstVarRef* const refp = VN_CAST(basep, VarRef))
return refp->varp()->processQueue();
if (const AstMemberSel* const selp = VN_CAST(basep, MemberSel)) {
return selp->varp() && selp->varp()->processQueue();
}
return false;
}
static bool isDisableQueuePushSelfStmt(const AstNode* const nodep) {
// Detect LinkJump-generated registration:
// __VprocessQueue_*.push_back(std::process::self())
const AstStmtExpr* const stmtExprp = VN_CAST(nodep, StmtExpr);
if (!stmtExprp) return false;
const AstCMethodHard* const methodp = VN_CAST(stmtExprp->exprp(), CMethodHard);
if (!methodp || methodp->name() != "push_back") return false;
return isDisableProcessQueueExpr(methodp->fromp());
}
static const AstNode* unwrapLeadingJumpBlocks(const AstNode* nodep) {
while (const AstJumpBlock* const jumpBlockp = VN_CAST(nodep, JumpBlock)) {
nodep = jumpBlockp->stmtsp(); nodep = jumpBlockp->stmtsp();
} }
return nodep; return nodep && nodep->isDisableQueuePushSelfStmt();
}
static bool isDisableQueuePushSelfPrefix(const AstNode* const nodep) {
return isDisableQueuePushSelfStmt(unwrapLeadingJumpBlocks(nodep));
} }
template <typename T_Owner> template <typename T_Owner>
static bool insertForkSentinelAfterDisableQueuePushes(T_Owner* const ownerp, static bool insertForkSentinelAfterDisableQueuePushes(T_Owner* const ownerp,
AstNode* const firstStmtp, AstNode* const firstStmtp,
AstNode* const delayp) { AstNode* const delayp) {
AstNode* insertBeforep = firstStmtp; AstNode* insertBeforep = firstStmtp;
while (insertBeforep && isDisableQueuePushSelfStmt(insertBeforep)) { while (insertBeforep && insertBeforep->isDisableQueuePushSelfStmt()) {
insertBeforep = insertBeforep->nextp(); insertBeforep = insertBeforep->nextp();
} }
if (AstJumpBlock* const jumpBlockp = VN_CAST(insertBeforep, JumpBlock)) { if (AstJumpBlock* const jumpBlockp = VN_CAST(insertBeforep, JumpBlock)) {
@ -654,9 +632,8 @@ class ForkVisitor final : public VNVisitor {
= insertForkSentinelAfterDisableQueuePushes(beginp, afterSentinelp, delayp); = insertForkSentinelAfterDisableQueuePushes(beginp, afterSentinelp, delayp);
UASSERT_OBJ(moved, beginp, "Failed to move fork sentinel after disable queue pushes"); UASSERT_OBJ(moved, beginp, "Failed to move fork sentinel after disable queue pushes");
} }
static bool forkIsDisableable(const AstFork* const nodep) { static bool forkIsDisableable(AstFork* const nodep) {
for (const AstBegin* itemp = nodep->forksp(); itemp; for (AstBegin* itemp = nodep->forksp(); itemp; itemp = VN_AS(itemp->nextp(), Begin)) {
itemp = VN_AS(itemp->nextp(), Begin)) {
if (isDisableQueuePushSelfPrefix(itemp->stmtsp())) return true; if (isDisableQueuePushSelfPrefix(itemp->stmtsp())) return true;
} }
return false; return false;
@ -680,7 +657,8 @@ class ForkVisitor final : public VNVisitor {
// start executing until the parent process is blocked or terminates. Because join and // start executing until the parent process is blocked or terminates. Because join and
// join_any block the parent process, deferring branch start with a synthetic #0 delay is // join_any block the parent process, deferring branch start with a synthetic #0 delay is
// normally only needed for join_none. A fork that can be disabled by name needs the same // normally only needed for join_none. A fork that can be disabled by name needs the same
// deferral for every join type. // deferral for every join type so all branches register their processes before any branch
// body can disable the block.
if (nodep->joinType().joinNone() || forkIsDisableable(nodep)) { if (nodep->joinType().joinNone() || forkIsDisableable(nodep)) {
UINFO(9, "Adding fork branch start sentinels " << nodep); UINFO(9, "Adding fork branch start sentinels " << nodep);
FileLine* fl = nodep->fileline(); FileLine* fl = nodep->fileline();

View File

@ -6209,7 +6209,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
nodep->targetRefp()->unlinkFrBack()->deleteTree(); nodep->targetRefp()->unlinkFrBack()->deleteTree();
if (!hasPartSelect) { if (!hasPartSelect) {
const string instancePath = targetInstancePath(nodep->targetp(), targetPath); const string instancePath = targetInstancePath(nodep->targetp(), targetPath);
if (instancePath != "") { if (!instancePath.empty()) {
// Keep only the instance prefix so V3LinkJump can reference the selected // Keep only the instance prefix so V3LinkJump can reference the selected
// instance's process queue without reparsing the disable target. // instance's process queue without reparsing the disable target.
nodep->targetRefp( nodep->targetRefp(

View File

@ -607,8 +607,8 @@ class LinkJumpVisitor final : public VNVisitor {
// If disable executes inside a fork branch of this named block, jump to the // If disable executes inside a fork branch of this named block, jump to the
// end of that branch to prevent statements after disable from executing. // end of that branch to prevent statements after disable from executing.
AstBegin* const branchp = innerForkBranchp(beginp); AstBegin* const branchp = innerForkBranchp(beginp);
AstBegin* const jumpTargetp = branchp ? branchp : m_beginDisableBegins[beginp]; AstBegin* const jumpTargetp
UASSERT_OBJ(jumpTargetp, nodep, "Missing disable jump target"); = branchp ? branchp : m_beginDisableBegins.at(beginp);
addJumpAfterKill(killStmtp, jumpTargetp); addJumpAfterKill(killStmtp, jumpTargetp);
} }
} else { } else {

View File

@ -749,31 +749,19 @@ class TimingControlVisitor final : public VNVisitor {
addDebugInfo(donep); addDebugInfo(donep);
beginp->addStmtsp(donep->makeStmt()); beginp->addStmtsp(donep->makeStmt());
} }
static bool isDisableProcessQueueExpr(const AstNodeExpr* const nodep) { static bool hasDisableQueuePushSelfPrefix(AstBegin* const beginp) {
const AstNode* const basep
= AstArraySel::baseFromp(const_cast<AstNodeExpr*>(nodep), false);
if (const AstVarRef* const refp = VN_CAST(basep, VarRef))
return refp->varp()->processQueue();
if (const AstMemberSel* const selp = VN_CAST(basep, MemberSel)) {
return selp->varp() && selp->varp()->processQueue();
}
return false;
}
static bool hasDisableQueuePushSelfPrefix(const AstBegin* const beginp) {
// LinkJump prepends disable-by-name registration as: // LinkJump prepends disable-by-name registration as:
// __VprocessQueue_*.push_back(std::process::self()) // __VprocessQueue_*.push_back(std::process::self())
// By this pass V3LiftExpr has lifted the std::process::self() argument into a preceding // V3LiftExpr lifts std::process::self() into an assignment to a temporary, then V3Task
// temporary (and left a leading comment), so the push_back is no longer necessarily the // lowers that assignment's function call into a leading comment and AstStmtExpr. Thus the
// first statement. Scan across the leading registration statements for it, stopping at the // push_back is no longer necessarily the first statement. Scan across this generated
// fork-start sentinel or the branch body. The branch's own registration is at the front; // prefix for it, stopping at the fork-start sentinel or the branch body. Registrations for
// registrations for nested forks live in sub-blocks and so are not in this statement list. // nested forks live in sub-blocks and so are not in this statement list.
for (const AstNode* stmtp = beginp->stmtsp(); stmtp; stmtp = stmtp->nextp()) { for (AstNode* stmtp = beginp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
if (VN_IS(stmtp, Comment)) continue; if (VN_IS(stmtp, Comment)) continue;
const AstStmtExpr* const stmtExprp = VN_CAST(stmtp, StmtExpr); AstStmtExpr* const stmtExprp = VN_CAST(stmtp, StmtExpr);
if (!stmtExprp) break; if (!stmtExprp) break;
const AstCMethodHard* const methodp = VN_CAST(stmtExprp->exprp(), CMethodHard); if (stmtExprp->isDisableQueuePushSelfStmt()) return true;
if (!methodp || methodp->name() != "push_back") continue;
if (isDisableProcessQueueExpr(methodp->fromp())) return true;
} }
return false; return false;
} }