From 16c7e0b48cd0a34565aae663caee83e5a641823a Mon Sep 17 00:00:00 2001 From: Paul Robinson Date: Fri, 22 Nov 2013 19:11:24 +0000 Subject: [PATCH] Teach ISel not to optimize 'optnone' functions (revised). Improvements over r195317: - Set/restore EnableFastISel flag instead of just running FastISel within SelectAllBasicBlocks; the flag is checked in various places, and FastISel won't run properly if those places don't do the right thing. - Test looks for normal ISel versus FastISel behavior, and not something more subtle that doesn't work everywhere. Based on work by Andrea Di Biagio. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@195491 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/MC/MCCodeGenInfo.h | 3 ++ include/llvm/Target/TargetMachine.h | 6 ++- lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp | 44 +++++++++++++++++++ lib/Target/TargetMachine.cpp | 5 +++ test/CodeGen/X86/isel-optnone.ll | 42 ++++++++++++++++++ 5 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 test/CodeGen/X86/isel-optnone.ll diff --git a/include/llvm/MC/MCCodeGenInfo.h b/include/llvm/MC/MCCodeGenInfo.h index d1765e1240a..84ce934d822 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 4c1f927869f..eed07065e81 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 91cb125dc89..c0e8a72aa34 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -222,6 +222,44 @@ defaultListDAGScheduler("default", "Best scheduler for the target", createDefaultScheduler); 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. @@ -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(Fn), this); diff --git a/lib/Target/TargetMachine.cpp b/lib/Target/TargetMachine.cpp index b367287b530..9ba78bce7f9 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 00000000000..d2f062832e0 --- /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 }