@@ -206,6 +206,12 @@ class InferAddressSpacesImpl {
206206
207207 bool isSafeToCastConstAddrSpace (Constant *C, unsigned NewAS) const ;
208208
209+ Value *clonePtrMaskWithNewAddressSpace (
210+ IntrinsicInst *I, unsigned NewAddrSpace,
211+ const ValueToValueMapTy &ValueWithNewAddrSpace,
212+ const PredicatedAddrSpaceMapTy &PredicatedAS,
213+ SmallVectorImpl<const Use *> *PoisonUsesToFix) const ;
214+
209215 Value *cloneInstructionWithNewAddressSpace (
210216 Instruction *I, unsigned NewAddrSpace,
211217 const ValueToValueMapTy &ValueWithNewAddrSpace,
@@ -651,6 +657,69 @@ static Value *operandWithNewAddressSpaceOrCreatePoison(
651657 return PoisonValue::get (NewPtrTy);
652658}
653659
660+ // A helper function for cloneInstructionWithNewAddressSpace. Handles the
661+ // conversion of a ptrmask intrinsic instruction.
662+ Value *InferAddressSpacesImpl::clonePtrMaskWithNewAddressSpace (
663+ IntrinsicInst *I, unsigned NewAddrSpace,
664+ const ValueToValueMapTy &ValueWithNewAddrSpace,
665+ const PredicatedAddrSpaceMapTy &PredicatedAS,
666+ SmallVectorImpl<const Use *> *PoisonUsesToFix) const {
667+ const Use &PtrOpUse = I->getArgOperandUse (0 );
668+ unsigned OldAddrSpace = PtrOpUse->getType ()->getPointerAddressSpace ();
669+ Value *MaskOp = I->getArgOperand (1 );
670+ Type *MaskTy = MaskOp->getType ();
671+
672+ std::optional<KnownBits> OldPtrBits;
673+ std::optional<KnownBits> NewPtrBits;
674+ if (!TTI->isNoopAddrSpaceCast (OldAddrSpace, NewAddrSpace)) {
675+ if (std::optional<std::pair<KnownBits, KnownBits>> KB =
676+ TTI->computeKnownBitsAddrSpaceCast (NewAddrSpace, *PtrOpUse.get ())) {
677+ OldPtrBits = KB->first ;
678+ NewPtrBits = KB->second ;
679+ }
680+ }
681+
682+ // If the pointers in both addrspaces have a bitwise representation and if the
683+ // representation of the new pointer is smaller (fewer bits) than the old one,
684+ // check if the mask is applicable to the ptr in the new addrspace. Any
685+ // masking only clearing the low bits will also apply in the new addrspace
686+ // Note: checking if the mask clears high bits is not sufficient as those
687+ // might have already been 0 in the old ptr.
688+ if (NewPtrBits && OldPtrBits->getBitWidth () > NewPtrBits->getBitWidth ()) {
689+ KnownBits MaskBits =
690+ computeKnownBits (MaskOp, *DL, /* AssumptionCache=*/ nullptr , I);
691+ // Set all unknown bits of the old ptr to 1, so that we are conservative in
692+ // checking which bits are cleared by the mask.
693+ OldPtrBits->One |= ~OldPtrBits->Zero ;
694+ // Check which bits are cleared by the mask in the old ptr.
695+ KnownBits ClearedBits = KnownBits::sub (*OldPtrBits, *OldPtrBits & MaskBits);
696+
697+ // If the mask isn't applicable to the new ptr, leave the ptrmask as-is and
698+ // insert an addrspacecast after it.
699+ if (ClearedBits.countMaxActiveBits () > NewPtrBits->countMaxActiveBits ()) {
700+ std::optional<BasicBlock::iterator> InsertPoint =
701+ I->getInsertionPointAfterDef ();
702+ assert (InsertPoint && " insertion after ptrmask should be possible" );
703+ Type *NewPtrType = getPtrOrVecOfPtrsWithNewAS (I->getType (), NewAddrSpace);
704+ Instruction *AddrSpaceCast =
705+ new AddrSpaceCastInst (I, NewPtrType, " " , *InsertPoint);
706+ AddrSpaceCast->setDebugLoc (I->getDebugLoc ());
707+ return AddrSpaceCast;
708+ }
709+ }
710+
711+ IRBuilder<> B (I);
712+ if (NewPtrBits) {
713+ MaskTy = MaskTy->getWithNewBitWidth (NewPtrBits->getBitWidth ());
714+ MaskOp = B.CreateTrunc (MaskOp, MaskTy);
715+ }
716+ Value *NewPtr = operandWithNewAddressSpaceOrCreatePoison (
717+ PtrOpUse, NewAddrSpace, ValueWithNewAddrSpace, PredicatedAS,
718+ PoisonUsesToFix);
719+ return B.CreateIntrinsic (Intrinsic::ptrmask, {NewPtr->getType (), MaskTy},
720+ {NewPtr, MaskOp});
721+ }
722+
654723// Returns a clone of `I` with its operands converted to those specified in
655724// ValueWithNewAddrSpace. Due to potential cycles in the data flow graph, an
656725// operand whose address space needs to be modified might not exist in
@@ -660,9 +729,6 @@ static Value *operandWithNewAddressSpaceOrCreatePoison(
660729// Note that we do not necessarily clone `I`, e.g., if it is an addrspacecast
661730// from a pointer whose type already matches. Therefore, this function returns a
662731// Value* instead of an Instruction*.
663- //
664- // This may also return nullptr in the case the instruction could not be
665- // rewritten.
666732Value *InferAddressSpacesImpl::cloneInstructionWithNewAddressSpace (
667733 Instruction *I, unsigned NewAddrSpace,
668734 const ValueToValueMapTy &ValueWithNewAddrSpace,
@@ -683,17 +749,8 @@ Value *InferAddressSpacesImpl::cloneInstructionWithNewAddressSpace(
683749 // Technically the intrinsic ID is a pointer typed argument, so specially
684750 // handle calls early.
685751 assert (II->getIntrinsicID () == Intrinsic::ptrmask);
686- Value *NewPtr = operandWithNewAddressSpaceOrCreatePoison (
687- II->getArgOperandUse (0 ), NewAddrSpace, ValueWithNewAddrSpace,
688- PredicatedAS, PoisonUsesToFix);
689- Value *Rewrite =
690- TTI->rewriteIntrinsicWithAddressSpace (II, II->getArgOperand (0 ), NewPtr);
691- if (Rewrite) {
692- assert (Rewrite != II && " cannot modify this pointer operation in place" );
693- return Rewrite;
694- }
695-
696- return nullptr ;
752+ return clonePtrMaskWithNewAddressSpace (
753+ II, NewAddrSpace, ValueWithNewAddrSpace, PredicatedAS, PoisonUsesToFix);
697754 }
698755
699756 unsigned AS = TTI->getAssumedAddrSpace (I);
@@ -1331,7 +1388,10 @@ bool InferAddressSpacesImpl::rewriteWithNewAddressSpaces(
13311388
13321389 unsigned OperandNo = PoisonUse->getOperandNo ();
13331390 assert (isa<PoisonValue>(NewV->getOperand (OperandNo)));
1334- NewV->setOperand (OperandNo, ValueWithNewAddrSpace.lookup (PoisonUse->get ()));
1391+ WeakTrackingVH NewOp = ValueWithNewAddrSpace.lookup (PoisonUse->get ());
1392+ assert (NewOp &&
1393+ " poison replacements in ValueWithNewAddrSpace shouldn't be null" );
1394+ NewV->setOperand (OperandNo, NewOp);
13351395 }
13361396
13371397 SmallVector<Instruction *, 16 > DeadInstructions;
0 commit comments