summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp')
-rw-r--r--llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp60
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;
OpenPOWER on IntegriCloud