Fix fork/join_non disable by name race.

This commit is contained in:
Nick Brereton 2026-03-02 22:44:34 -05:00
parent 81c898ef2f
commit 6f154fa1ba
2 changed files with 38 additions and 2 deletions

View File

@ -582,6 +582,39 @@ class ForkVisitor final : public VNVisitor {
// We did wrap the body
return true;
}
static bool isForkJoinNoneSentinelDelay(const AstNode* const nodep) {
const AstDelay* const delayp = VN_CAST(nodep, Delay);
if (!delayp) return false;
const AstConst* const constp = VN_CAST(delayp->lhsp(), Const);
return constp && (constp->toUQuad() == std::numeric_limits<uint64_t>::max());
}
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;
const AstVarRef* const queueRefp = VN_CAST(methodp->fromp(), VarRef);
return queueRefp && queueRefp->name().rfind("__VprocessQueue_", 0) == 0;
}
static void moveForkSentinelAfterDisableQueuePushes(AstBegin* const beginp) {
AstNode* const firstStmtp = beginp->stmtsp();
if (!isForkJoinNoneSentinelDelay(firstStmtp)) return;
AstNode* insertBeforep = firstStmtp->nextp();
while (insertBeforep && isDisableQueuePushSelfStmt(insertBeforep)) {
insertBeforep = insertBeforep->nextp();
}
if (insertBeforep == firstStmtp->nextp()) return;
AstNode* const delayp = firstStmtp->unlinkFrBackWithNext();
if (insertBeforep) {
insertBeforep->addHereThisAsNext(delayp);
} else {
beginp->addStmtsp(delayp);
}
}
// VISITORS
void visit(AstNodeModule* nodep) override {
@ -619,6 +652,7 @@ class ForkVisitor final : public VNVisitor {
new AstConst{fl, AstConst::Unsized64{}, std::numeric_limits<uint64_t>::max()},
false};
itemp->stmtsp()->addHereThisAsNext(delayp);
moveForkSentinelAfterDisableQueuePushes(itemp);
}
}

View File

@ -9,8 +9,10 @@
import vltest_bootstrap
test.scenarios('linter')
test.scenarios('simulator')
test.lint()
test.compile(timing_loop=True, verilator_flags2=["--timing"])
test.execute()
test.passes()