Disable most IR-level transform passes on functions marked 'optnone'.
authorPaul Robinson <paul_robinson@playstation.sony.com>
Thu, 6 Feb 2014 00:07:05 +0000 (00:07 +0000)
committerPaul Robinson <paul_robinson@playstation.sony.com>
Thu, 6 Feb 2014 00:07:05 +0000 (00:07 +0000)
Ideally only those transform passes that run at -O0 remain enabled,
in reality we get as close as we reasonably can.
Passes are responsible for disabling themselves, it's not the job of
the pass manager to do it for them.

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

34 files changed:
include/llvm/Analysis/LoopPass.h
include/llvm/Pass.h
lib/Analysis/LoopPass.cpp
lib/IR/Pass.cpp
lib/Transforms/IPO/LoopExtractor.cpp
lib/Transforms/InstCombine/InstructionCombining.cpp
lib/Transforms/Scalar/ADCE.cpp
lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
lib/Transforms/Scalar/DCE.cpp
lib/Transforms/Scalar/DeadStoreElimination.cpp
lib/Transforms/Scalar/EarlyCSE.cpp
lib/Transforms/Scalar/GVN.cpp
lib/Transforms/Scalar/IndVarSimplify.cpp
lib/Transforms/Scalar/JumpThreading.cpp
lib/Transforms/Scalar/LICM.cpp
lib/Transforms/Scalar/LoopDeletion.cpp
lib/Transforms/Scalar/LoopIdiomRecognize.cpp
lib/Transforms/Scalar/LoopInstSimplify.cpp
lib/Transforms/Scalar/LoopRerollPass.cpp
lib/Transforms/Scalar/LoopRotation.cpp
lib/Transforms/Scalar/LoopStrengthReduce.cpp
lib/Transforms/Scalar/LoopUnrollPass.cpp
lib/Transforms/Scalar/LoopUnswitch.cpp
lib/Transforms/Scalar/LowerAtomic.cpp
lib/Transforms/Scalar/MemCpyOptimizer.cpp
lib/Transforms/Scalar/Reassociate.cpp
lib/Transforms/Scalar/SCCP.cpp
lib/Transforms/Scalar/SROA.cpp
lib/Transforms/Scalar/ScalarReplAggregates.cpp
lib/Transforms/Scalar/SimplifyCFGPass.cpp
lib/Transforms/Scalar/TailRecursionElimination.cpp
lib/Transforms/Vectorize/BBVectorize.cpp
lib/Transforms/Vectorize/SLPVectorizer.cpp
test/Feature/optnone-opt.ll [new file with mode: 0644]

index 5926610d1aa651bde39e4031e69285eba85646b6..9ca55053f53cd91002e61e4810d626b4b0d7febd 100644 (file)
@@ -81,6 +81,11 @@ public:
 
   /// deleteAnalysisValue - Delete analysis info associated with value V.
   virtual void deleteAnalysisValue(Value *V, Loop *L) {}
+
+protected:
+  /// skipOptnoneFunction - Containing function has Attribute::OptimizeNone
+  /// and most transformation passes should skip it.
+  bool skipOptnoneFunction(Loop *L) const;
 };
 
 class LPPassManager : public FunctionPass, public PMDataManager {
index 35ec022516a546f166a1fb2dfbc81e80a7bce4ce..e16144397c447aa2de3401fc7db94c731720ea0e 100644 (file)
@@ -307,6 +307,11 @@ public:
 
   ///  Return what kind of Pass Manager can manage this pass.
   virtual PassManagerType getPotentialPassManagerType() const;
+
+protected:
+  /// skipOptnoneFunction - This function has Attribute::OptimizeNone
+  /// and most transformation passes should skip it.
+  bool skipOptnoneFunction(Function &F) const;
 };
 
 
@@ -351,6 +356,11 @@ public:
 
   ///  Return what kind of Pass Manager can manage this pass.
   virtual PassManagerType getPotentialPassManagerType() const;
+
+protected:
+  /// skipOptnoneFunction - Containing function has Attribute::OptimizeNone
+  /// and most transformation passes should skip it.
+  bool skipOptnoneFunction(BasicBlock &BB) const;
 };
 
 /// If the user specifies the -time-passes argument on an LLVM tool command line
