Teach ISel not to optimize 'optnone' functions.
authorPaul Robinson <paul_robinson@playstation.sony.com>
Thu, 21 Nov 2013 06:33:32 +0000 (06:33 +0000)
committerPaul Robinson <paul_robinson@playstation.sony.com>
Thu, 21 Nov 2013 06:33:32 +0000 (06:33 +0000)
Based on work by Andrea Di Biagio.

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

include/llvm/MC/MCCodeGenInfo.h
include/llvm/Target/TargetMachine.h
lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
lib/Target/TargetMachine.cpp
test/CodeGen/Generic/isel-optnone.ll [new file with mode: 0644]

index d1765e1240a47c536126b13e4c48e26daccacc64..84ce934d822eeb0523bdc260bd0700955ff8273b 100644 (file)
@@ -42,6 +42,9 @@ namespace llvm {
     CodeModel::Model getCodeModel() const { return CMModel; }
 
     CodeGenOpt::Level getOptLevel() const { return OptLevel; }
+
+    // Allow overriding OptLevel on a per-function basis.
+    void setOptLevel(CodeGenOpt::Level Level) { OptLevel = Level; }
   };
 } // namespace llvm
 
index 91e4715eea3afe027e5f58de9c2ff1c7ed80fd31..11b0f5fb77fcd30fefcf2a9f6b3f7df8d934e955 100644 (file)
@@ -75,7 +75,8 @@ protected: // Can only create subclasses.
   std::string TargetFS;
 
   /// CodeGenInfo - Low level target information such as relocation model.
-  const MCCodeGenInfo *CodeGenInfo;
+  /// Non-const to allow resetting optimization level per-function.
+  MCCodeGenInfo *CodeGenInfo;
 
   /// AsmInfo - Contains target specific asm information.
   ///
@@ -213,6 +214,9 @@ public:
   /// Default, or Aggressive.
   CodeGenOpt::Level getOptLevel() const;
 
+  /// \brief Overrides the optimization level.
+  void setOptLevel(CodeGenOpt::Level Level) const;
+
   void setFastISel(bool Enable) { Options.EnableFastISel = Enable; }
 
   bool shouldPrintMachineCode() const { return Options.PrintMachineCode; }
index 91cb125dc89bbd50c61e7d7231d1e250a4c7a165..faca3ee823ce8bddc38f2caf3db258220c508a2c 100644 (file)
@@ -222,6 +222,39 @@ defaultListDAGScheduler("default", "Best scheduler for the target",
                         createDefaultScheduler);
 
 namespace llvm {
+  //===--------------------------------------------------------------------===//
+  /// \brief This struct is used by SelectionDAGISel to temporarily override
+  /// the optimization level on a per-function basis.
+  class OptLevelChanger {
+    SelectionDAGISel &IS;
+    CodeGenOpt::Level SavedOptLevel;
+
+  public:
+    OptLevelChanger(SelectionDAGISel &ISel,
+                    CodeGenOpt::Level NewOptLevel) : IS(ISel) {
+      SavedOptLevel = IS.OptLevel;
+      if (NewOptLevel == SavedOptLevel)
+        return;
+      IS.OptLevel = NewOptLevel;
+      IS.TM.setOptLevel(NewOptLevel);
+      DEBUG(dbgs() << "\nChanging optimization level for Function "
+            << IS.MF->getFunction()->getName() << "\n");
+      DEBUG(dbgs() << "\tBefore: -O" << SavedOptLevel
+            << " ; After: -O" << NewOptLevel << "\n");
+    }
+
+    ~OptLevelChanger() {
+      if (IS.OptLevel == SavedOptLevel)
+        return;
+      DEBUG(dbgs() << "\nRestoring optimization level for Function "
+            << IS.MF->getFunction()->getName() << "\n");
+      DEBUG(dbgs() << "\tBefore: -O" << IS.OptLevel
+            << " ; After: -O" << SavedOptLevel << "\n");
+      IS.OptLevel = SavedOptLevel;
+      IS.TM.setOptLevel(SavedOptLevel);
+    }
+  };
+
   //===--------------------------------------------------------------------===//
   /// createDefaultScheduler - This creates an instruction scheduler appropriate
   /// for the target.
@@ -370,6 +403,12 @@ bool SelectionDAGISel::runOnMachineFunction(MachineFunction &mf) {
   ST.resetSubtargetFeatures(MF);
   TM.resetTargetOptions(MF);
 
+  // Reset OptLevel to None for optnone functions.
+  CodeGenOpt::Level NewOptLevel = OptLevel;
+  if (Fn.hasFnAttribute(Attribute::OptimizeNone))
+    NewOptLevel = CodeGenOpt::None;
+  OptLevelChanger OLC(*this, NewOptLevel);
+
   DEBUG(dbgs() << "\n\n\n=== " << Fn.getName() << "\n");
 
   SplitCriticalSideEffectEdges(const_cast<Function&>(Fn), this);
@@ -948,7 +987,7 @@ static void collectFailStats(const Instruction *I) {
 void SelectionDAGISel::SelectAllBasicBlocks(const Function &Fn) {
   // Initialize the Fast-ISel state, if needed.
   FastISel *FastIS = 0;
-  if (TM.Options.EnableFastISel)
+  if (TM.Options.EnableFastISel || Fn.hasFnAttribute(Attribute::OptimizeNone))
     FastIS = getTargetLowering()->createFastISel(*FuncInfo, LibInfo);
 
   // Iterate over all basic blocks in the function.
index df4a03c9e8ba964e1a6fcc78de06ee735f6557f7..cb42e8311b87953f617a437a454fe281a06ad838 100644 (file)
@@ -164,6 +164,11 @@ CodeGenOpt::Level TargetMachine::getOptLevel() const {
   return CodeGenInfo->getOptLevel();
 }
 
+void TargetMachine::setOptLevel(CodeGenOpt::Level Level) const {
+  if (CodeGenInfo)
+    CodeGenInfo->setOptLevel(Level);
+}
+
 bool TargetMachine::getAsmVerbosityDefault() {
   return AsmVerbosityDefault;
 }
diff --git a/test/CodeGen/Generic/isel-optnone.ll b/test/CodeGen/Generic/isel-optnone.ll
new file mode 100644 (file)
index 0000000..405a1bc
--- /dev/null
@@ -0,0 +1,31 @@
+; RUN: llc -debug < %s -o /dev/null 2>&1 | FileCheck %s
+
+; Verify that the backend correctly overrides the optimization level
+; of optnone functions during instruction selection.
+
+define float @foo(float %x) #0 {
+entry:
+  %add = fadd fast float %x, %x
+  %add1 = fadd fast float %add, %x
+  ret float %add1
+}
+
+; CHECK-NOT: Changing optimization level for Function foo
+; CHECK-NOT: Restoring optimization level for Function foo
+
+; Function Attrs: noinline optnone
+define float @fooWithOptnone(float %x) #1 {
+entry:
+  %add = fadd fast float %x, %x
+  %add1 = fadd fast float %add, %x
+  ret float %add1
+}
+
+; CHECK: Changing optimization level for Function fooWithOptnone
+; CHECK-NEXT: Before: -O2 ; After: -O0
+
+; CHECK: Restoring optimization level for Function fooWithOptnone
+; CHECK-NEXT: Before: -O0 ; After: -O2
+
+attributes #0 = { "unsafe-fp-math"="true" }
+attributes #1 = { noinline optnone "unsafe-fp-math"="true" }