mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-15 07:39:31 +00:00
[IPSCCP,PM] Preserve DT in the new pass manager.
After D45330, Dominators are required for IPSCCP and can be preserved. This patch preserves DominatorTreeAnalysis in the new pass manager. AFAIK the legacy pass manager cannot preserve function analysis required by a module analysis. Reviewers: davide, dberlin, chandlerc, efriedma, kuhar, NutshellySima Reviewed By: chandlerc, kuhar, NutshellySima Differential Revision: https://reviews.llvm.org/D47259 llvm-svn: 346486
This commit is contained in:
parent
912039ffa2
commit
71301cf938
@ -39,9 +39,14 @@ public:
|
||||
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
|
||||
};
|
||||
|
||||
bool runIPSCCP(
|
||||
Module &M, const DataLayout &DL, const TargetLibraryInfo *TLI,
|
||||
function_ref<std::unique_ptr<PredicateInfo>(Function &)> getPredicateInfo);
|
||||
/// Helper struct for bundling up the analysis results per function for IPSCCP.
|
||||
struct AnalysisResultsForFn {
|
||||
std::unique_ptr<PredicateInfo> PredInfo;
|
||||
DominatorTree *DT;
|
||||
};
|
||||
|
||||
bool runIPSCCP(Module &M, const DataLayout &DL, const TargetLibraryInfo *TLI,
|
||||
function_ref<AnalysisResultsForFn(Function &)> getAnalysis);
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_TRANSFORMS_SCALAR_SCCP_H
|
||||
|
@ -10,16 +10,20 @@ PreservedAnalyses IPSCCPPass::run(Module &M, ModuleAnalysisManager &AM) {
|
||||
const DataLayout &DL = M.getDataLayout();
|
||||
auto &TLI = AM.getResult<TargetLibraryAnalysis>(M);
|
||||
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));
|
||||
auto getAnalysis = [&FAM](Function &F) -> AnalysisResultsForFn {
|
||||
DominatorTree &DT = FAM.getResult<DominatorTreeAnalysis>(F);
|
||||
return {
|
||||
make_unique<PredicateInfo>(F, DT, FAM.getResult<AssumptionAnalysis>(F)),
|
||||
&DT};
|
||||
};
|
||||
|
||||
if (!runIPSCCP(M, DL, &TLI, getPredicateInfo))
|
||||
if (!runIPSCCP(M, DL, &TLI, getAnalysis))
|
||||
return PreservedAnalyses::all();
|
||||
return PreservedAnalyses::none();
|
||||
|
||||
PreservedAnalyses PA;
|
||||
PA.preserve<DominatorTreeAnalysis>();
|
||||
PA.preserve<FunctionAnalysisManagerModuleProxy>();
|
||||
return PA;
|
||||
}
|
||||
|
||||
namespace {
|
||||
@ -44,14 +48,19 @@ public:
|
||||
const TargetLibraryInfo *TLI =
|
||||
&getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
|
||||
|
||||
auto getPredicateInfo =
|
||||
[this](Function &F) -> std::unique_ptr<PredicateInfo> {
|
||||
return make_unique<PredicateInfo>(
|
||||
F, this->getAnalysis<DominatorTreeWrapperPass>(F).getDomTree(),
|
||||
this->getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F));
|
||||
auto getAnalysis = [this](Function &F) -> AnalysisResultsForFn {
|
||||
DominatorTree &DT =
|
||||
this->getAnalysis<DominatorTreeWrapperPass>(F).getDomTree();
|
||||
return {
|
||||
make_unique<PredicateInfo>(
|
||||
F, DT,
|
||||
this->getAnalysis<AssumptionCacheTracker>().getAssumptionCache(
|
||||
F)),
|
||||
nullptr}; // We cannot preserve the DT with the legacy pass manager,
|
||||
// so so set it to nullptr.
|
||||
};
|
||||
|
||||
return runIPSCCP(M, DL, TLI, getPredicateInfo);
|
||||
return runIPSCCP(M, DL, TLI, getAnalysis);
|
||||
}
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
|
@ -247,19 +247,25 @@ class SCCPSolver : public InstVisitor<SCCPSolver> {
|
||||
using Edge = std::pair<BasicBlock *, BasicBlock *>;
|
||||
DenseSet<Edge> KnownFeasibleEdges;
|
||||
|
||||
DenseMap<Function *, std::unique_ptr<PredicateInfo>> PredInfos;
|
||||
DenseMap<Function *, AnalysisResultsForFn> AnalysisResults;
|
||||
DenseMap<Value *, SmallPtrSet<User *, 2>> AdditionalUsers;
|
||||
|
||||
public:
|
||||
void addPredInfo(Function &F, std::unique_ptr<PredicateInfo> PI) {
|
||||
PredInfos[&F] = std::move(PI);
|
||||
void addAnalysis(Function &F, AnalysisResultsForFn A) {
|
||||
AnalysisResults.insert({&F, std::move(A)});
|
||||
}
|
||||
|
||||
const PredicateBase *getPredicateInfoFor(Instruction *I) {
|
||||
auto PI = PredInfos.find(I->getFunction());
|
||||
if (PI == PredInfos.end())
|
||||
auto A = AnalysisResults.find(I->getParent()->getParent());
|
||||
if (A == AnalysisResults.end())
|
||||
return nullptr;
|
||||
return PI->second->getPredicateInfoFor(I);
|
||||
return A->second.PredInfo->getPredicateInfoFor(I);
|
||||
}
|
||||
|
||||
DominatorTree *getDomTree(Function &F) {
|
||||
auto A = AnalysisResults.find(&F);
|
||||
assert(A != AnalysisResults.end() && "Need analysis results for function.");
|
||||
return A->second.DT;
|
||||
}
|
||||
|
||||
SCCPSolver(const DataLayout &DL, const TargetLibraryInfo *tli)
|
||||
@ -1927,10 +1933,9 @@ static void forceIndeterminateEdge(Instruction* I, SCCPSolver &Solver) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool llvm::runIPSCCP(
|
||||
Module &M, const DataLayout &DL, const TargetLibraryInfo *TLI,
|
||||
function_ref<std::unique_ptr<PredicateInfo>(Function &)> getPredicateInfo) {
|
||||
function_ref<AnalysisResultsForFn(Function &)> getAnalysis) {
|
||||
SCCPSolver Solver(DL, TLI);
|
||||
|
||||
// Loop over all functions, marking arguments to those with their addresses
|
||||
@ -1939,7 +1944,8 @@ bool llvm::runIPSCCP(
|
||||
if (F.isDeclaration())
|
||||
continue;
|
||||
|
||||
Solver.addPredInfo(F, getPredicateInfo(F));
|
||||
Solver.addAnalysis(F, getAnalysis(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))
|
||||
@ -1988,12 +1994,13 @@ bool llvm::runIPSCCP(
|
||||
|
||||
// Iterate over all of the instructions in the module, replacing them with
|
||||
// constants if we have found them to be of constant values.
|
||||
SmallVector<BasicBlock*, 512> BlocksToErase;
|
||||
|
||||
for (Function &F : M) {
|
||||
if (F.isDeclaration())
|
||||
continue;
|
||||
|
||||
SmallVector<BasicBlock *, 512> BlocksToErase;
|
||||
|
||||
if (Solver.isBlockExecutable(&F.front()))
|
||||
for (Function::arg_iterator AI = F.arg_begin(), E = F.arg_end(); AI != E;
|
||||
++AI) {
|
||||
@ -2029,23 +2036,27 @@ bool llvm::runIPSCCP(
|
||||
}
|
||||
}
|
||||
|
||||
// Change dead blocks to unreachable. We do it after replacing constants in
|
||||
// all executable blocks, because changeToUnreachable may remove PHI nodes
|
||||
// in executable blocks we found values for. The function's entry block is
|
||||
// not part of BlocksToErase, so we have to handle it separately.
|
||||
for (BasicBlock *BB : BlocksToErase)
|
||||
DomTreeUpdater DTU(Solver.getDomTree(F),
|
||||
DomTreeUpdater::UpdateStrategy::Lazy);
|
||||
// Change dead blocks to unreachable. We do it after replacing constants
|
||||
// in all executable blocks, because changeToUnreachable may remove PHI
|
||||
// nodes in executable blocks we found values for. The function's entry
|
||||
// block is not part of BlocksToErase, so we have to handle it separately.
|
||||
for (BasicBlock *BB : BlocksToErase) {
|
||||
NumInstRemoved +=
|
||||
changeToUnreachable(BB->getFirstNonPHI(), /*UseLLVMTrap=*/false);
|
||||
changeToUnreachable(BB->getFirstNonPHI(), /*UseLLVMTrap=*/false,
|
||||
/*PreserveLCSSA=*/false, &DTU);
|
||||
}
|
||||
if (!Solver.isBlockExecutable(&F.front()))
|
||||
NumInstRemoved += changeToUnreachable(F.front().getFirstNonPHI(),
|
||||
/*UseLLVMTrap=*/false);
|
||||
/*UseLLVMTrap=*/false,
|
||||
/*PreserveLCSSA=*/false, &DTU);
|
||||
|
||||
// Now that all instructions in the function are constant folded, erase dead
|
||||
// blocks, because we can now use ConstantFoldTerminator to get rid of
|
||||
// in-edges.
|
||||
for (unsigned i = 0, e = BlocksToErase.size(); i != e; ++i) {
|
||||
// Now that all instructions in the function are constant folded,
|
||||
// use ConstantFoldTerminator to get rid of in-edges, record DT updates and
|
||||
// delete dead BBs.
|
||||
for (BasicBlock *DeadBB : BlocksToErase) {
|
||||
// If there are any PHI nodes in this successor, drop entries for BB now.
|
||||
BasicBlock *DeadBB = BlocksToErase[i];
|
||||
for (Value::user_iterator UI = DeadBB->user_begin(),
|
||||
UE = DeadBB->user_end();
|
||||
UI != UE;) {
|
||||
@ -2060,16 +2071,16 @@ bool llvm::runIPSCCP(
|
||||
// If we have forced an edge for an indeterminate value, then force the
|
||||
// terminator to fold to that edge.
|
||||
forceIndeterminateEdge(I, Solver);
|
||||
bool Folded = ConstantFoldTerminator(I->getParent());
|
||||
bool Folded = ConstantFoldTerminator(I->getParent(),
|
||||
/*DeleteDeadConditions=*/false,
|
||||
/*TLI=*/nullptr, &DTU);
|
||||
assert(Folded &&
|
||||
"Expect TermInst on constantint or blockaddress to be folded");
|
||||
(void) Folded;
|
||||
}
|
||||
|
||||
// Finally, delete the basic block.
|
||||
F.getBasicBlockList().erase(DeadBB);
|
||||
// Mark dead BB for deletion.
|
||||
DTU.deleteBB(DeadBB);
|
||||
}
|
||||
BlocksToErase.clear();
|
||||
|
||||
for (BasicBlock &BB : F) {
|
||||
for (BasicBlock::iterator BI = BB.begin(), E = BB.end(); BI != E;) {
|
||||
|
63
test/Transforms/SCCP/ipsccp-preserve-domtree.ll
Normal file
63
test/Transforms/SCCP/ipsccp-preserve-domtree.ll
Normal file
@ -0,0 +1,63 @@
|
||||
; Basic test to check that DominatorTreeAnalysis is preserved by IPSCCP and
|
||||
; the following analysis can re-use it. The test contains two trivial functions
|
||||
; IPSCCP can simplify, so we can test the case where IPSCCP makes changes.
|
||||
|
||||
; RUN: opt -disable-verify -debug-pass-manager \
|
||||
; RUN: -passes='ipsccp,globalopt' -S %s 2>&1 \
|
||||
; RUN: | FileCheck -check-prefixes='IR,NEW-PM' %s
|
||||
|
||||
; RUN: opt -passes='ipsccp,function(verify<domtree>)' -S %s | FileCheck -check-prefixes='IR' %s
|
||||
|
||||
; NEW-PM: Starting llvm::Module pass manager run.
|
||||
; NEW-PM-NEXT: Running pass: IPSCCPPass
|
||||
; NEW-PM-DAG: Running analysis: TargetLibraryAnalysis
|
||||
; NEW-PM-DAG: Running analysis: InnerAnalysisManagerProxy
|
||||
; NEW-PM-DAG: Running analysis: AssumptionAnalysis on f1
|
||||
; NEW-PM-DAG: Running analysis: DominatorTreeAnalysis on f1
|
||||
; NEW-PM-DAG: Running analysis: PassInstrumentationAnalysis on f1
|
||||
; NEW-PM-DAG: Running analysis: DominatorTreeAnalysis on f2
|
||||
; NEW-PM-DAG: Running analysis: AssumptionAnalysis on f2
|
||||
; NEW-PM-DAG: Running analysis: PassInstrumentationAnalysis on f2
|
||||
; NEW-PM-NEXT: Invalidating all non-preserved analyses for:
|
||||
; NEW-PM-NEXT: Invalidating all non-preserved analyses for: f1
|
||||
; NEW-PM-NEXT: Invalidating all non-preserved analyses for: f2
|
||||
; NEW-PM-NEXT: Running pass: GlobalOptPass on
|
||||
; NEW-PM-DAG: Running analysis: BlockFrequencyAnalysis on f2
|
||||
; NEW-PM-DAG: Running analysis: LoopAnalysis on f2
|
||||
; NEW-PM-DAG: Running analysis: BranchProbabilityAnalysis on f2
|
||||
; NEW-PM-DAG: Running analysis: TargetLibraryAnalysis on f2
|
||||
; NEW-PM-NEXT: Running analysis: TargetIRAnalysis on f1
|
||||
; NEW-PM-NEXT: Invalidating all non-preserved analyses for:
|
||||
|
||||
; IR-LABEL: @f1
|
||||
; IR-LABEL: entry:
|
||||
; IR-NEXT: br label %bb2
|
||||
; IR-LABEL: bb2:
|
||||
; IR-NEXT: undef
|
||||
|
||||
; IR-LABEL: @f2
|
||||
; IR-NOT: icmp
|
||||
; IR: br label %bbtrue
|
||||
; IR-LABEL: bbtrue:
|
||||
; IR-NEXT: ret i32 0
|
||||
define internal i32 @f1() readnone {
|
||||
entry:
|
||||
br i1 false, label %bb1, label %bb2
|
||||
bb1:
|
||||
ret i32 10
|
||||
bb2:
|
||||
ret i32 10
|
||||
}
|
||||
|
||||
define i32 @f2(i32 %n) {
|
||||
%i = call i32 @f1()
|
||||
%cmp = icmp eq i32 %i, 10
|
||||
br i1 %cmp, label %bbtrue, label %bbfalse
|
||||
|
||||
bbtrue:
|
||||
ret i32 0
|
||||
|
||||
bbfalse:
|
||||
%res = add i32 %n, %i
|
||||
ret i32 %res
|
||||
}
|
Loading…
Reference in New Issue
Block a user