aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/llvm/MC/MCCodeGenInfo.h3
-rw-r--r--include/llvm/Target/TargetMachine.h6
-rw-r--r--lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp44
-rw-r--r--lib/Target/TargetMachine.cpp5
-rw-r--r--test/CodeGen/X86/isel-optnone.ll42
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 }