index 4775359c506246e548fd9b77b58d14464cf30748..db69e1325a8c6df69666dd0221825fd0e5f36fad 100644 (file)
@@ -365,3 +365,17 @@ void LoopPass::assignPassManager(PMStack &PMS,
 
   LPPM->add(this);
 }
+
+// Containing function has Attribute::OptimizeNone and transformation
+// passes should skip it.
+bool LoopPass::skipOptnoneFunction(Loop *L) const {
+  Function *F = L->getHeader()->getParent();
+  if (F && F->hasFnAttribute(Attribute::OptimizeNone)) {
+    // FIXME: Report this to dbgs() only once per function.
+    DEBUG(dbgs() << "Skipping pass '" << getPassName()
+          << "' in function " << F->getName() << "\n");
+    // FIXME: Delete loop from pass manager's queue?
+    return true;
+  }
+  return false;
+}
index 3782e2d7be5d280ed1dbd1702f3657de8fd09fb2..84b0b04d6989cd6e8e73a411cbae877585bb44c2 100644 (file)
@@ -14,6 +14,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/Pass.h"
+#include "llvm/IR/Function.h"
 #include "llvm/IR/IRPrintingPasses.h"
 #include "llvm/PassRegistry.h"
 #include "llvm/Support/Debug.h"
@@ -137,6 +138,15 @@ PassManagerType FunctionPass::getPotentialPassManagerType() const {
   return PMT_FunctionPassManager;
 }
 
+bool FunctionPass::skipOptnoneFunction(Function &F) const {
+  if (F.hasFnAttribute(Attribute::OptimizeNone)) {
+    DEBUG(dbgs() << "Skipping pass '" << getPassName()
+          << "' on function " << F.getName() << "\n");
+    return true;
+  }
+  return false;
+}
+
 //===----------------------------------------------------------------------===//
 // BasicBlockPass Implementation
 //
@@ -156,6 +166,18 @@ bool BasicBlockPass::doFinalization(Function &) {
   return false;
 }
 
+bool BasicBlockPass::skipOptnoneFunction(BasicBlock &BB) const {
+  Function *F = BB.getParent();
+  if (F && F->hasFnAttribute(Attribute::OptimizeNone)) {
+    // Report this only once per function.
+    if (&BB == &F->getEntryBlock())
+      DEBUG(dbgs() << "Skipping pass '" << getPassName()
+            << "' on function " << F->getName() << "\n");
+    return true;
+  }
+  return false;
+}
+
 PassManagerType BasicBlockPass::getPotentialPassManagerType() const {
   return PMT_BasicBlockPassManager;
 }
