diff options
-rw-r--r-- | include/llvm/MC/MCCodeGenInfo.h | 3 | ||||
-rw-r--r-- | include/llvm/Target/TargetMachine.h | 6 | ||||
-rw-r--r-- | lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp | 44 | ||||
-rw-r--r-- | lib/Target/TargetMachine.cpp | 5 | ||||
-rw-r--r-- | test/CodeGen/X86/isel-optnone.ll | 42 |
5 files changed, 99 insertions, 1 deletions
diff --git a/include/llvm/MC/MCCodeGenInfo.h b/include/llvm/MC/MCCodeGenInfo.h index d1765e1..84ce934 100644 --- a/include/llvm/MC/MCCodeGenInfo.h +++ b/include/llvm/MC/MCCodeGenInfo.h @@ -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 diff --git a/include/llvm/Target/TargetMachine.h b/include/llvm/Target/TargetMachine.h index 91e4715..11b0f5f 100644 --- a/include/llvm/Target/TargetMachine.h +++ b/include/llvm/Target/TargetMachine.h @@ -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; } diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index 15f2ee2..50d6402 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -223,6 +223,44 @@ defaultListDAGScheduler("default", "Best scheduler for the target", namespace llvm { //===--------------------------------------------------------------------===// + /// \brief This class is used by SelectionDAGISel to temporarily override + /// the optimization level on a per-function basis. + class OptLevelChanger { + SelectionDAGISel &IS; + CodeGenOpt::Level SavedOptLevel; + bool SavedFastISel; + + public: + OptLevelChanger(SelectionDAGISel &ISel, + CodeGenOpt::Level NewOptLevel) : IS(ISel) { + SavedOptLevel = IS.OptLevel; + if (NewOptLevel == SavedOptLevel) + return; + IS.OptLevel = NewOptLevel; + IS.TM.setOptLevel(NewOptLevel); + SavedFastISel = IS.TM.Options.EnableFastISel; + if (NewOptLevel == CodeGenOpt::None) + IS.TM.setFastISel(true); + 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); + IS.TM.setFastISel(SavedFastISel); + } + }; + + //===--------------------------------------------------------------------===// /// createDefaultScheduler - This creates an instruction scheduler appropriate /// for the target. ScheduleDAGSDNodes* createDefaultScheduler(SelectionDAGISel *IS, @@ -370,6 +408,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); diff --git a/lib/Target/TargetMachine.cpp b/lib/Target/TargetMachine.cpp index df4a03c..cb42e83 100644 --- a/lib/Target/TargetMachine.cpp +++ b/lib/Target/TargetMachine.cpp @@ -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/X86/isel-optnone.ll b/test/CodeGen/X86/isel-optnone.ll new file mode 100644 index 0000000..d2f0628 --- /dev/null +++ b/test/CodeGen/X86/isel-optnone.ll @@ -0,0 +1,42 @@ +; RUN: llc -O2 -march=x86 < %s | FileCheck %s + +define i32* @fooOptnone(i32* %p, i32* %q, i32** %z) #0 { +entry: + %r = load i32* %p + %s = load i32* %q + %y = load i32** %z + + %t0 = add i32 %r, %s + %t1 = add i32 %t0, 1 + %t2 = getelementptr i32* %y, i32 1 + %t3 = getelementptr i32* %t2, i32 %t1 + + ret i32* %t3 + +; 'optnone' should use fast-isel which will not produce 'lea'. +; CHECK-LABEL: fooOptnone: +; CHECK-NOT: lea +; CHECK: ret +} + +define i32* @fooNormal(i32* %p, i32* %q, i32** %z) #1 { +entry: + %r = load i32* %p + %s = load i32* %q + %y = load i32** %z + + %t0 = add i32 %r, %s + %t1 = add i32 %t0, 1 + %t2 = getelementptr i32* %y, i32 1 + %t3 = getelementptr i32* %t2, i32 %t1 + + ret i32* %t3 + +; Normal ISel will produce 'lea'. +; CHECK-LABEL: fooNormal: +; CHECK: lea +; CHECK: ret +} + +attributes #0 = { nounwind optnone noinline } +attributes #1 = { nounwind } |