diff options
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp index 417f482c1d9..a85daaa0780 100644 --- a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp +++ b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp @@ -52,6 +52,7 @@ using namespace llvm; #define DEBUG_TYPE "correlated-value-propagation" STATISTIC(NumPhis, "Number of phis propagated"); +STATISTIC(NumPhiCommon, "Number of phis deleted via common incoming value"); STATISTIC(NumSelects, "Number of selects propagated"); STATISTIC(NumMemAccess, "Number of memory access targets propagated"); STATISTIC(NumCmps, "Number of comparisons propagated"); @@ -123,6 +124,62 @@ static bool processSelect(SelectInst *S, LazyValueInfo *LVI) { return true; } +/// Try to simplify a phi with constant incoming values that match the edge +/// values of a non-constant value on all other edges: +/// bb0: +/// %isnull = icmp eq i8* %x, null +/// br i1 %isnull, label %bb2, label %bb1 +/// bb1: +/// br label %bb2 +/// bb2: +/// %r = phi i8* [ %x, %bb1 ], [ null, %bb0 ] +/// --> +/// %r = %x +static bool simplifyCommonValuePhi(PHINode *P, LazyValueInfo *LVI, + const SimplifyQuery &SQ) { + // Collect incoming constants and initialize possible common value. + SmallVector<std::pair<Constant *, unsigned>, 4> IncomingConstants; + Value *CommonValue = nullptr; + for (unsigned i = 0, e = P->getNumIncomingValues(); i != e; ++i) { + Value *Incoming = P->getIncomingValue(i); + if (auto *IncomingConstant = dyn_cast<Constant>(Incoming)) { + IncomingConstants.push_back(std::make_pair(IncomingConstant, i)); + } else if (!CommonValue) { + // The potential common value is initialized to the first non-constant. + CommonValue = Incoming; + } else if (Incoming != CommonValue) { + // There can be only one non-constant common value. + return false; + } + } + + if (!CommonValue || IncomingConstants.empty()) + return false; + + // The common value must be valid in all incoming blocks. + BasicBlock *ToBB = P->getParent(); + if (auto *CommonInst = dyn_cast<Instruction>(CommonValue)) + if (!SQ.DT->dominates(CommonInst, ToBB)) + return false; + + // We have a phi with exactly 1 variable incoming value and 1 or more constant + // incoming values. See if all constant incoming values can be mapped back to + // the same incoming variable value. + for (auto &IncomingConstant : IncomingConstants) { + Constant *C = IncomingConstant.first; + BasicBlock *IncomingBB = P->getIncomingBlock(IncomingConstant.second); + if (C != LVI->getConstantOnEdge(CommonValue, IncomingBB, ToBB, P)) + return false; + } + + // All constant incoming values map to the same variable along the incoming + // edges of the phi. The phi is unnecessary. + P->replaceAllUsesWith(CommonValue); + P->eraseFromParent(); + ++NumPhiCommon; + return true; +} + static bool processPHI(PHINode *P, LazyValueInfo *LVI, const SimplifyQuery &SQ) { bool Changed = false; @@ -184,6 +241,9 @@ static bool processPHI(PHINode *P, LazyValueInfo *LVI, Changed = true; } + if (!Changed) + Changed = simplifyCommonValuePhi(P, LVI, SQ); + if (Changed) ++NumPhis; |