diff --git a/src/V3Ast.h b/src/V3Ast.h index 2963987f2..5a4e95245 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -730,6 +730,7 @@ public: // ACCESSORS for specific types // Alas these can't be virtual or they break when passed a nullptr + bool isDisableQueuePushSelfStmt(); inline bool isClassHandleValue() const; inline bool isNull() const; inline bool isZero() const; diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 8fa797adb..4d8c55738 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -108,6 +108,21 @@ int AstNodeSel::bitConst() const { 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::dumpJson(std::ostream& str) const { dumpJsonGen(str); } diff --git a/src/V3Fork.cpp b/src/V3Fork.cpp index 8ee9452cc..0b58c859c 100644 --- a/src/V3Fork.cpp +++ b/src/V3Fork.cpp @@ -593,40 +593,18 @@ class ForkVisitor final : public VNVisitor { const AstConst* const constp = VN_CAST(delayp->lhsp(), Const); return constp && (constp->toUQuad() == std::numeric_limits::max()); } - static bool isDisableProcessQueueExpr(const AstNodeExpr* const nodep) { - const AstNode* const basep - = AstArraySel::baseFromp(const_cast(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)) { + static bool isDisableQueuePushSelfPrefix(AstNode* nodep) { + while (AstJumpBlock* const jumpBlockp = VN_CAST(nodep, JumpBlock)) { nodep = jumpBlockp->stmtsp(); } - return nodep; - } - static bool isDisableQueuePushSelfPrefix(const AstNode* const nodep) { - return isDisableQueuePushSelfStmt(unwrapLeadingJumpBlocks(nodep)); + return nodep && nodep->isDisableQueuePushSelfStmt(); } template static bool insertForkSentinelAfterDisableQueuePushes(T_Owner* const ownerp, AstNode* const firstStmtp, AstNode* const delayp) { AstNode* insertBeforep = firstStmtp; - while (insertBeforep && isDisableQueuePushSelfStmt(insertBeforep)) { + while (insertBeforep && insertBeforep->isDisableQueuePushSelfStmt()) { insertBeforep = insertBeforep->nextp(); } if (AstJumpBlock* const jumpBlockp = VN_CAST(insertBeforep, JumpBlock)) { @@ -654,9 +632,8 @@ class ForkVisitor final : public VNVisitor { = insertForkSentinelAfterDisableQueuePushes(beginp, afterSentinelp, delayp); UASSERT_OBJ(moved, beginp, "Failed to move fork sentinel after disable queue pushes"); } - static bool forkIsDisableable(const AstFork* const nodep) { - for (const AstBegin* itemp = nodep->forksp(); itemp; - itemp = VN_AS(itemp->nextp(), Begin)) { + static bool forkIsDisableable(AstFork* const nodep) { + for (AstBegin* itemp = nodep->forksp(); itemp; itemp = VN_AS(itemp->nextp(), Begin)) { if (isDisableQueuePushSelfPrefix(itemp->stmtsp())) return true; } return false; @@ -680,7 +657,8 @@ class ForkVisitor final : public VNVisitor { // 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 // 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)) { UINFO(9, "Adding fork branch start sentinels " << nodep); FileLine* fl = nodep->fileline(); diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 2f06855fd..09885ca98 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -6209,7 +6209,7 @@ class LinkDotResolveVisitor final : public VNVisitor { nodep->targetRefp()->unlinkFrBack()->deleteTree(); if (!hasPartSelect) { const string instancePath = targetInstancePath(nodep->targetp(), targetPath); - if (instancePath != "") { + if (!instancePath.empty()) { // Keep only the instance prefix so V3LinkJump can reference the selected // instance's process queue without reparsing the disable target. nodep->targetRefp( diff --git a/src/V3LinkJump.cpp b/src/V3LinkJump.cpp index 22020ce0e..c6578cdc2 100644 --- a/src/V3LinkJump.cpp +++ b/src/V3LinkJump.cpp @@ -607,8 +607,8 @@ class LinkJumpVisitor final : public VNVisitor { // 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. AstBegin* const branchp = innerForkBranchp(beginp); - AstBegin* const jumpTargetp = branchp ? branchp : m_beginDisableBegins[beginp]; - UASSERT_OBJ(jumpTargetp, nodep, "Missing disable jump target"); + AstBegin* const jumpTargetp + = branchp ? branchp : m_beginDisableBegins.at(beginp); addJumpAfterKill(killStmtp, jumpTargetp); } } else { diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp index 2da6485f5..385bf8c8a 100644 --- a/src/V3Timing.cpp +++ b/src/V3Timing.cpp @@ -749,31 +749,19 @@ class TimingControlVisitor final : public VNVisitor { addDebugInfo(donep); beginp->addStmtsp(donep->makeStmt()); } - static bool isDisableProcessQueueExpr(const AstNodeExpr* const nodep) { - const AstNode* const basep - = AstArraySel::baseFromp(const_cast(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) { + static bool hasDisableQueuePushSelfPrefix(AstBegin* const beginp) { // LinkJump prepends disable-by-name registration as: // __VprocessQueue_*.push_back(std::process::self()) - // By this pass V3LiftExpr has lifted the std::process::self() argument into a preceding - // temporary (and left a leading comment), so the push_back is no longer necessarily the - // first statement. Scan across the leading registration statements for it, stopping at the - // fork-start sentinel or the branch body. The branch's own registration is at the front; - // registrations for nested forks live in sub-blocks and so are not in this statement list. - for (const AstNode* stmtp = beginp->stmtsp(); stmtp; stmtp = stmtp->nextp()) { + // V3LiftExpr lifts std::process::self() into an assignment to a temporary, then V3Task + // lowers that assignment's function call into a leading comment and AstStmtExpr. Thus the + // push_back is no longer necessarily the first statement. Scan across this generated + // prefix for it, stopping at the fork-start sentinel or the branch body. Registrations for + // nested forks live in sub-blocks and so are not in this statement list. + for (AstNode* stmtp = beginp->stmtsp(); stmtp; stmtp = stmtp->nextp()) { if (VN_IS(stmtp, Comment)) continue; - const AstStmtExpr* const stmtExprp = VN_CAST(stmtp, StmtExpr); + AstStmtExpr* const stmtExprp = VN_CAST(stmtp, StmtExpr); if (!stmtExprp) break; - const AstCMethodHard* const methodp = VN_CAST(stmtExprp->exprp(), CMethodHard); - if (!methodp || methodp->name() != "push_back") continue; - if (isDisableProcessQueueExpr(methodp->fromp())) return true; + if (stmtExprp->isDisableQueuePushSelfStmt()) return true; } return false; }