]> granicus.if.org Git - llvm/commitdiff
Track validity of pass results
authorSerge Pavlov <sepavloff@gmail.com>
Fri, 13 Jan 2017 06:09:54 +0000 (06:09 +0000)
committerSerge Pavlov <sepavloff@gmail.com>
Fri, 13 Jan 2017 06:09:54 +0000 (06:09 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@291882 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Pass.h
include/llvm/PassAnalysisSupport.h
lib/Analysis/CallGraphSCCPass.cpp
lib/Analysis/LoopInfo.cpp
lib/Analysis/LoopPass.cpp
lib/CodeGen/MachineDominators.cpp
lib/CodeGen/MachineFunctionPass.cpp
lib/IR/LegacyPassManager.cpp
lib/IR/Pass.cpp
test/CodeGen/Generic/externally_available.ll
test/CodeGen/Mips/mul.ll

index e9c8ca3072c71b0f708efa4f00dc557d550711dd..105da67cbb3e83918d071e36bfc7cef57856a157 100644 (file)
@@ -29,6 +29,7 @@
 #ifndef LLVM_PASS_H
 #define LLVM_PASS_H
 
+#include <assert.h>
 #include <string>
 
 namespace llvm {
@@ -82,17 +83,40 @@ class Pass {
   AnalysisResolver *Resolver;  // Used to resolve analysis
   const void *PassID;
   PassKind Kind;
+  bool Executed;
+
   void operator=(const Pass&) = delete;
   Pass(const Pass &) = delete;
 
 public:
   explicit Pass(PassKind K, char &pid)
-    : Resolver(nullptr), PassID(&pid), Kind(K) { }
+    : Resolver(nullptr), PassID(&pid), Kind(K), Executed(false) { }
   virtual ~Pass();
 
-
   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
   /// implemented in terms of the name that is registered by one of the
   /// Registration templates, but can be overloaded directly.
@@ -279,8 +303,7 @@ public:
   ///
   bool runOnModule(Module &) override { return false; }
 
-  explicit ImmutablePass(char &pid)
-  : ModulePass(pid) {}
+  explicit ImmutablePass(char &pid) : ModulePass(pid) { setExecuted(true); }
 
   // Force out-of-line virtual method.
   ~ImmutablePass() override;
@@ -316,8 +339,9 @@ public:
 protected:
   /// Optional passes call this function to check whether the pass should be
   /// skipped. This is the case when Attribute::OptimizeNone is set or when
-  /// optimization bisect is over the limit.
-  bool skipFunction(const Function &F) const;
+  /// optimization bisect is over the limit. It also resets flag Executed on
+  /// the pass.
+  bool skipFunction(const Function &F);
 };
 
 
index abd9929380575f3df430c50fe1ad5fadfb82ec67..d7091fc4fe40bd22dadcbdbef715bfd44841ec61 100644 (file)
@@ -206,6 +206,9 @@ AnalysisType *Pass::getAnalysisIfAvailable() const {
   Pass *ResultPass = Resolver->getAnalysisIfAvailable(PI, true);
   if (!ResultPass) return nullptr;
 
+  if (!ResultPass->isExecuted())
+    return nullptr;
+
   // Because the AnalysisType may not be a subclass of pass (for
   // AnalysisGroups), we use getAdjustedAnalysisPointer here to potentially
   // adjust the return pointer (because the class may multiply inherit, once
@@ -234,6 +237,8 @@ AnalysisType &Pass::getAnalysisID(AnalysisID PI) const {
   assert (ResultPass && 
           "getAnalysis*() called on an analysis that was not "
           "'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
   // AnalysisGroups), we use getAdjustedAnalysisPointer here to potentially
index 9cef781441508fda95aee3524f4d2385862638e8..290fd34cff563f8f47789f7d6885cf754ddbfb1b 100644 (file)
@@ -414,6 +414,7 @@ bool CGPassManager::RunAllPassesOnSCC(CallGraphSCC &CurSCC, CallGraph &CG,
     initializeAnalysisImpl(P);
     
     // Actually run this pass on the current SCC.
+    P->setExecuted(true);
     Changed |= RunPassOnSCC(P, CurSCC, CG,
                             CallGraphUpToDate, DevirtualizedCall);
     
index f449ce94d57ca6ba2ebed7dfb315fdf8006b14e1..1b5d6e5d1b7f73625c9b2adf0ca4eecf99a83506 100644 (file)
@@ -722,8 +722,10 @@ void LoopInfoWrapperPass::verifyAnalysis() const {
   // checking by default, LoopPass has been taught to call verifyLoop manually
   // during loop pass sequences.
   if (VerifyLoopInfo) {
-    auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
-    LI.verify(DT);
+    if (auto *Analysis = getAnalysisIfAvailable<DominatorTreeWrapperPass>()) {
+      auto &DT = Analysis->getDomTree();
+      LI.verify(DT);
+    }
   }
 }
 
index 3f4a07942154c853c5a03b0fb8a8998292914f79..d3e697e5c61364ac74c47edaf22beb6ca24feb44 100644 (file)
@@ -198,6 +198,7 @@ bool LPPassManager::runOnFunction(Function &F) {
         PassManagerPrettyStackEntry X(P, *CurrentLoop->getHeader());
         TimeRegion PassTimer(getPassTimer(P));
 
+        P->setExecuted(true);
         Changed |= P->runOnLoop(CurrentLoop, *this);
       }
       LoopWasDeleted = CurrentLoop->isInvalid();
index 303a6a9263be7a51c81cc7ccc1c23386f40e48b0..a548480044eeb2300f328aa76cdbafbe37a7ab2c 100644 (file)
@@ -69,7 +69,7 @@ void MachineDominatorTree::releaseMemory() {
 }
 
 void MachineDominatorTree::verifyAnalysis() const {
-  if (VerifyMachineDomInfo)
+  if (VerifyMachineDomInfo && isExecuted())
     verifyDomTree();
 }
 
index 2265676ff8b1445836263891339abd025a8f1ba5..a7ece36a1e52a38249ba8975e7b177d2fcc452e5 100644 (file)
@@ -38,8 +38,10 @@ Pass *MachineFunctionPass::createPrinterPass(raw_ostream &O,
 bool MachineFunctionPass::runOnFunction(Function &F) {
   // Do not codegen any 'available_externally' functions at all, they have
   // definitions outside the translation unit.
-  if (F.hasAvailableExternallyLinkage())
+  if (F.hasAvailableExternallyLinkage()) {
+    setExecuted(false);
     return false;
+  }
 
   MachineModuleInfo &MMI = getAnalysis<MachineModuleInfo>();
   MachineFunction &MF = MMI.getMachineFunction(F);
index 628a67bd639ce29f9cf5e0e2be63628f49532a80..0b2c40b742a2dfcf698bb89a3074495049c0c2fb 100644 (file)
@@ -955,6 +955,9 @@ void PMDataManager::freePass(Pass *P, StringRef Msg,
         AvailableAnalysis.erase(Pos);
     }
   }
+
+  if (!P->getAsImmutablePass())
+    P->setExecuted(false);
 }
 
 /// Add pass P into the PassVector. Update
@@ -1293,6 +1296,7 @@ bool BBPassManager::runOnFunction(Function &F) {
         PassManagerPrettyStackEntry X(BP, *I);
         TimeRegion PassTimer(getPassTimer(BP));
 
+        BP->setExecuted(true);
         LocalChanged |= BP->runOnBasicBlock(*I);
       }
 
@@ -1459,7 +1463,9 @@ bool FunctionPassManagerImpl::run(Function &F) {
 
   initializeAllAnalysisInfo();
   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();
   }
 
@@ -1510,6 +1516,7 @@ bool FPPassManager::runOnFunction(Function &F) {
       PassManagerPrettyStackEntry X(FP, F);
       TimeRegion PassTimer(getPassTimer(FP));
 
+      FP->setExecuted(true);
       LocalChanged |= FP->runOnFunction(F);
     }
 
@@ -1530,8 +1537,10 @@ bool FPPassManager::runOnFunction(Function &F) {
 bool FPPassManager::runOnModule(Module &M) {
   bool Changed = false;
 
-  for (Function &F : M)
+  for (Function &F : M) {
+    setExecuted(true);
     Changed |= runOnFunction(F);
+  }
 
   return Changed;
 }
@@ -1587,6 +1596,7 @@ MPPassManager::runOnModule(Module &M) {
       PassManagerPrettyStackEntry X(MP, M);
       TimeRegion PassTimer(getPassTimer(MP));
 
+      MP->setExecuted(true);
       LocalChanged |= MP->runOnModule(M);
     }
 
@@ -1690,7 +1700,9 @@ bool PassManagerImpl::run(Module &M) {
 
   initializeAllAnalysisInfo();
   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();
   }
 
index a42945ef3fffa34ff35e25d5f5438dcb5c8e928f..6e22c1d4641d38a7a33e6f06a071edcd8c5aab52 100644 (file)
@@ -146,13 +146,16 @@ PassManagerType FunctionPass::getPotentialPassManagerType() const {
   return PMT_FunctionPassManager;
 }
 
-bool FunctionPass::skipFunction(const Function &F) const {
-  if (!F.getContext().getOptBisect().shouldRunPass(this, F))
+bool FunctionPass::skipFunction(const Function &F) {
+  if (!F.getContext().getOptBisect().shouldRunPass(this, F)) {
+    setExecuted(false);
     return true;
+  }
 
   if (F.hasFnAttribute(Attribute::OptimizeNone)) {
     DEBUG(dbgs() << "Skipping pass '" << getPassName() << "' on function "
                  << F.getName() << "\n");
+    setExecuted(false);
     return true;
   }
   return false;
index 7976cc971880f117b49f248885808291d77c93a8..2376bc7399277c40a7fc1973c831aab20d190c9f 100644 (file)
@@ -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.
 define available_externally i32 @test_function() {
index 9e053fc2e7d67f507a91cb24a9ba75423a66529c..fa147b08ff2a422d18c40a6b0b6b7d08fdc1e7cb 100644 (file)
@@ -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
 @jjjj = global i32 -6, align 4