43
43
#include " llvm/Analysis/GlobalsModRef.h"
44
44
#include " llvm/Analysis/Loads.h"
45
45
#include " llvm/Analysis/PtrUseVisitor.h"
46
+ #include " llvm/Analysis/ValueTracking.h"
46
47
#include " llvm/Config/llvm-config.h"
47
48
#include " llvm/IR/BasicBlock.h"
48
49
#include " llvm/IR/Constant.h"
83
84
#include " llvm/Transforms/Utils/BasicBlockUtils.h"
84
85
#include " llvm/Transforms/Utils/Local.h"
85
86
#include " llvm/Transforms/Utils/PromoteMemToReg.h"
87
+ #include " llvm/Transforms/Utils/SSAUpdater.h"
86
88
#include < algorithm>
87
89
#include < cassert>
88
90
#include < cstddef>
@@ -246,6 +248,7 @@ class SROA {
246
248
bool presplitLoadsAndStores (AllocaInst &AI, AllocaSlices &AS);
247
249
AllocaInst *rewritePartition (AllocaInst &AI, AllocaSlices &AS, Partition &P);
248
250
bool splitAlloca (AllocaInst &AI, AllocaSlices &AS);
251
+ bool propagateStoredValuesToLoads (AllocaInst &AI, AllocaSlices &AS);
249
252
std::pair<bool /* Changed*/ , bool /* CFGChanged*/ > runOnAlloca (AllocaInst &AI);
250
253
void clobberUse (Use &U);
251
254
bool deleteDeadInstructions (SmallPtrSetImpl<AllocaInst *> &DeletedAllocas);
@@ -598,6 +601,7 @@ class AllocaSlices {
598
601
// / If this is true, the slices are never fully built and should be
599
602
// / ignored.
600
603
bool isEscaped () const { return PointerEscapingInstr; }
604
+ bool isEscapedReadOnly () const { return PointerEscapingInstrReadOnly; }
601
605
602
606
// / Support for iterating over the slices.
603
607
// / @{
@@ -680,6 +684,7 @@ class AllocaSlices {
680
684
// / store a pointer to that here and abort trying to form slices of the
681
685
// / alloca. This will be null if the alloca slices are analyzed successfully.
682
686
Instruction *PointerEscapingInstr;
687
+ Instruction *PointerEscapingInstrReadOnly;
683
688
684
689
// / The slices of the alloca.
685
690
// /
@@ -1390,14 +1395,26 @@ class AllocaSlices::SliceBuilder : public PtrUseVisitor<SliceBuilder> {
1390
1395
1391
1396
// / Disable SROA entirely if there are unhandled users of the alloca.
1392
1397
void visitInstruction (Instruction &I) { PI.setAborted (&I); }
1398
+
1399
+ void visitCallBase (CallBase &CB) {
1400
+ // If the call operand is NoCapture ReadOnly, then we mark it as
1401
+ // EscapedReadOnly.
1402
+ if (CB.doesNotCapture (U->getOperandNo ()) &&
1403
+ CB.onlyReadsMemory (U->getOperandNo ())) {
1404
+ PI.setEscapedReadOnly (&CB);
1405
+ return ;
1406
+ }
1407
+
1408
+ Base::visitCallBase (CB);
1409
+ }
1393
1410
};
1394
1411
1395
1412
AllocaSlices::AllocaSlices (const DataLayout &DL, AllocaInst &AI)
1396
1413
:
1397
1414
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1398
1415
AI (AI),
1399
1416
#endif
1400
- PointerEscapingInstr (nullptr ) {
1417
+ PointerEscapingInstr (nullptr ), PointerEscapingInstrReadOnly( nullptr ) {
1401
1418
SliceBuilder PB (DL, AI, *this );
1402
1419
SliceBuilder::PtrInfo PtrI = PB.visitPtr (AI);
1403
1420
if (PtrI.isEscaped () || PtrI.isAborted ()) {
@@ -1408,6 +1425,7 @@ AllocaSlices::AllocaSlices(const DataLayout &DL, AllocaInst &AI)
1408
1425
assert (PointerEscapingInstr && " Did not track a bad instruction" );
1409
1426
return ;
1410
1427
}
1428
+ PointerEscapingInstrReadOnly = PtrI.getEscapedReadOnlyInst ();
1411
1429
1412
1430
llvm::erase_if (Slices, [](const Slice &S) { return S.isDead (); });
1413
1431
@@ -1445,6 +1463,9 @@ void AllocaSlices::print(raw_ostream &OS) const {
1445
1463
return ;
1446
1464
}
1447
1465
1466
+ if (PointerEscapingInstrReadOnly)
1467
+ OS << " Escapes into ReadOnly: " << *PointerEscapingInstrReadOnly << " \n " ;
1468
+
1448
1469
OS << " Slices of alloca: " << AI << " \n " ;
1449
1470
for (const_iterator I = begin (), E = end (); I != E; ++I)
1450
1471
print (OS, I);
@@ -5454,6 +5475,88 @@ void SROA::clobberUse(Use &U) {
5454
5475
}
5455
5476
}
5456
5477
5478
+ // / A basic LoadAndStorePromoter that does not remove store nodes.
5479
+ class BasicLoadAndStorePromoter : public LoadAndStorePromoter {
5480
+ public:
5481
+ BasicLoadAndStorePromoter (ArrayRef<const Instruction *> Insts, SSAUpdater &S,
5482
+ Type *ZeroType)
5483
+ : LoadAndStorePromoter(Insts, S), ZeroType(ZeroType) {}
5484
+ bool shouldDelete (Instruction *I) const override {
5485
+ return !isa<StoreInst>(I) && !isa<AllocaInst>(I);
5486
+ }
5487
+
5488
+ Value *getValueToUseForAlloca (Instruction *I) const override {
5489
+ return UndefValue::get (ZeroType);
5490
+ }
5491
+
5492
+ private:
5493
+ Type *ZeroType;
5494
+ };
5495
+
5496
+ bool SROA::propagateStoredValuesToLoads (AllocaInst &AI, AllocaSlices &AS) {
5497
+ // Look through each "partition", looking for slices with the same start/end
5498
+ // that do not overlap with any before them. The slices are sorted by
5499
+ // increasing beginOffset. We don't use AS.partitions(), as it will use a more
5500
+ // sophisticated algorithm that takes splittable slices into account.
5501
+ auto PartitionBegin = AS.begin ();
5502
+ auto PartitionEnd = PartitionBegin;
5503
+ uint64_t BeginOffset = PartitionBegin->beginOffset ();
5504
+ uint64_t EndOffset = PartitionBegin->endOffset ();
5505
+ while (PartitionBegin != AS.end ()) {
5506
+ bool AllSameAndValid = true ;
5507
+ SmallVector<Instruction *> Insts;
5508
+ Type *PartitionType = nullptr ;
5509
+ while (PartitionEnd != AS.end () &&
5510
+ (PartitionEnd->beginOffset () < EndOffset ||
5511
+ PartitionEnd->endOffset () <= EndOffset)) {
5512
+ if (AllSameAndValid) {
5513
+ AllSameAndValid &= PartitionEnd->beginOffset () == BeginOffset &&
5514
+ PartitionEnd->endOffset () == EndOffset;
5515
+ Instruction *User =
5516
+ cast<Instruction>(PartitionEnd->getUse ()->getUser ());
5517
+ if (auto *LI = dyn_cast<LoadInst>(User)) {
5518
+ Type *UserTy = LI->getType ();
5519
+ // LoadAndStorePromoter requires all the types to be the same.
5520
+ if (!LI->isSimple () || (PartitionType && UserTy != PartitionType))
5521
+ AllSameAndValid = false ;
5522
+ PartitionType = UserTy;
5523
+ Insts.push_back (User);
5524
+ } else if (auto *SI = dyn_cast<StoreInst>(User)) {
5525
+ Type *UserTy = SI->getValueOperand ()->getType ();
5526
+ if (!SI->isSimple () || (PartitionType && UserTy != PartitionType))
5527
+ AllSameAndValid = false ;
5528
+ PartitionType = UserTy;
5529
+ Insts.push_back (User);
5530
+ } else if (!isAssumeLikeIntrinsic (User)) {
5531
+ AllSameAndValid = false ;
5532
+ }
5533
+ }
5534
+ EndOffset = std::max (EndOffset, PartitionEnd->endOffset ());
5535
+ ++PartitionEnd;
5536
+ }
5537
+
5538
+ // So long as all the slices start and end offsets matched, update loads to
5539
+ // the values stored in the partition.
5540
+ if (AllSameAndValid && !Insts.empty ()) {
5541
+ LLVM_DEBUG (dbgs () << " Propagate values on slice [" << BeginOffset << " , "
5542
+ << EndOffset << " )\n " );
5543
+ SmallVector<PHINode *, 4 > NewPHIs;
5544
+ SSAUpdater SSA (&NewPHIs);
5545
+ Insts.push_back (&AI);
5546
+ BasicLoadAndStorePromoter Promoter (Insts, SSA, PartitionType);
5547
+ Promoter.run (Insts);
5548
+ }
5549
+
5550
+ // Step on to the next partition.
5551
+ PartitionBegin = PartitionEnd;
5552
+ if (PartitionBegin == AS.end ())
5553
+ break ;
5554
+ BeginOffset = PartitionBegin->beginOffset ();
5555
+ EndOffset = PartitionBegin->endOffset ();
5556
+ }
5557
+ return true ;
5558
+ }
5559
+
5457
5560
// / Analyze an alloca for SROA.
5458
5561
// /
5459
5562
// / This analyzes the alloca to ensure we can reason about it, builds
@@ -5494,6 +5597,11 @@ SROA::runOnAlloca(AllocaInst &AI) {
5494
5597
if (AS.isEscaped ())
5495
5598
return {Changed, CFGChanged};
5496
5599
5600
+ if (AS.isEscapedReadOnly ()) {
5601
+ Changed |= propagateStoredValuesToLoads (AI, AS);
5602
+ return {Changed, CFGChanged};
5603
+ }
5604
+
5497
5605
// Delete all the dead users of this alloca before splitting and rewriting it.
5498
5606
for (Instruction *DeadUser : AS.getDeadUsers ()) {
5499
5607
// Free up everything used by this instruction.
0 commit comments