Skip to content

Commit

Permalink
[InstCombine] Fold PHIs with equal incoming pointers
Browse files Browse the repository at this point in the history
In case when all incoming values of a PHI are equal pointers, this
transformation inserts a definition of such a pointer right after
definition of the base pointer and replaces with this value both PHI and
all it's incoming pointers. Primary goal of this transformation is
canonicalization of this pattern in order to enable optimizations that
can't handle PHIs. Non-inbounds pointers aren't currently supported.

Reviewers: spatel, RKSimon, lebedev.ri, apilipenko

Reviewed By: apilipenko

Tags: #llvm

Subscribers: hiraditya, llvm-commits

Differential Revision: https://reviews.llvm.org/D68128
  • Loading branch information
Daniil Suchkov authored and DaniilSuchkov committed Nov 13, 2019
1 parent 9a1c243 commit bbb2973
Show file tree
Hide file tree
Showing 3 changed files with 360 additions and 136 deletions.
5 changes: 5 additions & 0 deletions llvm/lib/Transforms/InstCombine/InstCombineInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -895,6 +895,11 @@ class LLVM_LIBRARY_VISIBILITY InstCombiner
/// 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);
Expand Down
60 changes: 60 additions & 0 deletions llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1122,6 +1122,63 @@ 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())
replaceInstUsesWith(*cast<Instruction>(Incoming), GEPTyped);
return replaceInstUsesWith(PN, GEPTyped);
}

// PHINode simplification
//
Instruction *InstCombiner::visitPHINode(PHINode &PN) {
Expand All @@ -1143,6 +1200,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.
Expand Down
Loading

0 comments on commit bbb2973

Please sign in to comment.