mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 11:42:57 +01:00
Track validity of pass results
Running tests with expensive checks enabled exhibits some problems with verification of pass results. First, the pass verification may require results of analysis that are not available. For instance, verification of loop info requires results of dominator tree analysis. A pass may be marked as conserving loop info but does not need to be dependent on DominatorTreePass. When a pass manager tries to verify that loop info is valid, it needs dominator tree, but corresponding analysis may be already destroyed as no user of it remained. Another case is a pass that is skipped. For instance, entities with linkage available_externally do not need code generation and such passes are skipped for them. In this case result verification must also be skipped. To solve these problems this change introduces a special flag to the Pass structure to mark passes that have valid results. If this flag is reset, verifications dependent on the pass result are skipped. Differential Revision: https://reviews.llvm.org/D27190 llvm-svn: 291882
This commit is contained in:
parent
50f9f008cb
commit
c81d1f1786
@ -29,6 +29,7 @@
|
|||||||
#ifndef LLVM_PASS_H
|
#ifndef LLVM_PASS_H
|
||||||
#define LLVM_PASS_H
|
#define LLVM_PASS_H
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
@ -82,17 +83,40 @@ class Pass {
|
|||||||
AnalysisResolver *Resolver; // Used to resolve analysis
|
AnalysisResolver *Resolver; // Used to resolve analysis
|
||||||
const void *PassID;
|
const void *PassID;
|
||||||
PassKind Kind;
|
PassKind Kind;
|
||||||
|
bool Executed;
|
||||||
|
|
||||||
void operator=(const Pass&) = delete;
|
void operator=(const Pass&) = delete;
|
||||||
Pass(const Pass &) = delete;
|
Pass(const Pass &) = delete;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Pass(PassKind K, char &pid)
|
explicit Pass(PassKind K, char &pid)
|
||||||
: Resolver(nullptr), PassID(&pid), Kind(K) { }
|
: Resolver(nullptr), PassID(&pid), Kind(K), Executed(false) { }
|
||||||
virtual ~Pass();
|
virtual ~Pass();
|
||||||
|
|
||||||
|
|
||||||
PassKind getPassKind() const { return Kind; }
|
PassKind getPassKind() const { return Kind; }
|
||||||
|
|
||||||
|
/// Returns true if the pass has already executed.
|
||||||
|
///
|
||||||
|
/// For an analysis pass it means the result is available. If the function
|
||||||
|
/// returns false, the pass was not run, was skipped or freed.
|
||||||
|
///
|
||||||
|
bool isExecuted() const { return Executed; }
|
||||||
|
|
||||||
|
/// Marks the pass as executed or not.
|
||||||
|
///
|
||||||
|
/// A pass should be marked as executed, if its 'runOn*' method successfully
|
||||||
|
/// finished. When the pass is not needed anymore, it is marked as
|
||||||
|
/// 'non-executed', it takes place in \c freePass. It also occurs when the
|
||||||
|
/// pass is skipped for some reason.
|
||||||
|
///
|
||||||
|
/// The flag should be set prior to call to 'runOn*' method. If it decides
|
||||||
|
/// that the pass should be skipped, it will reset the flag.
|
||||||
|
///
|
||||||
|
void setExecuted(bool x) {
|
||||||
|
assert(x || !getAsImmutablePass()); // Immutable pass cannot be invalidated.
|
||||||
|
Executed = x;
|
||||||
|
}
|
||||||
|
|
||||||
/// getPassName - Return a nice clean name for a pass. This usually
|
/// getPassName - Return a nice clean name for a pass. This usually
|
||||||
/// implemented in terms of the name that is registered by one of the
|
/// implemented in terms of the name that is registered by one of the
|
||||||
/// Registration templates, but can be overloaded directly.
|
/// Registration templates, but can be overloaded directly.
|
||||||
@ -279,8 +303,7 @@ public:
|
|||||||
///
|
///
|
||||||
bool runOnModule(Module &) override { return false; }
|
bool runOnModule(Module &) override { return false; }
|
||||||
|
|
||||||
explicit ImmutablePass(char &pid)
|
explicit ImmutablePass(char &pid) : ModulePass(pid) { setExecuted(true); }
|
||||||
: ModulePass(pid) {}
|
|
||||||
|
|
||||||
// Force out-of-line virtual method.
|
// Force out-of-line virtual method.
|
||||||
~ImmutablePass() override;
|
~ImmutablePass() override;
|
||||||
@ -316,8 +339,9 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
/// Optional passes call this function to check whether the pass should be
|
/// Optional passes call this function to check whether the pass should be
|
||||||
/// skipped. This is the case when Attribute::OptimizeNone is set or when
|
/// skipped. This is the case when Attribute::OptimizeNone is set or when
|
||||||
/// optimization bisect is over the limit.
|
/// optimization bisect is over the limit. It also resets flag Executed on
|
||||||
bool skipFunction(const Function &F) const;
|
/// the pass.
|
||||||
|
bool skipFunction(const Function &F);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -206,6 +206,9 @@ AnalysisType *Pass::getAnalysisIfAvailable() const {
|
|||||||
Pass *ResultPass = Resolver->getAnalysisIfAvailable(PI, true);
|
Pass *ResultPass = Resolver->getAnalysisIfAvailable(PI, true);
|
||||||
if (!ResultPass) return nullptr;
|
if (!ResultPass) return nullptr;
|
||||||
|
|
||||||
|
if (!ResultPass->isExecuted())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
// Because the AnalysisType may not be a subclass of pass (for
|
// Because the AnalysisType may not be a subclass of pass (for
|
||||||
// AnalysisGroups), we use getAdjustedAnalysisPointer here to potentially
|
// AnalysisGroups), we use getAdjustedAnalysisPointer here to potentially
|
||||||
// adjust the return pointer (because the class may multiply inherit, once
|
// adjust the return pointer (because the class may multiply inherit, once
|
||||||
@ -234,6 +237,8 @@ AnalysisType &Pass::getAnalysisID(AnalysisID PI) const {
|
|||||||
assert (ResultPass &&
|
assert (ResultPass &&
|
||||||
"getAnalysis*() called on an analysis that was not "
|
"getAnalysis*() called on an analysis that was not "
|
||||||
"'required' by pass!");
|
"'required' by pass!");
|
||||||
|
assert(ResultPass->isExecuted() &&
|
||||||
|
"getAnalysis*() called on an analysis that was freed");
|
||||||
|
|
||||||
// Because the AnalysisType may not be a subclass of pass (for
|
// Because the AnalysisType may not be a subclass of pass (for
|
||||||
// AnalysisGroups), we use getAdjustedAnalysisPointer here to potentially
|
// AnalysisGroups), we use getAdjustedAnalysisPointer here to potentially
|
||||||
|
@ -414,6 +414,7 @@ bool CGPassManager::RunAllPassesOnSCC(CallGraphSCC &CurSCC, CallGraph &CG,
|
|||||||
initializeAnalysisImpl(P);
|
initializeAnalysisImpl(P);
|
||||||
|
|
||||||
// Actually run this pass on the current SCC.
|
// Actually run this pass on the current SCC.
|
||||||
|
P->setExecuted(true);
|
||||||
Changed |= RunPassOnSCC(P, CurSCC, CG,
|
Changed |= RunPassOnSCC(P, CurSCC, CG,
|
||||||
CallGraphUpToDate, DevirtualizedCall);
|
CallGraphUpToDate, DevirtualizedCall);
|
||||||
|
|
||||||
|
@ -722,8 +722,10 @@ void LoopInfoWrapperPass::verifyAnalysis() const {
|
|||||||
// checking by default, LoopPass has been taught to call verifyLoop manually
|
// checking by default, LoopPass has been taught to call verifyLoop manually
|
||||||
// during loop pass sequences.
|
// during loop pass sequences.
|
||||||
if (VerifyLoopInfo) {
|
if (VerifyLoopInfo) {
|
||||||
auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
|
if (auto *Analysis = getAnalysisIfAvailable<DominatorTreeWrapperPass>()) {
|
||||||
LI.verify(DT);
|
auto &DT = Analysis->getDomTree();
|
||||||
|
LI.verify(DT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,6 +198,7 @@ bool LPPassManager::runOnFunction(Function &F) {
|
|||||||
PassManagerPrettyStackEntry X(P, *CurrentLoop->getHeader());
|
PassManagerPrettyStackEntry X(P, *CurrentLoop->getHeader());
|
||||||
TimeRegion PassTimer(getPassTimer(P));
|
TimeRegion PassTimer(getPassTimer(P));
|
||||||
|
|
||||||
|
P->setExecuted(true);
|
||||||
Changed |= P->runOnLoop(CurrentLoop, *this);
|
Changed |= P->runOnLoop(CurrentLoop, *this);
|
||||||
}
|
}
|
||||||
LoopWasDeleted = CurrentLoop->isInvalid();
|
LoopWasDeleted = CurrentLoop->isInvalid();
|
||||||
|
@ -69,7 +69,7 @@ void MachineDominatorTree::releaseMemory() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MachineDominatorTree::verifyAnalysis() const {
|
void MachineDominatorTree::verifyAnalysis() const {
|
||||||
if (VerifyMachineDomInfo)
|
if (VerifyMachineDomInfo && isExecuted())
|
||||||
verifyDomTree();
|
verifyDomTree();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,8 +38,10 @@ Pass *MachineFunctionPass::createPrinterPass(raw_ostream &O,
|
|||||||
bool MachineFunctionPass::runOnFunction(Function &F) {
|
bool MachineFunctionPass::runOnFunction(Function &F) {
|
||||||
// Do not codegen any 'available_externally' functions at all, they have
|
// Do not codegen any 'available_externally' functions at all, they have
|
||||||
// definitions outside the translation unit.
|
// definitions outside the translation unit.
|
||||||
if (F.hasAvailableExternallyLinkage())
|
if (F.hasAvailableExternallyLinkage()) {
|
||||||
|
setExecuted(false);
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
MachineModuleInfo &MMI = getAnalysis<MachineModuleInfo>();
|
MachineModuleInfo &MMI = getAnalysis<MachineModuleInfo>();
|
||||||
MachineFunction &MF = MMI.getMachineFunction(F);
|
MachineFunction &MF = MMI.getMachineFunction(F);
|
||||||
|
@ -955,6 +955,9 @@ void PMDataManager::freePass(Pass *P, StringRef Msg,
|
|||||||
AvailableAnalysis.erase(Pos);
|
AvailableAnalysis.erase(Pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!P->getAsImmutablePass())
|
||||||
|
P->setExecuted(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add pass P into the PassVector. Update
|
/// Add pass P into the PassVector. Update
|
||||||
@ -1293,6 +1296,7 @@ bool BBPassManager::runOnFunction(Function &F) {
|
|||||||
PassManagerPrettyStackEntry X(BP, *I);
|
PassManagerPrettyStackEntry X(BP, *I);
|
||||||
TimeRegion PassTimer(getPassTimer(BP));
|
TimeRegion PassTimer(getPassTimer(BP));
|
||||||
|
|
||||||
|
BP->setExecuted(true);
|
||||||
LocalChanged |= BP->runOnBasicBlock(*I);
|
LocalChanged |= BP->runOnBasicBlock(*I);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1459,7 +1463,9 @@ bool FunctionPassManagerImpl::run(Function &F) {
|
|||||||
|
|
||||||
initializeAllAnalysisInfo();
|
initializeAllAnalysisInfo();
|
||||||
for (unsigned Index = 0; Index < getNumContainedManagers(); ++Index) {
|
for (unsigned Index = 0; Index < getNumContainedManagers(); ++Index) {
|
||||||
Changed |= getContainedManager(Index)->runOnFunction(F);
|
FPPassManager *P = getContainedManager(Index);
|
||||||
|
P->setExecuted(true);
|
||||||
|
Changed |= P->runOnFunction(F);
|
||||||
F.getContext().yield();
|
F.getContext().yield();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1510,6 +1516,7 @@ bool FPPassManager::runOnFunction(Function &F) {
|
|||||||
PassManagerPrettyStackEntry X(FP, F);
|
PassManagerPrettyStackEntry X(FP, F);
|
||||||
TimeRegion PassTimer(getPassTimer(FP));
|
TimeRegion PassTimer(getPassTimer(FP));
|
||||||
|
|
||||||
|
FP->setExecuted(true);
|
||||||
LocalChanged |= FP->runOnFunction(F);
|
LocalChanged |= FP->runOnFunction(F);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1530,8 +1537,10 @@ bool FPPassManager::runOnFunction(Function &F) {
|
|||||||
bool FPPassManager::runOnModule(Module &M) {
|
bool FPPassManager::runOnModule(Module &M) {
|
||||||
bool Changed = false;
|
bool Changed = false;
|
||||||
|
|
||||||
for (Function &F : M)
|
for (Function &F : M) {
|
||||||
|
setExecuted(true);
|
||||||
Changed |= runOnFunction(F);
|
Changed |= runOnFunction(F);
|
||||||
|
}
|
||||||
|
|
||||||
return Changed;
|
return Changed;
|
||||||
}
|
}
|
||||||
@ -1587,6 +1596,7 @@ MPPassManager::runOnModule(Module &M) {
|
|||||||
PassManagerPrettyStackEntry X(MP, M);
|
PassManagerPrettyStackEntry X(MP, M);
|
||||||
TimeRegion PassTimer(getPassTimer(MP));
|
TimeRegion PassTimer(getPassTimer(MP));
|
||||||
|
|
||||||
|
MP->setExecuted(true);
|
||||||
LocalChanged |= MP->runOnModule(M);
|
LocalChanged |= MP->runOnModule(M);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1690,7 +1700,9 @@ bool PassManagerImpl::run(Module &M) {
|
|||||||
|
|
||||||
initializeAllAnalysisInfo();
|
initializeAllAnalysisInfo();
|
||||||
for (unsigned Index = 0; Index < getNumContainedManagers(); ++Index) {
|
for (unsigned Index = 0; Index < getNumContainedManagers(); ++Index) {
|
||||||
Changed |= getContainedManager(Index)->runOnModule(M);
|
MPPassManager *P = getContainedManager(Index);
|
||||||
|
P->setExecuted(true);
|
||||||
|
Changed |= P->runOnModule(M);
|
||||||
M.getContext().yield();
|
M.getContext().yield();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,13 +146,16 @@ PassManagerType FunctionPass::getPotentialPassManagerType() const {
|
|||||||
return PMT_FunctionPassManager;
|
return PMT_FunctionPassManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FunctionPass::skipFunction(const Function &F) const {
|
bool FunctionPass::skipFunction(const Function &F) {
|
||||||
if (!F.getContext().getOptBisect().shouldRunPass(this, F))
|
if (!F.getContext().getOptBisect().shouldRunPass(this, F)) {
|
||||||
|
setExecuted(false);
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (F.hasFnAttribute(Attribute::OptimizeNone)) {
|
if (F.hasFnAttribute(Attribute::OptimizeNone)) {
|
||||||
DEBUG(dbgs() << "Skipping pass '" << getPassName() << "' on function "
|
DEBUG(dbgs() << "Skipping pass '" << getPassName() << "' on function "
|
||||||
<< F.getName() << "\n");
|
<< F.getName() << "\n");
|
||||||
|
setExecuted(false);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
; RUN: llc < %s | not grep test_
|
; RUN: llc -verify-machine-dom-info < %s | not grep test_
|
||||||
|
|
||||||
; test_function should not be emitted to the .s file.
|
; test_function should not be emitted to the .s file.
|
||||||
define available_externally i32 @test_function() {
|
define available_externally i32 @test_function() {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
; RUN: llc -march=mipsel -mattr=mips16 -relocation-model=pic -O3 < %s | FileCheck %s -check-prefix=16
|
; RUN: llc -march=mipsel -mattr=mips16 -relocation-model=pic -O3 -verify-loop-info < %s | FileCheck %s -check-prefix=16
|
||||||
|
|
||||||
@iiii = global i32 5, align 4
|
@iiii = global i32 5, align 4
|
||||||
@jjjj = global i32 -6, align 4
|
@jjjj = global i32 -6, align 4
|
||||||
|
Loading…
Reference in New Issue
Block a user