index 714e0786f6de2a4e70847a7bc72de7c0ee89b8d3..f6dda62fa438796cf0f6c188880bcbfb6b3d1219 100644 (file)
@@ -79,6 +79,9 @@ INITIALIZE_PASS(SingleLoopExtractor, "loop-extract-single",
 Pass *llvm::createLoopExtractorPass() { return new LoopExtractor(); }
 
 bool LoopExtractor::runOnLoop(Loop *L, LPPassManager &LPM) {
+  if (skipOptnoneFunction(L))
+    return false;
+
   // Only visit top-level loops.
   if (L->getParentLoop())
     return false;
index b453f81de9452f98b891eb9acc98c65ac7b69044..04c1499220c8e5e3c4871ab77cd17a09124dcec6 100644 (file)
@@ -2509,6 +2509,9 @@ public:
 }
 
 bool InstCombiner::runOnFunction(Function &F) {
+  if (skipOptnoneFunction(F))
+    return false;
+
   TD = getAnalysisIfAvailable<DataLayout>();
   TLI = &getAnalysis<TargetLibraryInfo>();
   // Minimizing size?
index a3eb07a9f6d66507a76fb5b23f07c597482b9011..a53b23ec446c0d221947b45d424344a9fe03b0d8 100644 (file)
@@ -50,6 +50,9 @@ char ADCE::ID = 0;
 INITIALIZE_PASS(ADCE, "adce", "Aggressive Dead Code Elimination", false, false)
 
 bool ADCE::runOnFunction(Function& F) {
+  if (skipOptnoneFunction(F))
+    return false;
+
   SmallPtrSet<Instruction*, 128> alive;
   SmallVector<Instruction*, 128> worklist;
 
index 995782e1bc6b72bb7ad5d08c15583bf8ee92747f..7615e8f17b6ce8405130121320b405e478df25d0 100644 (file)
@@ -281,6 +281,9 @@ bool CorrelatedValuePropagation::processSwitch(SwitchInst *SI) {
 }
 
 bool CorrelatedValuePropagation::runOnFunction(Function &F) {
+  if (skipOptnoneFunction(F))
+    return false;
+
   LVI = &getAnalysis<LazyValueInfo>();
 
   bool FnChanged = false;
index e8a090af40c316f1d3d09b53d00b926f67b633aa..a4f24df384b6e0eb6227e7752351cb4c79919b89 100644 (file)
@@ -39,6 +39,8 @@ namespace {
       initializeDeadInstEliminationPass(*PassRegistry::getPassRegistry());
     }
     virtual bool runOnBasicBlock(BasicBlock &BB) {
+      if (skipOptnoneFunction(BB))
+        return false;
       TargetLibraryInfo *TLI = getAnalysisIfAvailable<TargetLibraryInfo>();
       bool Changed = false;
       for (BasicBlock::iterator DI = BB.begin(); DI != BB.end(); ) {
@@ -89,6 +91,9 @@ char DCE::ID = 0;
 INITIALIZE_PASS(DCE, "dce", "Dead Code Elimination", false, false)
 
 bool DCE::runOnFunction(Function &F) {
+  if (skipOptnoneFunction(F))
+    return false;
+
   TargetLibraryInfo *TLI = getAnalysisIfAvailable<TargetLibraryInfo>();
 
   // Start out with all of the instructions in the worklist...
index 453dca303d3827f756324d93451c22fcf7b7994b..216f65509ed7a5550a4d6ef5778d980df80b81df 100644 (file)
@@ -54,6 +54,9 @@ namespace {
     }
 
     virtual bool runOnFunction(Function &F) {
+      if (skipOptnoneFunction(F))
+        return false;
+
       AA = &getAnalysis<AliasAnalysis>();
       MD = &getAnalysis<MemoryDependenceAnalysis>();
       DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
index d049dd5a997d1c32356c299b423cc091fd58cfe5..24baee72dc1e099b2a5a803c29059db53c527632 100644 (file)
@@ -552,6 +552,9 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
 
 
 bool EarlyCSE::runOnFunction(Function &F) {
+  if (skipOptnoneFunction(F))
+    return false;
+
   std::vector<StackNode *> nodesToProcess;
 
   TD = getAnalysisIfAvailable<DataLayout>();
index 1041dc9af6890ea2609a788d26e305cc429b83db..955ea1b7fe95428e9c64b33a27e0620ed719eb7b 100644 (file)
@@ -2313,6 +2313,9 @@ bool GVN::processInstruction(Instruction *I) {
 
 /// runOnFunction - This is the main transformation entry point for a function.
 bool GVN::runOnFunction(Function& F) {
+  if (skipOptnoneFunction(F))
+    return false;
+
   if (!NoLoads)
     MD = &getAnalysis<MemoryDependenceAnalysis>();
   DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
index dfcd11fb4c7b130f921f32d268f68d1599b4f78c..723af0f02cbbe27372fba83f18df5bdf6123f4d5 100644 (file)
@@ -1801,6 +1801,9 @@ void IndVarSimplify::SinkUnusedInvariants(Loop *L) {
 //===----------------------------------------------------------------------===//
 
 bool IndVarSimplify::runOnLoop(Loop *L, LPPassManager &LPM) {
+  if (skipOptnoneFunction(L))
+    return false;
+
   // If LoopSimplify form is not available, stay out of trouble. Some notes:
   //  - LSR currently only supports LoopSimplify-form loops. Indvars'
   //    canonicalization can be a pessimization without LSR to "clean up"
index b3ec2fc84c03dac1d18cbb6dc3c4b87b7c3a43cb..087944a2be22a066658822314569e7c7ec773a02 100644 (file)
@@ -148,6 +148,9 @@ FunctionPass *llvm::createJumpThreadingPass() { return new JumpThreading(); }
 /// runOnFunction - Top level algorithm.
 ///
 bool JumpThreading::runOnFunction(Function &F) {
+  if (skipOptnoneFunction(F))
+    return false;
+
   DEBUG(dbgs() << "Jump threading on function '" << F.getName() << "'\n");
   TD = getAnalysisIfAvailable<DataLayout>();
   TLI = &getAnalysis<TargetLibraryInfo>();
index 1ce0cbc1c4a89cb423ebaa669757fb018a0aa997..24ef1727941758aca3d5e5a105ce5b038f45e1d5 100644 (file)
@@ -209,6 +209,9 @@ Pass *llvm::createLICMPass() { return new LICM(); }
 /// times on one loop.
 ///
 bool LICM::runOnLoop(Loop *L, LPPassManager &LPM) {
+  if (skipOptnoneFunction(L))
+    return false;
+
   Changed = false;
 
   // Get our Loop and Alias Analysis information...
index cae1253a959b708f30eb41ebb46e99f3192f0649..b0155458a42f9696728a50af2051b103580efa44 100644 (file)
@@ -130,6 +130,9 @@ bool LoopDeletion::isLoopDead(Loop *L,
 /// NOTE: This entire process relies pretty heavily on LoopSimplify and LCSSA
 /// in order to make various safety checks work.
 bool LoopDeletion::runOnLoop(Loop *L, LPPassManager &LPM) {
+  if (skipOptnoneFunction(L))
+    return false;
+
   // We can only remove the loop if there is a preheader that we can
   // branch from after removing it.
   BasicBlock *preheader = L->getLoopPreheader();
index c89cd74c6eb271c097229e739939210e743aef7e..b9c4046c0c5ee7734272fcf0dc50377a8623958f 100644 (file)
@@ -707,6 +707,9 @@ bool LoopIdiomRecognize::runOnNoncountableLoop() {
 }
 
 bool LoopIdiomRecognize::runOnLoop(Loop *L, LPPassManager &LPM) {
+  if (skipOptnoneFunction(L))
+    return false;
+
   CurLoop = L;
 
   // If the loop could not be converted to canonical form, it must have an
index d6ed9d333009aadc36487cf8f4ab252100ed8547..362b8ab63bea9dc83fd58764efa3406fca4446b9 100644 (file)
@@ -65,6 +65,9 @@ Pass *llvm::createLoopInstSimplifyPass() {
 }
 
 bool LoopInstSimplify::runOnLoop(Loop *L, LPPassManager &LPM) {
+  if (skipOptnoneFunction(L))
+    return false;
+
   DominatorTreeWrapperPass *DTWP =
       getAnalysisIfAvailable<DominatorTreeWrapperPass>();
   DominatorTree *DT = DTWP ? &DTWP->getDomTree() : 0;
index 144aa7e5c584ae4188514d733a2fe2a588971448..7245e0a5c5072a2618e888a63690c13a74f865b8 100644 (file)
@@ -1134,6 +1134,9 @@ bool LoopReroll::reroll(Instruction *IV, Loop *L, BasicBlock *Header,
 }
 
 bool LoopReroll::runOnLoop(Loop *L, LPPassManager &LPM) {
+  if (skipOptnoneFunction(L))
+    return false;
+
   AA = &getAnalysis<AliasAnalysis>();
   LI = &getAnalysis<LoopInfo>();
   SE = &getAnalysis<ScalarEvolution>();
index 9af053b682fe8c33a4cde23aa943756fcfc5d7aa..04c3b9877b477fa432da1f3939cc8c7bc10f2485 100644 (file)
@@ -79,6 +79,9 @@ Pass *llvm::createLoopRotatePass() { return new LoopRotate(); }
 /// Rotate Loop L as many times as possible. Return true if
 /// the loop is rotated at least once.
 bool LoopRotate::runOnLoop(Loop *L, LPPassManager &LPM) {
+  if (skipOptnoneFunction(L))
+    return false;
+
   LI = &getAnalysis<LoopInfo>();
   TTI = &getAnalysis<TargetTransformInfo>();
 
index 734d8451fb70b104a19b6c4453b87661a1477f09..b25943011f38b9fe9410b5f02d6448b05081ace4 100644 (file)
@@ -4912,6 +4912,9 @@ void LoopStrengthReduce::getAnalysisUsage(AnalysisUsage &AU) const {
 }
 
 bool LoopStrengthReduce::runOnLoop(Loop *L, LPPassManager & /*LPM*/) {
+  if (skipOptnoneFunction(L))
+    return false;
+
   bool Changed = false;
 
   // Run the main LSR transformation.
index 658413497a0f03190b9158b93cf315f8f68891c2..450614684efc976c6fc0dc7e4db6d21ca841998e 100644 (file)
@@ -147,6 +147,9 @@ static unsigned ApproximateLoopSize(const Loop *L, unsigned &NumCalls,
 }
 
 bool LoopUnroll::runOnLoop(Loop *L, LPPassManager &LPM) {
+  if (skipOptnoneFunction(L))
+    return false;
+
   LoopInfo *LI = &getAnalysis<LoopInfo>();
   ScalarEvolution *SE = &getAnalysis<ScalarEvolution>();
   const TargetTransformInfo &TTI = getAnalysis<TargetTransformInfo>();
index 32c6412ef757b7b9a8cf72d9d90d942b0f766c42..cfadf9a9d4abcc3312de1c6d6f03385bdc98b060 100644 (file)
@@ -382,6 +382,9 @@ static Value *FindLIVLoopCondition(Value *Cond, Loop *L, bool &Changed) {
 }
 
 bool LoopUnswitch::runOnLoop(Loop *L, LPPassManager &LPM_Ref) {
+  if (skipOptnoneFunction(L))
+    return false;
+
   LI = &getAnalysis<LoopInfo>();
   LPM = &LPM_Ref;
   DominatorTreeWrapperPass *DTWP =
index 8ced4946c83225ffa594ca1b13f098225f314ac1..b28c29f40d9b68c1e3167b43efbfc9ecfeee83e1 100644 (file)
@@ -112,6 +112,8 @@ namespace {
       initializeLowerAtomicPass(*PassRegistry::getPassRegistry());
     }
     bool runOnBasicBlock(BasicBlock &BB) {
+      if (skipOptnoneFunction(BB))
+        return false;
       bool Changed = false;
       for (BasicBlock::iterator DI = BB.begin(), DE = BB.end(); DI != DE; ) {
         Instruction *Inst = DI++;
index d46b1ddcddedafb3c2d8adc8ec1a6cb487e600ae..3c24e6d3643a0bed74473a612f1484198cd5e699 100644 (file)
@@ -1010,6 +1010,9 @@ bool MemCpyOpt::iterateOnFunction(Function &F) {
 // function.
 //
 bool MemCpyOpt::runOnFunction(Function &F) {
+  if (skipOptnoneFunction(F))
+    return false;
+
   bool MadeChange = false;
   MD = &getAnalysis<MemoryDependenceAnalysis>();
   TD = getAnalysisIfAvailable<DataLayout>();
index 7d31de4d741dabfc8edde56a7e7330e211ab85cf..1a387f60e1915c3306f6106cbe74a35dba09c635 100644 (file)
@@ -1971,6 +1971,9 @@ void Reassociate::ReassociateExpression(BinaryOperator *I) {
 }
 
 bool Reassociate::runOnFunction(Function &F) {
+  if (skipOptnoneFunction(F))
+    return false;
+
   // Calculate the rank map for F
   BuildRankMap(F);
 
index 43647207c2cc0ffefb445bb43e9e09076a2846f6..02c64d9ea88ba08f2923c4ce6731e607d090762c 100644 (file)
@@ -1553,6 +1553,9 @@ static void DeleteInstructionInBlock(BasicBlock *BB) {
 // and return true if the function was modified.
 //
 bool SCCP::runOnFunction(Function &F) {
+  if (skipOptnoneFunction(F))
+    return false;
+
   DEBUG(dbgs() << "SCCP on function '" << F.getName() << "'\n");
   const DataLayout *TD = getAnalysisIfAvailable<DataLayout>();
   const TargetLibraryInfo *TLI = &getAnalysis<TargetLibraryInfo>();
index 08a9bc09267180efe950aedc9ebca5a0cf735821..bed53b832a9c65891f5c390a3c7f4f2fa1e9838f 100644 (file)
@@ -3572,6 +3572,9 @@ namespace {
 }
 
 bool SROA::runOnFunction(Function &F) {
+  if (skipOptnoneFunction(F))
+    return false;
+
   DEBUG(dbgs() << "SROA function: " << F.getName() << "\n");
   C = &F.getContext();
   DL = getAnalysisIfAvailable<DataLayout>();
index a3c74cd43e917acd62716a98a47da27030694958..a8186ae3428c8474ba5069f79d3f3ea998737014 100644 (file)
@@ -1020,6 +1020,9 @@ ConvertScalar_InsertValue(Value *SV, Value *Old,
 
 
 bool SROA::runOnFunction(Function &F) {
+  if (skipOptnoneFunction(F))
+    return false;
+
   TD = getAnalysisIfAvailable<DataLayout>();
 
   bool Changed = performPromotion(F);
index 8371f6d35279ebd05879b4b0f2688266090e311d..f1e3ac573ecbb842c158a8e9b614091ee22b7784 100644 (file)
@@ -168,6 +168,9 @@ static bool iterativelySimplifyCFG(Function &F, const TargetTransformInfo &TTI,
 // simplify the CFG.
 //
 bool CFGSimplifyPass::runOnFunction(Function &F) {
+  if (skipOptnoneFunction(F))
+    return false;
+
   const TargetTransformInfo &TTI = getAnalysis<TargetTransformInfo>();
   const DataLayout *TD = getAnalysisIfAvailable<DataLayout>();
   bool EverChanged = removeUnreachableBlocks(F);
index 9fb8ddc3d2c1c15475efd0cb73cb66e36c70c8cf..351aee058ba846fa69740d18d871d5b54d53a428 100644 (file)
@@ -171,6 +171,9 @@ struct AllocaCaptureTracker : public CaptureTracker {
 } // end anonymous namespace
 
 bool TailCallElim::runOnFunction(Function &F) {
+  if (skipOptnoneFunction(F))
+    return false;
+
   // If this function is a varargs function, we won't be able to PHI the args
   // right, so don't even try to convert it...
   if (F.getFunctionType()->isVarArg()) return false;
index ffbf81b942e87b7a918ee348d2c38deb89309cac..0cc1f3962a4491acc4db1946f88deb05a6a4a732 100644 (file)
@@ -388,6 +388,8 @@ namespace {
     void combineMetadata(Instruction *K, const Instruction *J);
 
     bool vectorizeBB(BasicBlock &BB) {
+      if (skipOptnoneFunction(BB))
+        return false;
       if (!DT->isReachableFromEntry(&BB)) {
         DEBUG(dbgs() << "BBV: skipping unreachable " << BB.getName() <<
               " in " << BB.getParent()->getName() << "\n");
@@ -429,6 +431,8 @@ namespace {
     }
 
     virtual bool runOnBasicBlock(BasicBlock &BB) {
+      // OptimizeNone check deferred to vectorizeBB().
+
       AA = &getAnalysis<AliasAnalysis>();
       DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
       SE = &getAnalysis<ScalarEvolution>();
index 80d9ffccafbba7f4d2f6dcfd4b21d3025c557c11..9eadfb58bea9ae0dd8bba7a75b88655f72459650 100644 (file)
@@ -1771,6 +1771,9 @@ struct SLPVectorizer : public FunctionPass {
   DominatorTree *DT;
 
   virtual bool runOnFunction(Function &F) {
+    if (skipOptnoneFunction(F))
+      return false;
+
     SE = &getAnalysis<ScalarEvolution>();
     DL = getAnalysisIfAvailable<DataLayout>();
     TTI = &getAnalysis<TargetTransformInfo>();
diff --git a/test/Feature/optnone-opt.ll b/test/Feature/optnone-opt.ll
new file mode 100644 (file)
index 0000000..f83e68c
--- /dev/null
@@ -0,0 +1,74 @@
+; RUN: opt     -S -debug %s 2>&1 | FileCheck %s --check-prefix=OPT-O0
+; RUN: opt -O1 -S -debug %s 2>&1 | FileCheck %s --check-prefix=OPT-O1
+; RUN: opt -O2 -S -debug %s 2>&1 | FileCheck %s --check-prefix=OPT-O1 --check-prefix=OPT-O2O3
+; RUN: opt -O3 -S -debug %s 2>&1 | FileCheck %s --check-prefix=OPT-O1 --check-prefix=OPT-O2O3
+; RUN: opt -bb-vectorize -dce -die -loweratomic -S -debug %s 2>&1 | FileCheck %s --check-prefix=OPT-MORE
+; RUN: opt -indvars -licm -loop-deletion -loop-extract -loop-idiom -loop-instsimplify -loop-reduce -loop-reroll -loop-rotate -loop-unroll -loop-unswitch -S -debug %s 2>&1 | FileCheck %s --check-prefix=OPT-LOOP
+
+; REQUIRES: asserts
+
+; This test verifies that we don't run target independent IR-level
+; optimizations on optnone functions.
+
+; Function Attrs: noinline optnone
+define i32 @_Z3fooi(i32 %x) #0 {
+entry:
+  %x.addr = alloca i32, align 4
+  store i32 %x, i32* %x.addr, align 4
+  br label %while.cond
+
+while.cond:                                       ; preds = %while.body, %entry
+  %0 = load i32* %x.addr, align 4
+  %dec = add nsw i32 %0, -1
+  store i32 %dec, i32* %x.addr, align 4
+  %tobool = icmp ne i32 %0, 0
+  br i1 %tobool, label %while.body, label %while.end
+
+while.body:                                       ; preds = %while.cond
+  br label %while.cond
+
+while.end:                                        ; preds = %while.cond
+  ret i32 0
+}
+
+attributes #0 = { optnone noinline }
+
+; Nothing that runs at -O0 gets skipped.
+; OPT-O0-NOT: Skipping pass
+
+; IR passes run at -O1 and higher.
+; OPT-O1-DAG: Skipping pass 'Aggressive Dead Code Elimination'
+; OPT-O1-DAG: Skipping pass 'Combine redundant instructions'
+; OPT-O1-DAG: Skipping pass 'Dead Store Elimination'
+; OPT-O1-DAG: Skipping pass 'Early CSE'
+; OPT-O1-DAG: Skipping pass 'Jump Threading'
+; OPT-O1-DAG: Skipping pass 'MemCpy Optimization'
+; OPT-O1-DAG: Skipping pass 'Reassociate expressions'
+; OPT-O1-DAG: Skipping pass 'Simplify the CFG'
+; OPT-O1-DAG: Skipping pass 'Sparse Conditional Constant Propagation'
+; OPT-O1-DAG: Skipping pass 'SROA'
+; OPT-O1-DAG: Skipping pass 'Tail Call Elimination'
+; OPT-O1-DAG: Skipping pass 'Value Propagation'
+
+; Additional IR passes run at -O2 and higher.
+; OPT-O2O3-DAG: Skipping pass 'Global Value Numbering'
+; OPT-O2O3-DAG: Skipping pass 'SLP Vectorizer'
+
+; Additional IR passes that opt doesn't turn on by default.
+; OPT-MORE-DAG: Skipping pass 'Basic-Block Vectorization'
+; OPT-MORE-DAG: Skipping pass 'Dead Code Elimination'
+; OPT-MORE-DAG: Skipping pass 'Dead Instruction Elimination'
+; OPT-MORE-DAG: Skipping pass 'Lower atomic intrinsics
+
+; Loop IR passes that opt doesn't turn on by default.
+; OPT-LOOP-DAG: Skipping pass 'Delete dead loops'
+; OPT-LOOP-DAG: Skipping pass 'Extract loops into new functions'
+; OPT-LOOP-DAG: Skipping pass 'Induction Variable Simplification'
+; OPT-LOOP-DAG: Skipping pass 'Loop Invariant Code Motion'
+; OPT-LOOP-DAG: Skipping pass 'Loop Strength Reduction'
+; OPT-LOOP-DAG: Skipping pass 'Recognize loop idioms'
+; OPT-LOOP-DAG: Skipping pass 'Reroll loops'
+; OPT-LOOP-DAG: Skipping pass 'Rotate Loops'
+; OPT-LOOP-DAG: Skipping pass 'Simplify instructions in loops'
+; OPT-LOOP-DAG: Skipping pass 'Unroll loops'
+; OPT-LOOP-DAG: Skipping pass 'Unswitch loops'