summaryrefslogtreecommitdiffstats
path: root/llvm/lib
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib')
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombineInternal.h5
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp65
2 files changed, 70 insertions, 0 deletions
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
index 524f9313d8c..52aeb787aaf 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
+++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
@@ -895,6 +895,11 @@ private:
/// insert a new pointer typed PHI and replace the original one.
Instruction *FoldIntegerTypedPHI(PHINode &PN);
+ /// If all incoming values of a pointer typed PHI are pointers with the same
+ /// base and offset, replace the PHI and all incoming values with one
+ /// definition of such pointer.
+ Instruction *FoldPHIWithEqualPointers(PHINode &PN);
+
/// Helper function for FoldPHIArgXIntoPHI() to set debug location for the
/// folded operation.
void PHIArgMergedDebugLoc(Instruction *Inst, PHINode &PN);
diff --git a/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp b/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp
index e0376b7582f..d1035414560 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp
@@ -1122,6 +1122,68 @@ Instruction *InstCombiner::SliceUpIllegalIntegerPHI(PHINode &FirstPhi) {
return replaceInstUsesWith(FirstPhi, Undef);
}
+Instruction *InstCombiner::FoldPHIWithEqualPointers(PHINode &PN) {
+ auto *PhiTy = dyn_cast<PointerType>(PN.getType());
+ if (!PhiTy)
+ return nullptr;
+
+ // Make sure all incoming pointers have the same base pointers and offsets.
+ // Also, make sure no addrspacecasts involved.
+ // Note: only inbounds GEPs are supported!
+ const DataLayout &DL = PN.getModule()->getDataLayout();
+ Value *FirstValue = PN.getIncomingValue(0);
+ int64_t Offset;
+ Value *Base = GetPointerBaseWithConstantOffset(
+ FirstValue, Offset, DL, /* AllowNonInbounds */ false);
+
+ auto *BaseTy = cast<PointerType>(Base->getType());
+ if (BaseTy->getAddressSpace() != PhiTy->getAddressSpace())
+ return nullptr;
+
+ for (Use &Incoming : PN.incoming_values()) {
+ if (!isa<Instruction>(Incoming))
+ return nullptr;
+ int64_t CurrentOffset;
+ Value *CurrentBase = GetPointerBaseWithConstantOffset(
+ Incoming, CurrentOffset, DL, /* AllowNonInbounds */ false);
+ if (CurrentBase != Base || CurrentOffset != Offset)
+ return nullptr;
+ }
+
+ Instruction *InsertPt = nullptr;
+ if (auto *BaseInst = dyn_cast<Instruction>(Base)) {
+ if (isa<PHINode>(BaseInst)) {
+ BasicBlock *InsertBB = BaseInst->getParent();
+ BasicBlock::iterator InsertPtIter = InsertBB->getFirstInsertionPt();
+ // Make sure the insertion point exists. At the moment the only reason why
+ // insertion point may not exist is EHPad being a terminator. This check
+ // is a bit more future-proof than just `if (!TI->isEHPad())`.
+ if (InsertPtIter != InsertBB->end())
+ InsertPt = &*InsertPtIter;
+ } else
+ InsertPt = BaseInst->getNextNode();
+ } else
+ InsertPt = &*PN.getFunction()->getEntryBlock().getFirstInsertionPt();
+
+ if (!InsertPt)
+ return nullptr;
+
+ Builder.SetInsertPoint(InsertPt);
+ Type *I8PtrTy = Builder.getInt8PtrTy(PhiTy->getAddressSpace());
+ Value *BaseI8Ptr = Builder.CreateBitCast(Base, I8PtrTy);
+ Value *GEP = Builder.CreateConstInBoundsGEP1_64(BaseI8Ptr, Offset);
+ Value *GEPTyped = Builder.CreateBitCast(GEP, PhiTy);
+
+ for (Use &Incoming : PN.incoming_values()) {
+ auto *IncomingInst = cast<Instruction>(Incoming);
+ // If we haven't already replaced this instruction.
+ if (IncomingInst != GEPTyped)
+ replaceInstUsesWith(*IncomingInst, GEPTyped);
+ }
+
+ return replaceInstUsesWith(PN, GEPTyped);
+}
+
// PHINode simplification
//
Instruction *InstCombiner::visitPHINode(PHINode &PN) {
@@ -1143,6 +1205,9 @@ Instruction *InstCombiner::visitPHINode(PHINode &PN) {
if (Instruction *Result = FoldPHIArgOpIntoPHI(PN))
return Result;
+ if (Instruction *Result = FoldPHIWithEqualPointers(PN))
+ return Result;
+
// If this is a trivial cycle in the PHI node graph, remove it. Basically, if
// this PHI only has a single use (a PHI), and if that PHI only has one use (a
// PHI)... break the cycle.
OpenPOWER on IntegriCloud