summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorian Hahn <florian.hahn@arm.com>2018-08-23 11:04:00 +0000
committerFlorian Hahn <florian.hahn@arm.com>2018-08-23 11:04:00 +0000
commit3052290dc04e9c876ce47b469f276134c3d25242 (patch)
tree098ea903471944ec7e7b7e1d30ebc5a9c40f8a91
parent9f356ddec88e0e49804e14ff2fafcf125da17481 (diff)
downloadbcm5719-llvm-3052290dc04e9c876ce47b469f276134c3d25242.tar.gz
bcm5719-llvm-3052290dc04e9c876ce47b469f276134c3d25242.zip
Recommit r333268: [IPSCCP] Use PredicateInfo to propagate facts from cmp instructions.
This version of the patch fixes cleaning up ssa_copy intrinsics, so it does not crash for instructions in blocks that have been marked unreachable. This patch updates IPSCCP to use PredicateInfo to propagate facts to true branches predicated by EQ and to false branches predicated by NE. As a follow up, we should be able to extend it to also propagate additional facts about nonnull. Reviewers: davide, mssimpso, dberlin, efriedma Reviewed By: davide, dberlin Differential Revision: https://reviews.llvm.org/D45330 llvm-svn: 340525
-rw-r--r--llvm/include/llvm/Transforms/Scalar/SCCP.h6
-rw-r--r--llvm/lib/Transforms/IPO/SCCP.cpp24
-rw-r--r--llvm/lib/Transforms/Scalar/SCCP.cpp123
-rw-r--r--llvm/test/Other/new-pm-lto-defaults.ll4
-rw-r--r--llvm/test/Other/opt-O2-pipeline.ll4
-rw-r--r--llvm/test/Other/opt-O3-pipeline.ll4
-rw-r--r--llvm/test/Other/opt-Os-pipeline.ll4
-rw-r--r--llvm/test/Transforms/IPConstantProp/musttail-call.ll4
8 files changed, 158 insertions, 15 deletions
diff --git a/llvm/include/llvm/Transforms/Scalar/SCCP.h b/llvm/include/llvm/Transforms/Scalar/SCCP.h
index 2a294c95a17..e434d41d034 100644
--- a/llvm/include/llvm/Transforms/Scalar/SCCP.h
+++ b/llvm/include/llvm/Transforms/Scalar/SCCP.h
@@ -21,11 +21,13 @@
#ifndef LLVM_TRANSFORMS_SCALAR_SCCP_H
#define LLVM_TRANSFORMS_SCALAR_SCCP_H
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/PassManager.h"
+#include "llvm/Transforms/Utils/PredicateInfo.h"
namespace llvm {
@@ -37,7 +39,9 @@ public:
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
};
-bool runIPSCCP(Module &M, const DataLayout &DL, const TargetLibraryInfo *TLI);
+bool runIPSCCP(
+ Module &M, const DataLayout &DL, const TargetLibraryInfo *TLI,
+ function_ref<std::unique_ptr<PredicateInfo>(Function &)> getPredicateInfo);
} // end namespace llvm
#endif // LLVM_TRANSFORMS_SCALAR_SCCP_H
diff --git a/llvm/lib/Transforms/IPO/SCCP.cpp b/llvm/lib/Transforms/IPO/SCCP.cpp
index cc53c4b8c46..e2bb6f185c3 100644
--- a/llvm/lib/Transforms/IPO/SCCP.cpp
+++ b/llvm/lib/Transforms/IPO/SCCP.cpp
@@ -1,4 +1,5 @@
#include "llvm/Transforms/IPO/SCCP.h"
+#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/Scalar/SCCP.h"
@@ -8,7 +9,15 @@ using namespace llvm;
PreservedAnalyses IPSCCPPass::run(Module &M, ModuleAnalysisManager &AM) {
const DataLayout &DL = M.getDataLayout();
auto &TLI = AM.getResult<TargetLibraryAnalysis>(M);
- if (!runIPSCCP(M, DL, &TLI))
+ auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
+ auto getPredicateInfo =
+ [&FAM](Function &F) -> std::unique_ptr<PredicateInfo> {
+ return make_unique<PredicateInfo>(F,
+ FAM.getResult<DominatorTreeAnalysis>(F),
+ FAM.getResult<AssumptionAnalysis>(F));
+ };
+
+ if (!runIPSCCP(M, DL, &TLI, getPredicateInfo))
return PreservedAnalyses::all();
return PreservedAnalyses::none();
}
@@ -34,10 +43,20 @@ public:
const DataLayout &DL = M.getDataLayout();
const TargetLibraryInfo *TLI =
&getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
- return runIPSCCP(M, DL, TLI);
+
+ auto getPredicateInfo =
+ [this](Function &F) -> std::unique_ptr<PredicateInfo> {
+ return make_unique<PredicateInfo>(
+ F, this->getAnalysis<DominatorTreeWrapperPass>(F).getDomTree(),
+ this->getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F));
+ };
+
+ return runIPSCCP(M, DL, TLI, getPredicateInfo);
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
+ AU.addRequired<AssumptionCacheTracker>();
+ AU.addRequired<DominatorTreeWrapperPass>();
AU.addRequired<TargetLibraryInfoWrapperPass>();
}
};
@@ -49,6 +68,7 @@ char IPSCCPLegacyPass::ID = 0;
INITIALIZE_PASS_BEGIN(IPSCCPLegacyPass, "ipsccp",
"Interprocedural Sparse Conditional Constant Propagation",
false, false)
+INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
INITIALIZE_PASS_END(IPSCCPLegacyPass, "ipsccp",
"Interprocedural Sparse Conditional Constant Propagation",
diff --git a/llvm/lib/Transforms/Scalar/SCCP.cpp b/llvm/lib/Transforms/Scalar/SCCP.cpp
index 5e3ddeda2d4..429b9802ecb 100644
--- a/llvm/lib/Transforms/Scalar/SCCP.cpp
+++ b/llvm/lib/Transforms/Scalar/SCCP.cpp
@@ -55,6 +55,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Scalar.h"
+#include "llvm/Transforms/Utils/PredicateInfo.h"
#include <cassert>
#include <utility>
#include <vector>
@@ -246,7 +247,21 @@ class SCCPSolver : public InstVisitor<SCCPSolver> {
using Edge = std::pair<BasicBlock *, BasicBlock *>;
DenseSet<Edge> KnownFeasibleEdges;
+ DenseMap<Function *, std::unique_ptr<PredicateInfo>> PredInfos;
+ DenseMap<Value *, SmallPtrSet<User *, 2>> AdditionalUsers;
+
public:
+ void addPredInfo(Function &F, std::unique_ptr<PredicateInfo> PI) {
+ PredInfos[&F] = std::move(PI);
+ }
+
+ const PredicateBase *getPredicateInfoFor(Instruction *I) {
+ auto PI = PredInfos.find(I->getFunction());
+ if (PI == PredInfos.end())
+ return nullptr;
+ return PI->second->getPredicateInfoFor(I);
+ }
+
SCCPSolver(const DataLayout &DL, const TargetLibraryInfo *tli)
: DL(DL), TLI(tli) {}
@@ -558,6 +573,26 @@ private:
visit(*I);
}
+ // Add U as additional user of V.
+ void addAdditionalUser(Value *V, User *U) {
+ auto Iter = AdditionalUsers.insert({V, {}});
+ Iter.first->second.insert(U);
+ }
+
+ // Mark I's users as changed, including AdditionalUsers.
+ void markUsersAsChanged(Value *I) {
+ for (User *U : I->users())
+ if (auto *UI = dyn_cast<Instruction>(U))
+ OperandChangedState(UI);
+
+ auto Iter = AdditionalUsers.find(I);
+ if (Iter != AdditionalUsers.end()) {
+ for (User *U : Iter->second)
+ if (auto *UI = dyn_cast<Instruction>(U))
+ OperandChangedState(UI);
+ }
+ }
+
private:
friend class InstVisitor<SCCPSolver>;
@@ -1119,6 +1154,65 @@ void SCCPSolver::visitCallSite(CallSite CS) {
Function *F = CS.getCalledFunction();
Instruction *I = CS.getInstruction();
+ if (auto *II = dyn_cast<IntrinsicInst>(I)) {
+ if (II->getIntrinsicID() == Intrinsic::ssa_copy) {
+ if (ValueState[I].isOverdefined())
+ return;
+
+ auto *PI = getPredicateInfoFor(I);
+ if (!PI)
+ return;
+
+ auto *PBranch = dyn_cast<PredicateBranch>(getPredicateInfoFor(I));
+ if (!PBranch) {
+ mergeInValue(ValueState[I], I, getValueState(PI->OriginalOp));
+ return;
+ }
+
+ Value *CopyOf = I->getOperand(0);
+ Value *Cond = PBranch->Condition;
+
+ // Everything below relies on the condition being a comparison.
+ auto *Cmp = dyn_cast<CmpInst>(Cond);
+ if (!Cmp) {
+ mergeInValue(ValueState[I], I, getValueState(PI->OriginalOp));
+ return;
+ }
+
+ Value *CmpOp0 = Cmp->getOperand(0);
+ Value *CmpOp1 = Cmp->getOperand(1);
+ if (CopyOf != CmpOp0 && CopyOf != CmpOp1) {
+ mergeInValue(ValueState[I], I, getValueState(PI->OriginalOp));
+ return;
+ }
+
+ if (CmpOp0 != CopyOf)
+ std::swap(CmpOp0, CmpOp1);
+
+ LatticeVal OriginalVal = getValueState(CopyOf);
+ LatticeVal EqVal = getValueState(CmpOp1);
+ LatticeVal &IV = ValueState[I];
+ if (PBranch->TrueEdge && Cmp->getPredicate() == CmpInst::ICMP_EQ) {
+ addAdditionalUser(CmpOp1, I);
+ if (OriginalVal.isConstant())
+ mergeInValue(IV, I, OriginalVal);
+ else
+ mergeInValue(IV, I, EqVal);
+ return;
+ }
+ if (!PBranch->TrueEdge && Cmp->getPredicate() == CmpInst::ICMP_NE) {
+ addAdditionalUser(CmpOp1, I);
+ if (OriginalVal.isConstant())
+ mergeInValue(IV, I, OriginalVal);
+ else
+ mergeInValue(IV, I, EqVal);
+ return;
+ }
+
+ return (void)mergeInValue(IV, I, getValueState(PBranch->OriginalOp));
+ }
+ }
+
// The common case is that we aren't tracking the callee, either because we
// are not doing interprocedural analysis or the callee is indirect, or is
// external. Handle these cases first.
@@ -1238,9 +1332,7 @@ void SCCPSolver::Solve() {
// since all of its users will have already been marked as overdefined
// Update all of the users of this instruction's value.
//
- for (User *U : I->users())
- if (auto *UI = dyn_cast<Instruction>(U))
- OperandChangedState(UI);
+ markUsersAsChanged(I);
}
// Process the instruction work list.
@@ -1257,9 +1349,7 @@ void SCCPSolver::Solve() {
// Update all of the users of this instruction's value.
//
if (I->getType()->isStructTy() || !getValueState(I).isOverdefined())
- for (User *U : I->users())
- if (auto *UI = dyn_cast<Instruction>(U))
- OperandChangedState(UI);
+ markUsersAsChanged(I);
}
// Process the basic block work list.
@@ -1798,8 +1888,9 @@ static void findReturnsToZap(Function &F,
}
}
-bool llvm::runIPSCCP(Module &M, const DataLayout &DL,
- const TargetLibraryInfo *TLI) {
+bool llvm::runIPSCCP(
+ Module &M, const DataLayout &DL, const TargetLibraryInfo *TLI,
+ function_ref<std::unique_ptr<PredicateInfo>(Function &)> getPredicateInfo) {
SCCPSolver Solver(DL, TLI);
// Loop over all functions, marking arguments to those with their addresses
@@ -1808,6 +1899,7 @@ bool llvm::runIPSCCP(Module &M, const DataLayout &DL,
if (F.isDeclaration())
continue;
+ Solver.addPredInfo(F, getPredicateInfo(F));
// Determine if we can track the function's return values. If so, add the
// function to the solver's set of return-tracked functions.
if (canTrackReturnsInterprocedurally(&F))
@@ -1960,6 +2052,21 @@ bool llvm::runIPSCCP(Module &M, const DataLayout &DL,
F.getBasicBlockList().erase(DeadBB);
}
BlocksToErase.clear();
+
+ for (BasicBlock &BB : F) {
+ for (BasicBlock::iterator BI = BB.begin(), E = BB.end(); BI != E;) {
+ Instruction *Inst = &*BI++;
+ if (const PredicateBase *PI = Solver.getPredicateInfoFor(Inst)) {
+ if (auto *II = dyn_cast<IntrinsicInst>(Inst)) {
+ if (II->getIntrinsicID() == Intrinsic::ssa_copy) {
+ Value *Op = II->getOperand(0);
+ Inst->replaceAllUsesWith(Op);
+ Inst->eraseFromParent();
+ }
+ }
+ }
+ }
+ }
}
// If we inferred constant or undef return values for a function, we replaced
diff --git a/llvm/test/Other/new-pm-lto-defaults.ll b/llvm/test/Other/new-pm-lto-defaults.ll
index 26680f5edc4..741ed641f53 100644
--- a/llvm/test/Other/new-pm-lto-defaults.ll
+++ b/llvm/test/Other/new-pm-lto-defaults.ll
@@ -41,6 +41,8 @@
; CHECK-O2-NEXT: Running analysis: ProfileSummaryAnalysis
; CHECK-O2-NEXT: Running analysis: OptimizationRemarkEmitterAnalysis
; CHECK-O2-NEXT: Running pass: IPSCCPPass
+; CHECK-O2-DAG: Running analysis: AssumptionAnalysis on foo
+; CHECK-O2-DAG: Running analysis: DominatorTreeAnalysis on foo
; CHECK-O2-NEXT: Running pass: CalledValuePropagationPass
; CHECK-O-NEXT: Running pass: ModuleToPostOrderCGSCCPassAdaptor<{{.*}}PostOrderFunctionAttrsPass>
; CHECK-O-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}SCC
@@ -57,8 +59,6 @@
; CHECK-O1-NEXT: Running pass: LowerTypeTestsPass
; CHECK-O2-NEXT: Running pass: GlobalOptPass
; CHECK-O2-NEXT: Running pass: ModuleToFunctionPassAdaptor<{{.*}}PromotePass>
-; CHECK-O2-NEXT: Running analysis: DominatorTreeAnalysis
-; CHECK-O2-NEXT: Running analysis: AssumptionAnalysis
; CHECK-O2-NEXT: Running pass: ConstantMergePass
; CHECK-O2-NEXT: Running pass: DeadArgumentEliminationPass
; CHECK-O2-NEXT: Running pass: ModuleToFunctionPassAdaptor<{{.*}}PassManager{{.*}}>
diff --git a/llvm/test/Other/opt-O2-pipeline.ll b/llvm/test/Other/opt-O2-pipeline.ll
index b36bd2449fd..a7f64631b6e 100644
--- a/llvm/test/Other/opt-O2-pipeline.ll
+++ b/llvm/test/Other/opt-O2-pipeline.ll
@@ -28,6 +28,7 @@
; CHECK-NEXT: Force set function attributes
; CHECK-NEXT: Infer set function attributes
; CHECK-NEXT: Interprocedural Sparse Conditional Constant Propagation
+; CHECK-NEXT: Unnamed pass: implement Pass::getPassName()
; CHECK-NEXT: Called Value Propagation
; CHECK-NEXT: Global Variable Optimizer
; CHECK-NEXT: Unnamed pass: implement Pass::getPassName()
@@ -277,6 +278,9 @@
; CHECK-NEXT: Module Verifier
; CHECK-NEXT: Bitcode Writer
; CHECK-NEXT: Pass Arguments:
+; CHECK-NEXT: FunctionPass Manager
+; CHECK-NEXT: Dominator Tree Construction
+; CHECK-NEXT: Pass Arguments:
; CHECK-NEXT: Target Library Information
; CHECK-NEXT: FunctionPass Manager
; CHECK-NEXT: Dominator Tree Construction
diff --git a/llvm/test/Other/opt-O3-pipeline.ll b/llvm/test/Other/opt-O3-pipeline.ll
index 096982a9a8d..33033fef183 100644
--- a/llvm/test/Other/opt-O3-pipeline.ll
+++ b/llvm/test/Other/opt-O3-pipeline.ll
@@ -30,6 +30,7 @@
; CHECK-NEXT: FunctionPass Manager
; CHECK-NEXT: Call-site splitting
; CHECK-NEXT: Interprocedural Sparse Conditional Constant Propagation
+; CHECK-NEXT: Unnamed pass: implement Pass::getPassName()
; CHECK-NEXT: Called Value Propagation
; CHECK-NEXT: Global Variable Optimizer
; CHECK-NEXT: Unnamed pass: implement Pass::getPassName()
@@ -281,6 +282,9 @@
; CHECK-NEXT: Module Verifier
; CHECK-NEXT: Bitcode Writer
; CHECK-NEXT: Pass Arguments:
+; CHECK-NEXT: FunctionPass Manager
+; CHECK-NEXT: Dominator Tree Construction
+; CHECK-NEXT: Pass Arguments:
; CHECK-NEXT: Target Library Information
; CHECK-NEXT: FunctionPass Manager
; CHECK-NEXT: Dominator Tree Construction
diff --git a/llvm/test/Other/opt-Os-pipeline.ll b/llvm/test/Other/opt-Os-pipeline.ll
index 34b8fa86537..d1f874f5d19 100644
--- a/llvm/test/Other/opt-Os-pipeline.ll
+++ b/llvm/test/Other/opt-Os-pipeline.ll
@@ -28,6 +28,7 @@
; CHECK-NEXT: Force set function attributes
; CHECK-NEXT: Infer set function attributes
; CHECK-NEXT: Interprocedural Sparse Conditional Constant Propagation
+; CHECK-NEXT: Unnamed pass: implement Pass::getPassName()
; CHECK-NEXT: Called Value Propagation
; CHECK-NEXT: Global Variable Optimizer
; CHECK-NEXT: Unnamed pass: implement Pass::getPassName()
@@ -264,6 +265,9 @@
; CHECK-NEXT: Module Verifier
; CHECK-NEXT: Bitcode Writer
; CHECK-NEXT: Pass Arguments:
+; CHECK-NEXT: FunctionPass Manager
+; CHECK-NEXT: Dominator Tree Construction
+; CHECK-NEXT: Pass Arguments:
; CHECK-NEXT: Target Library Information
; CHECK-NEXT: FunctionPass Manager
; CHECK-NEXT: Dominator Tree Construction
diff --git a/llvm/test/Transforms/IPConstantProp/musttail-call.ll b/llvm/test/Transforms/IPConstantProp/musttail-call.ll
index 75877585710..567ca408099 100644
--- a/llvm/test/Transforms/IPConstantProp/musttail-call.ll
+++ b/llvm/test/Transforms/IPConstantProp/musttail-call.ll
@@ -9,7 +9,7 @@ define i8* @start(i8 %v) {
%c1 = icmp eq i8 %v, 0
br i1 %c1, label %true, label %false
true:
- ; CHECK: %ca = musttail call i8* @side_effects(i8 %v)
+ ; CHECK: %ca = musttail call i8* @side_effects(i8 0)
; CHECK: ret i8* %ca
%ca = musttail call i8* @side_effects(i8 %v)
ret i8* %ca
@@ -34,7 +34,7 @@ define internal i8* @side_effects(i8 %v) {
; is always `null`.
; The call can't be removed due to `external` call above, though.
- ; CHECK: %ca = musttail call i8* @start(i8 %v)
+ ; CHECK: %ca = musttail call i8* @start(i8 0)
%ca = musttail call i8* @start(i8 %v)
; Thus the result must be returned anyway
OpenPOWER on IntegriCloud