@@ -529,9 +529,21 @@ void copyByValParam(Function &F, Argument &Arg) {
529529 // the use of the byval parameter with this alloca instruction.
530530 AllocA->setAlignment (
531531 Arg.getParamAlign ().value_or (DL.getPrefTypeAlign (StructType)));
532- Arg.replaceAllUsesWith (AllocA);
533532
533+ // CRITICAL: Must create ArgInParam BEFORE replaceAllUsesWith.
534+ // createNVVMInternalAddrspaceWrap needs to use Arg as an operand, but
535+ // replaceAllUsesWith(AllocA) would replace ALL uses of Arg (including the
536+ // use we're about to create), leading to a circular dependency and crash.
534537 CallInst *ArgInParam = createNVVMInternalAddrspaceWrap (IRB, Arg);
538+ assert (ArgInParam->getArgOperand (0 ) == &Arg &&
539+ " ArgInParam must use original Arg before replacement" );
540+
541+ Arg.replaceAllUsesWith (AllocA);
542+
543+ // Verify ArgInParam still has Arg as operand after replacement (it should,
544+ // because replaceAllUsesWith skips the value being replaced itself)
545+ assert (ArgInParam->getArgOperand (0 ) == &Arg &&
546+ " ArgInParam must still use original Arg after replaceAllUsesWith" );
535547
536548 // Be sure to propagate alignment to this load; LLVM doesn't know that NVPTX
537549 // addrspacecast preserves alignment. Since params are constant, this load
@@ -599,10 +611,14 @@ static void handleByValParam(const NVPTXTargetMachine &TM, Argument *Arg) {
599611 ParamSpaceArg, IRB.getPtrTy (ADDRESS_SPACE_GENERIC),
600612 Arg->getName () + " .gen" );
601613
602- Arg->replaceAllUsesWith (GenericArg);
603-
604- // Do not replace Arg in the cast to param space
605- ParamSpaceArg->setOperand (0 , Arg);
614+ // Collect all uses of Arg except the one in ParamSpaceArg, then replace them
615+ SmallVector<Use *> UsesToReplace;
616+ for (Use &U : Arg->uses ()) {
617+ if (U.getUser () != ParamSpaceArg)
618+ UsesToReplace.push_back (&U);
619+ }
620+ for (Use *U : UsesToReplace)
621+ U->set (GenericArg);
606622 } else
607623 copyByValParam (*Func, *Arg);
608624}
0 commit comments