6262#include " llvm/IR/Instruction.h"
6363#include " llvm/IR/Instructions.h"
6464#include " llvm/IR/IntrinsicInst.h"
65+ #include " llvm/IR/Intrinsics.h"
6566#include " llvm/IR/LLVMContext.h"
6667#include " llvm/IR/Metadata.h"
6768#include " llvm/IR/Module.h"
@@ -523,9 +524,10 @@ class Slice {
523524public:
524525 Slice () = default ;
525526
526- Slice (uint64_t BeginOffset, uint64_t EndOffset, Use *U, bool IsSplittable)
527+ Slice (uint64_t BeginOffset, uint64_t EndOffset, Use *U, bool IsSplittable,
528+ Value *ProtectedFieldDisc)
527529 : BeginOffset(BeginOffset), EndOffset(EndOffset),
528- UseAndIsSplittable (U, IsSplittable) {}
530+ UseAndIsSplittable (U, IsSplittable), ProtectedFieldDisc(ProtectedFieldDisc) {}
529531
530532 uint64_t beginOffset () const { return BeginOffset; }
531533 uint64_t endOffset () const { return EndOffset; }
@@ -538,6 +540,10 @@ class Slice {
538540 bool isDead () const { return getUse () == nullptr ; }
539541 void kill () { UseAndIsSplittable.setPointer (nullptr ); }
540542
543+ // When this access is via an llvm.protected.field.ptr intrinsic, contains
544+ // the second argument to the intrinsic, the discriminator.
545+ Value *ProtectedFieldDisc;
546+
541547 // / Support for ordering ranges.
542548 // /
543549 // / This provides an ordering over ranges such that start offsets are
@@ -631,6 +637,9 @@ class AllocaSlices {
631637 // / Access the dead users for this alloca.
632638 ArrayRef<Instruction *> getDeadUsers () const { return DeadUsers; }
633639
640+ // / Access the PFP users for this alloca.
641+ ArrayRef<IntrinsicInst *> getPFPUsers () const { return PFPUsers; }
642+
634643 // / Access Uses that should be dropped if the alloca is promotable.
635644 ArrayRef<Use *> getDeadUsesIfPromotable () const {
636645 return DeadUseIfPromotable;
@@ -691,6 +700,10 @@ class AllocaSlices {
691700 // / they come from outside of the allocated space.
692701 SmallVector<Instruction *, 8 > DeadUsers;
693702
703+ // / Users that are llvm.protected.field.ptr intrinsics. These will be RAUW'd
704+ // / to their first argument if we rewrite the alloca.
705+ SmallVector<IntrinsicInst *, 0 > PFPUsers;
706+
694707 // / Uses which will become dead if can promote the alloca.
695708 SmallVector<Use *, 8 > DeadUseIfPromotable;
696709
@@ -1064,7 +1077,8 @@ class AllocaSlices::SliceBuilder : public PtrUseVisitor<SliceBuilder> {
10641077 EndOffset = AllocSize;
10651078 }
10661079
1067- AS.Slices .push_back (Slice (BeginOffset, EndOffset, U, IsSplittable));
1080+ AS.Slices .push_back (
1081+ Slice (BeginOffset, EndOffset, U, IsSplittable, ProtectedFieldDisc));
10681082 }
10691083
10701084 void visitBitCastInst (BitCastInst &BC) {
@@ -1274,6 +1288,9 @@ class AllocaSlices::SliceBuilder : public PtrUseVisitor<SliceBuilder> {
12741288 return ;
12751289 }
12761290
1291+ if (II.getIntrinsicID () == Intrinsic::protected_field_ptr)
1292+ AS.PFPUsers .push_back (&II);
1293+
12771294 Base::visitIntrinsicInst (II);
12781295 }
12791296
@@ -4682,7 +4699,7 @@ bool SROA::presplitLoadsAndStores(AllocaInst &AI, AllocaSlices &AS) {
46824699 NewSlices.push_back (
46834700 Slice (BaseOffset + PartOffset, BaseOffset + PartOffset + PartSize,
46844701 &PLoad->getOperandUse (PLoad->getPointerOperandIndex ()),
4685- /* IsSplittable*/ false ));
4702+ /* IsSplittable*/ false , nullptr ));
46864703 LLVM_DEBUG (dbgs () << " new slice [" << NewSlices.back ().beginOffset ()
46874704 << " , " << NewSlices.back ().endOffset ()
46884705 << " ): " << *PLoad << " \n " );
@@ -4838,10 +4855,12 @@ bool SROA::presplitLoadsAndStores(AllocaInst &AI, AllocaSlices &AS) {
48384855 LLVMContext::MD_access_group});
48394856
48404857 // Now build a new slice for the alloca.
4858+ // ProtectedFieldDisc==nullptr is a lie, but it doesn't matter because we
4859+ // already determined that all accesses are consistent.
48414860 NewSlices.push_back (
48424861 Slice (BaseOffset + PartOffset, BaseOffset + PartOffset + PartSize,
48434862 &PStore->getOperandUse (PStore->getPointerOperandIndex ()),
4844- /* IsSplittable*/ false ));
4863+ /* IsSplittable*/ false , nullptr ));
48454864 LLVM_DEBUG (dbgs () << " new slice [" << NewSlices.back ().beginOffset ()
48464865 << " , " << NewSlices.back ().endOffset ()
48474866 << " ): " << *PStore << " \n " );
@@ -5618,6 +5637,32 @@ SROA::runOnAlloca(AllocaInst &AI) {
56185637 return {Changed, CFGChanged};
56195638 }
56205639
5640+ for (auto &P : AS.partitions ()) {
5641+ std::optional<Value *> ProtectedFieldDisc;
5642+ // For now, we can't split if a field is accessed both via protected
5643+ // field and not.
5644+ for (Slice &S : P) {
5645+ if (auto *II = dyn_cast<IntrinsicInst>(S.getUse ()->getUser ()))
5646+ if (II->getIntrinsicID () == Intrinsic::lifetime_start ||
5647+ II->getIntrinsicID () == Intrinsic::lifetime_end)
5648+ continue ;
5649+ if (!ProtectedFieldDisc)
5650+ ProtectedFieldDisc = S.ProtectedFieldDisc ;
5651+ if (*ProtectedFieldDisc != S.ProtectedFieldDisc )
5652+ return {Changed, CFGChanged};
5653+ }
5654+ for (Slice *S : P.splitSliceTails ()) {
5655+ if (auto *II = dyn_cast<IntrinsicInst>(S->getUse ()->getUser ()))
5656+ if (II->getIntrinsicID () == Intrinsic::lifetime_start ||
5657+ II->getIntrinsicID () == Intrinsic::lifetime_end)
5658+ continue ;
5659+ if (!ProtectedFieldDisc)
5660+ ProtectedFieldDisc = S->ProtectedFieldDisc ;
5661+ if (*ProtectedFieldDisc != S->ProtectedFieldDisc )
5662+ return {Changed, CFGChanged};
5663+ }
5664+ }
5665+
56215666 // Delete all the dead users of this alloca before splitting and rewriting it.
56225667 for (Instruction *DeadUser : AS.getDeadUsers ()) {
56235668 // Free up everything used by this instruction.
@@ -5635,6 +5680,12 @@ SROA::runOnAlloca(AllocaInst &AI) {
56355680 clobberUse (*DeadOp);
56365681 Changed = true ;
56375682 }
5683+ for (IntrinsicInst *PFPUser : AS.getPFPUsers ()) {
5684+ PFPUser->replaceAllUsesWith (PFPUser->getArgOperand (0 ));
5685+
5686+ DeadInsts.push_back (PFPUser);
5687+ Changed = true ;
5688+ }
56385689
56395690 // No slices to split. Leave the dead alloca for a later pass to clean up.
56405691 if (AS.begin () == AS.end ())
0 commit comments