@@ -175,6 +175,8 @@ class RandomizeMarkVisitor final : public VNVisitor {
175175 if (varrefp->varp () == varp) return true ;
176176 } else if (const AstMemberSel* const memberselp = VN_CAST (exprp, MemberSel)) {
177177 if (memberselp->varp () == varp) return true ;
178+ } else if (const AstArraySel* const arrselp = VN_CAST (exprp, ArraySel)) {
179+ if (VN_AS (arrselp->fromp (), VarRef)->varp () == varp) return true ;
178180 }
179181 }
180182 return false ;
@@ -535,14 +537,19 @@ class RandomizeMarkVisitor final : public VNVisitor {
535537 AstNodeExpr* exprp = argp->exprp ();
536538 while (exprp) {
537539 AstVar* randVarp = nullptr ;
540+ AstVarRef* varrefp = nullptr ;
538541 if (AstMemberSel* const memberSelp = VN_CAST (exprp, MemberSel)) {
539542 randVarp = memberSelp->varp ();
540543 exprp = memberSelp->fromp ();
544+ } else if ((varrefp = VN_CAST (exprp, VarRef))) {
545+ randVarp = varrefp->varp ();
546+ varrefp->user1 (true );
547+ exprp = nullptr ;
541548 } else {
542- AstVarRef* varrefp = nullptr ;
543- varrefp = VN_AS (exprp, VarRef);
549+ varrefp = VN_AS (VN_CAST (exprp, ArraySel)->fromp (), VarRef);
544550 randVarp = varrefp->varp ();
545551 varrefp->user1 (true );
552+ varrefp->access (VAccess::READWRITE);
546553 exprp = nullptr ;
547554 }
548555 UASSERT_OBJ (randVarp, nodep, " No rand variable found" );
@@ -674,7 +681,7 @@ class RandomizeMarkVisitor final : public VNVisitor {
674681
675682 void visit (AstNodeExpr* nodep) override {
676683 iterateChildrenConst (nodep);
677- if (!m_constraintExprGenp) return ;
684+ if (!m_constraintExprGenp && !m_inStdWith ) return ;
678685 nodep->user1 ((nodep->op1p () && nodep->op1p ()->user1 ())
679686 || (nodep->op2p () && nodep->op2p ()->user1 ())
680687 || (nodep->op3p () && nodep->op3p ()->user1 ())
@@ -1425,6 +1432,7 @@ class CaptureVisitor final : public VNVisitor {
14251432 AstVar* getVar (AstVar* const varp) const {
14261433 const auto it = m_varCloneMap.find (varp);
14271434 if (it == m_varCloneMap.end ()) return nullptr ;
1435+ if (it->second ->isStdRandomizeArg ()) return nullptr ;
14281436 return it->second ;
14291437 }
14301438
@@ -1495,6 +1503,7 @@ class CaptureVisitor final : public VNVisitor {
14951503 if (m_ignore.count (nodep)) return ;
14961504 m_ignore.emplace (nodep);
14971505 UASSERT_OBJ (nodep->varp (), nodep, " Variable unlinked" );
1506+ if (nodep->varp ()->isStdRandomizeArg ()) return ;
14981507 CaptureMode capMode = getVarRefCaptureMode (nodep);
14991508 if (mode (capMode) == CaptureMode::CAP_NO) return ;
15001509 if (mode (capMode) == CaptureMode::CAP_VALUE) captureRefByValue (nodep, capMode);
@@ -1633,6 +1642,33 @@ class RandomizeVisitor final : public VNVisitor {
16331642 std::set<std::string> m_writtenVars; // Track write_var calls per class to avoid duplicates
16341643
16351644 // METHODS
1645+ // Check if two nodes are semantically equivalent (not pointer equality):
1646+ static bool isSimilarNode (const AstNodeExpr* withExpr, const AstNodeExpr* argExpr) {
1647+ // VarRef: compare variable pointers
1648+ if (VN_IS (argExpr, VarRef) && VN_IS (withExpr, VarRef)) {
1649+ return VN_AS (withExpr, VarRef)->varp () == VN_AS (argExpr, VarRef)->varp ();
1650+ }
1651+ // MemberSel: compare object and member (obj.y)
1652+ if (VN_IS (argExpr, MemberSel) && VN_IS (withExpr, MemberSel)) {
1653+ const AstMemberSel* const withMSp = VN_AS (withExpr, MemberSel);
1654+ const AstMemberSel* const argMSp = VN_AS (argExpr, MemberSel);
1655+ if (withMSp->varp () != argMSp->varp ()) return false ;
1656+ // Recursively compare the base object expression
1657+ return isSimilarNode (withMSp->fromp (), argMSp->fromp ());
1658+ }
1659+ // ArraySel: compare array base and index (arr[i])
1660+ if (VN_IS (argExpr, ArraySel) && VN_IS (withExpr, ArraySel)) {
1661+ const AstArraySel* const withASp = VN_AS (withExpr, ArraySel);
1662+ const AstArraySel* const argASp = VN_AS (argExpr, ArraySel);
1663+ // Index must be Sel type, extract VarRef using fromp()
1664+ if (!VN_IS (withASp->bitp (), Sel) || !VN_IS (argASp->bitp (), Sel)) return false ;
1665+ const AstNodeExpr* const withIdxp = VN_AS (withASp->bitp (), Sel)->fromp ();
1666+ const AstNodeExpr* const argIdxp = VN_AS (argASp->bitp (), Sel)->fromp ();
1667+ return isSimilarNode (withASp->fromp (), argASp->fromp ())
1668+ && isSimilarNode (withIdxp, argIdxp);
1669+ }
1670+ return false ;
1671+ }
16361672 void createRandomGenerator (AstClass* const classp) {
16371673 if (classp->user3p ()) return ;
16381674 if (classp->extendsp ()) {
@@ -2605,45 +2641,35 @@ class RandomizeVisitor final : public VNVisitor {
26052641 new AstConst{nodep->fileline (), AstConst::WidthedValue{}, 32 , 1 }});
26062642 std::unique_ptr<CaptureVisitor> withCapturep;
26072643 int argn = 0 ;
2644+ AstWith* withp = nullptr ;
26082645 for (AstNode* pinp = nodep->pinsp (); pinp; pinp = pinp->nextp ()) {
2609- AstArg* const argp = VN_CAST (pinp, Arg);
2610- AstWith* const withp = VN_CAST (pinp, With);
2611- if (withp) {
2612- FileLine* const fl = nodep->fileline ();
2613- withCapturep
2614- = std::make_unique<CaptureVisitor>(withp->exprp (), m_modp, nullptr );
2615- withCapturep->addFunctionArguments (randomizeFuncp);
2616- // Clear old constraints and variables for std::randomize with clause
2617- if (stdrand) {
2618- randomizeFuncp->addStmtsp (
2619- implementConstraintsClearAll (randomizeFuncp->fileline (), stdrand));
2620- }
2621- AstNode* const capturedTreep = withp->exprp ()->unlinkFrBackWithNext ();
2622- randomizeFuncp->addStmtsp (capturedTreep);
2623- {
2624- ConstraintExprVisitor{m_memberMap, capturedTreep, randomizeFuncp,
2625- stdrand, nullptr , m_writtenVars};
2626- }
2627- AstCExpr* const solverCallp = new AstCExpr{fl};
2628- solverCallp->dtypeSetBit ();
2629- solverCallp->add (new AstVarRef{fl, stdrand, VAccess::READWRITE});
2630- solverCallp->add (" .next()" );
2631- AstVar* const fvarp = VN_AS (randomizeFuncp->fvarp (), Var);
2632- AstVarRef* const retvalReadp = new AstVarRef{fl, fvarp, VAccess::READ};
2633- AstNodeExpr* const andExprp = new AstAnd{fl, retvalReadp, solverCallp};
2634- AstVarRef* const retvalWritep = new AstVarRef{fl, fvarp, VAccess::WRITE};
2635- randomizeFuncp->addStmtsp (new AstAssign{fl, retvalWritep, andExprp});
2636- }
2646+ if ((withp = VN_CAST (pinp, With))) break ;
2647+ }
2648+ for (const AstNode* pinp = nodep->pinsp (); pinp; pinp = pinp->nextp ()) {
2649+ const AstArg* const argp = VN_CAST (pinp, Arg);
26372650 if (!argp) continue ;
26382651 AstNodeExpr* exprp = argp->exprp ();
2639-
26402652 AstCMethodHard* const basicMethodp = new AstCMethodHard{
26412653 nodep->fileline (),
26422654 new AstVarRef{nodep->fileline (), stdrand, VAccess::READWRITE},
26432655 VCMethod::RANDOMIZER_BASIC_STD_RANDOMIZATION};
26442656 AstVar* const refvarp
26452657 = new AstVar{exprp->fileline (), VVarType::MEMBER,
26462658 " __Varg" s + std::to_string (++argn), exprp->dtypep ()};
2659+ refvarp->setStdRandomizeArg ();
2660+ // Replace argument occurrences in 'with' clause with __Varg* reference.
2661+ if (withp) {
2662+ withp->foreach ([&](AstNodeExpr* exp) {
2663+ if (isSimilarNode (exp, exprp)) {
2664+ AstVarRef* const replaceVar
2665+ = new AstVarRef{exprp->fileline (), refvarp, VAccess::READWRITE};
2666+ exp->replaceWith (replaceVar);
2667+ replaceVar->user1 (exp->user1 ());
2668+ replaceVar->varp ()->user2p (m_modp);
2669+ VL_DO_DANGLING (pushDeletep (exp), exp);
2670+ }
2671+ });
2672+ }
26472673 refvarp->direction (VDirection::REF);
26482674 refvarp->funcLocal (true );
26492675 refvarp->lifetime (VLifetime::AUTOMATIC_EXPLICIT);
@@ -2666,6 +2692,31 @@ class RandomizeVisitor final : public VNVisitor {
26662692 VN_AS (randomizeFuncp->fvarp (), Var), VAccess::READ},
26672693 basicMethodp}});
26682694 }
2695+ if (withp) {
2696+ FileLine* const fl = nodep->fileline ();
2697+ withCapturep = std::make_unique<CaptureVisitor>(withp->exprp (), m_modp, nullptr );
2698+ withCapturep->addFunctionArguments (randomizeFuncp);
2699+ // Clear old constraints and variables for std::randomize with clause
2700+ if (stdrand) {
2701+ randomizeFuncp->addStmtsp (
2702+ implementConstraintsClearAll (randomizeFuncp->fileline (), stdrand));
2703+ }
2704+ AstNode* const capturedTreep = withp->exprp ()->unlinkFrBackWithNext ();
2705+ randomizeFuncp->addStmtsp (capturedTreep);
2706+ {
2707+ ConstraintExprVisitor{m_memberMap, capturedTreep, randomizeFuncp,
2708+ stdrand, nullptr , m_writtenVars};
2709+ }
2710+ AstCExpr* const solverCallp = new AstCExpr{fl};
2711+ solverCallp->dtypeSetBit ();
2712+ solverCallp->add (new AstVarRef{fl, stdrand, VAccess::READWRITE});
2713+ solverCallp->add (" .next()" );
2714+ AstVar* const fvarp = VN_AS (randomizeFuncp->fvarp (), Var);
2715+ AstNodeExpr* const andExprp
2716+ = new AstAnd{fl, new AstVarRef{fl, fvarp, VAccess::READ}, solverCallp};
2717+ randomizeFuncp->addStmtsp (
2718+ new AstAssign{fl, new AstVarRef{fl, fvarp, VAccess::WRITE}, andExprp});
2719+ }
26692720 // Remove With nodes from pins as they have been processed
26702721 for (AstNode* pinp = nodep->pinsp (); pinp;) {
26712722 AstNode* const nextp = pinp->nextp ();
0 commit comments