Index: include/llvm/CodeGen/CommandFlags.h =================================================================== --- include/llvm/CodeGen/CommandFlags.h +++ include/llvm/CodeGen/CommandFlags.h @@ -230,6 +230,7 @@ TargetOptions Options; Options.LessPreciseFPMADOption = EnableFPMAD; Options.NoFramePointerElim = DisableFPElim; + Options.NoFramePointerElimOverride = DisableFPElim.getNumOccurrences() > 0; Options.AllowFPOpFusion = FuseFPOps; Options.UnsafeFPMath = EnableUnsafeFPMath; Options.NoInfsFPMath = EnableNoInfsFPMath; @@ -287,15 +288,4 @@ return Features.getString(); } -static inline void overrideFunctionAttributes(StringRef CPU, StringRef Features, - Module &M) { - for (auto &F : M) { - if (!CPU.empty()) - llvm::overrideFunctionAttribute("target-cpu", CPU, F); - - if (!Features.empty()) - llvm::overrideFunctionAttribute("target-features", Features, F); - } -} - #endif Index: include/llvm/IR/Function.h =================================================================== --- include/llvm/IR/Function.h +++ include/llvm/IR/Function.h @@ -591,9 +591,6 @@ return F ? &F->getValueSymbolTable() : nullptr; } -/// \brief Overwrite attribute Kind in function F. -void overrideFunctionAttribute(StringRef Kind, StringRef Value, Function &F); - } // End llvm namespace #endif Index: include/llvm/Target/TargetFrameLowering.h =================================================================== --- include/llvm/Target/TargetFrameLowering.h +++ include/llvm/Target/TargetFrameLowering.h @@ -173,6 +173,9 @@ return false; } + /// Return true if the target needs to disable frame pointer elimination. + virtual bool noFramePointerElim(const MachineFunction &MF) const; + /// hasFP - Return true if the specified function should have a dedicated /// frame pointer register. For most targets this is true only if the function /// has variable sized allocas or if frame pointer elimination is disabled. Index: include/llvm/Target/TargetOptions.h =================================================================== --- include/llvm/Target/TargetOptions.h +++ include/llvm/Target/TargetOptions.h @@ -20,6 +20,7 @@ namespace llvm { class MachineFunction; + class Module; class StringRef; namespace FloatABI { @@ -60,6 +61,7 @@ public: TargetOptions() : PrintMachineCode(false), NoFramePointerElim(false), + NoFramePointerElimOverride(false), LessPreciseFPMADOption(false), UnsafeFPMath(false), NoInfsFPMath(false), NoNaNsFPMath(false), HonorSignDependentRoundingFPMathOption(false), @@ -84,6 +86,9 @@ /// elimination optimization, this option should disable it. unsigned NoFramePointerElim : 1; + /// This flag is true when "disable-fp-elim" appeared on the command line. + unsigned NoFramePointerElimOverride : 1; + /// DisableFramePointerElim - This returns true if frame pointer elimination /// optimization should be disabled for the given machine function. bool DisableFramePointerElim(const MachineFunction &MF) const; @@ -222,6 +227,15 @@ MCTargetOptions MCOptions; }; +/// \brief Set function attributes of functions in Module M based on CPU, +/// Features, and Options. +/// If AlwaysRecordAttrs is true, it will always record the function attributes +/// in Options regardless of whether those attributes were specified on the +/// tool's command line. +void setFunctionAttributes(StringRef CPU, StringRef Features, + const TargetOptions &Options, Module &M, + bool AlwaysRecordAttrs); + // Comparison operators: Index: lib/CodeGen/TargetFrameLoweringImpl.cpp =================================================================== --- lib/CodeGen/TargetFrameLoweringImpl.cpp +++ lib/CodeGen/TargetFrameLoweringImpl.cpp @@ -14,6 +14,7 @@ #include "llvm/Target/TargetFrameLowering.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" +#include "llvm/IR/Function.h" #include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Target/TargetSubtargetInfo.h" #include @@ -22,6 +23,12 @@ TargetFrameLowering::~TargetFrameLowering() { } +/// The default implementation just looks at attribute "no-frame-pointer-elim". +bool TargetFrameLowering::noFramePointerElim(const MachineFunction &MF) const { + auto Attr = MF.getFunction()->getFnAttribute("no-frame-pointer-elim"); + return Attr.getValueAsString() == "true"; +} + /// getFrameIndexOffset - Returns the displacement from the frame register to /// the stack frame of the specified index. This is the default implementation /// which is overridden for some targets. Index: lib/CodeGen/TargetOptionsImpl.cpp =================================================================== --- lib/CodeGen/TargetOptionsImpl.cpp +++ lib/CodeGen/TargetOptionsImpl.cpp @@ -12,23 +12,26 @@ //===----------------------------------------------------------------------===// #include "llvm/IR/Function.h" +#include "llvm/IR/Module.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" +#include "llvm/Target/TargetFrameLowering.h" #include "llvm/Target/TargetOptions.h" +#include "llvm/Target/TargetSubtargetInfo.h" using namespace llvm; /// DisableFramePointerElim - This returns true if frame pointer elimination /// optimization should be disabled for the given machine function. bool TargetOptions::DisableFramePointerElim(const MachineFunction &MF) const { - // Check to see if we should eliminate non-leaf frame pointers and then - // check to see if we should eliminate all frame pointers. - if (MF.getFunction()->hasFnAttribute("no-frame-pointer-elim-non-leaf") && - !NoFramePointerElim) { - const MachineFrameInfo *MFI = MF.getFrameInfo(); - return MFI->hasCalls(); - } + // Check to see if we should eliminate all frame pointers. + if (MF.getSubtarget().getFrameLowering()->noFramePointerElim(MF)) + return true; + + // Check to see if we should eliminate non-leaf frame pointers. + if (MF.getFunction()->hasFnAttribute("no-frame-pointer-elim-non-leaf")) + return MF.getFrameInfo()->hasCalls(); - return NoFramePointerElim; + return false; } /// LessPreciseFPMAD - This flag return true when -enable-fp-mad option @@ -51,3 +54,30 @@ StringRef TargetOptions::getTrapFunctionName() const { return TrapFuncName; } + + +void llvm::setFunctionAttributes(StringRef CPU, StringRef Features, + const TargetOptions &Options, Module &M, + bool AlwaysRecordAttrs) { + for (auto &F : M) { + auto &Ctx = F.getContext(); + AttributeSet Attrs = F.getAttributes(), NewAttrs; + + if (!CPU.empty()) + NewAttrs = NewAttrs.addAttribute(Ctx, AttributeSet::FunctionIndex, + "target-cpu", CPU); + + if (!Features.empty()) + NewAttrs = NewAttrs.addAttribute(Ctx, AttributeSet::FunctionIndex, + "target-features", Features); + + if (Options.NoFramePointerElimOverride || AlwaysRecordAttrs) + NewAttrs = NewAttrs.addAttribute( + Ctx, AttributeSet::FunctionIndex, "no-frame-pointer-elim", + Options.NoFramePointerElim ? "true" : "false"); + + // Let NewAttrs override Attrs. + NewAttrs = Attrs.addAttributes(Ctx, AttributeSet::FunctionIndex, NewAttrs); + F.setAttributes(NewAttrs); + } +} Index: lib/ExecutionEngine/ExecutionEngineBindings.cpp =================================================================== --- lib/ExecutionEngine/ExecutionEngineBindings.cpp +++ lib/ExecutionEngine/ExecutionEngineBindings.cpp @@ -179,9 +179,13 @@ TargetOptions targetOptions; targetOptions.NoFramePointerElim = options.NoFramePointerElim; targetOptions.EnableFastISel = options.EnableFastISel; + std::unique_ptr Mod(unwrap(M)); + + if (Mod) + setFunctionAttributes("", "", targetOptions, *Mod, true); std::string Error; - EngineBuilder builder(std::unique_ptr(unwrap(M))); + EngineBuilder builder(std::move(Mod)); builder.setEngineKind(EngineKind::JIT) .setErrorStr(&Error) .setOptLevel((CodeGenOpt::Level)options.OptLevel) Index: lib/IR/Function.cpp =================================================================== --- lib/IR/Function.cpp +++ lib/IR/Function.cpp @@ -959,19 +959,6 @@ setValueSubclassData(PDData); } -void llvm::overrideFunctionAttribute(StringRef Kind, StringRef Value, - Function &F) { - auto &Ctx = F.getContext(); - AttributeSet Attrs = F.getAttributes(), AttrsToRemove; - - AttrsToRemove = - AttrsToRemove.addAttribute(Ctx, AttributeSet::FunctionIndex, Kind); - Attrs = Attrs.removeAttributes(Ctx, AttributeSet::FunctionIndex, - AttrsToRemove); - Attrs = Attrs.addAttribute(Ctx, AttributeSet::FunctionIndex, Kind, Value); - F.setAttributes(Attrs); -} - void Function::setEntryCount(uint64_t Count) { MDBuilder MDB(getContext()); setMetadata(LLVMContext::MD_prof, MDB.createFunctionEntryCount(Count)); Index: lib/Target/ARM/ARMFastISel.cpp =================================================================== --- lib/Target/ARM/ARMFastISel.cpp +++ lib/Target/ARM/ARMFastISel.cpp @@ -3065,23 +3065,9 @@ namespace llvm { FastISel *ARM::createFastISel(FunctionLoweringInfo &funcInfo, const TargetLibraryInfo *libInfo) { - const TargetMachine &TM = funcInfo.MF->getTarget(); - const ARMSubtarget &STI = - static_cast(funcInfo.MF->getSubtarget()); - // Thumb2 support on iOS; ARM support on iOS, Linux and NaCl. - bool UseFastISel = false; - UseFastISel |= STI.isTargetMachO() && !STI.isThumb1Only(); - UseFastISel |= STI.isTargetLinux() && !STI.isThumb(); - UseFastISel |= STI.isTargetNaCl() && !STI.isThumb(); - - if (UseFastISel) { - // iOS always has a FP for backtracking, force other targets - // to keep their FP when doing FastISel. The emitted code is - // currently superior, and in cases like test-suite's lencod - // FastISel isn't quite correct when FP is eliminated. - TM.Options.NoFramePointerElim = true; + if (funcInfo.MF->getSubtarget().useFastISel()) return new ARMFastISel(funcInfo, libInfo); - } + return nullptr; } } Index: lib/Target/ARM/ARMFrameLowering.h =================================================================== --- lib/Target/ARM/ARMFrameLowering.h +++ lib/Target/ARM/ARMFrameLowering.h @@ -43,6 +43,8 @@ const std::vector &CSI, const TargetRegisterInfo *TRI) const override; + bool noFramePointerElim(const MachineFunction &MF) const override; + bool hasFP(const MachineFunction &MF) const override; bool hasReservedCallFrame(const MachineFunction &MF) const override; bool canSimplifyCallFramePseudos(const MachineFunction &MF) const override; Index: lib/Target/ARM/ARMFrameLowering.cpp =================================================================== --- lib/Target/ARM/ARMFrameLowering.cpp +++ lib/Target/ARM/ARMFrameLowering.cpp @@ -43,6 +43,14 @@ : TargetFrameLowering(StackGrowsDown, sti.getStackAlignment(), 0, 4), STI(sti) {} +bool ARMFrameLowering::noFramePointerElim(const MachineFunction &MF) const { + // iOS always has a FP for backtracking, force other targets to keep their FP + // when doing FastISel. The emitted code is currently superior, and in cases + // like test-suite's lencod FastISel isn't quite correct when FP is eliminated. + return TargetFrameLowering::noFramePointerElim(MF) || + MF.getSubtarget().useFastISel(); +} + /// hasFP - Return true if the specified function should have a dedicated frame /// pointer register. This is true if the function has variable sized allocas /// or if frame pointer elimination is disabled. Index: lib/Target/ARM/ARMSubtarget.h =================================================================== --- lib/Target/ARM/ARMSubtarget.h +++ lib/Target/ARM/ARMSubtarget.h @@ -450,6 +450,8 @@ /// symbol. bool GVIsIndirectSymbol(const GlobalValue *GV, Reloc::Model RelocM) const; + /// True if fast-isel is used. + bool useFastISel() const; }; } // End llvm namespace Index: lib/Target/ARM/ARMSubtarget.cpp =================================================================== --- lib/Target/ARM/ARMSubtarget.cpp +++ lib/Target/ARM/ARMSubtarget.cpp @@ -353,3 +353,10 @@ return UseMovt && (isTargetWindows() || !MF.getFunction()->hasFnAttribute(Attribute::MinSize)); } + +bool ARMSubtarget::useFastISel() const { + // Thumb2 support on iOS; ARM support on iOS, Linux and NaCl. + return TM.Options.EnableFastISel && + ((isTargetMachO() && !isThumb1Only()) || + (isTargetLinux() && !isThumb()) || (isTargetNaCl() && !isThumb())); +} Index: lib/Target/TargetMachine.cpp =================================================================== --- lib/Target/TargetMachine.cpp +++ lib/Target/TargetMachine.cpp @@ -66,7 +66,6 @@ Options.X = (F.getFnAttribute(Y).getValueAsString() == "true"); \ } while (0) - RESET_OPTION(NoFramePointerElim, "no-frame-pointer-elim"); RESET_OPTION(LessPreciseFPMADOption, "less-precise-fpmad"); RESET_OPTION(UnsafeFPMath, "unsafe-fp-math"); RESET_OPTION(NoInfsFPMath, "no-infs-fp-math"); Index: test/CodeGen/ARM/disable-fp-elim.ll =================================================================== --- /dev/null +++ test/CodeGen/ARM/disable-fp-elim.ll @@ -0,0 +1,25 @@ +; RUN: llc < %s -mtriple armv7-none-linux-gnueabi -O1 | FileCheck %s --check-prefix=DISABLE-FP-ELIM +; RUN: llc < %s -mtriple armv7-none-linux-gnueabi -disable-fp-elim -O1 | FileCheck %s --check-prefix=DISABLE-FP-ELIM +; RUN: llc < %s -mtriple armv7-none-linux-gnueabi -disable-fp-elim=false -O1 | FileCheck %s --check-prefix=ENABLE-FP-ELIM +; RUN: llc < %s -mtriple armv7-none-linux-gnueabi -disable-fp-elim=false -O0 | FileCheck %s --check-prefix=DISABLE-FP-ELIM + +; Check that command line option "-disable-fp-elim" overrides function attribute +; "no-frame-pointer-elim". Also, check frame pointer elimination is disabled +; when fast-isel is used. + +; ENABLE-FP-ELIM-NOT: .setfp +; DISABLE-FP-ELIM: .setfp r11, sp + +define i32 @foo1(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) #0 { +entry: + %call = tail call i32 @foo2(i32 %a) + %add = add i32 %c, %b + %add1 = add i32 %add, %d + %add2 = add i32 %add1, %e + %add3 = add i32 %add2, %call + ret i32 %add3 +} + +declare i32 @foo2(i32) + +attributes #0 = { nounwind "no-frame-pointer-elim"="true" } Index: test/CodeGen/X86/2014-08-29-CompactUnwind.ll =================================================================== --- test/CodeGen/X86/2014-08-29-CompactUnwind.ll +++ test/CodeGen/X86/2014-08-29-CompactUnwind.ll @@ -1,4 +1,4 @@ -; RUN: llc < %s -disable-fp-elim -mtriple x86_64-apple-darwin11 -mcpu corei7 -filetype=obj -o - | llvm-objdump -d -unwind-info -s - | FileCheck %s +; RUN: llc < %s -mtriple x86_64-apple-darwin11 -mcpu corei7 -filetype=obj -o - | llvm-objdump -d -unwind-info -s - | FileCheck %s ; Regression test for http://llvm.org/bugs/show_bug.cgi?id=20800. ; ModuleID = 'asan_report.ii' Index: tools/llc/llc.cpp =================================================================== --- tools/llc/llc.cpp +++ tools/llc/llc.cpp @@ -305,7 +305,7 @@ M->setDataLayout(*DL); // Override function attributes. - overrideFunctionAttributes(CPUStr, FeaturesStr, *M); + setFunctionAttributes(CPUStr, FeaturesStr, Options, *M, false); if (RelaxAll.getNumOccurrences() > 0 && FileType != TargetMachine::CGFT_ObjectFile) Index: tools/opt/opt.cpp =================================================================== --- tools/opt/opt.cpp +++ tools/opt/opt.cpp @@ -265,7 +265,8 @@ // Returns the TargetMachine instance or zero if no triple is provided. static TargetMachine* GetTargetMachine(Triple TheTriple, StringRef CPUStr, - StringRef FeaturesStr) { + StringRef FeaturesStr, + const TargetOptions &Options) { std::string Error; const Target *TheTarget = TargetRegistry::lookupTarget(MArch, TheTriple, Error); @@ -275,8 +276,7 @@ } return TheTarget->createTargetMachine(TheTriple.getTriple(), - CPUStr, FeaturesStr, - InitTargetOptionsFromCodeGenFlags(), + CPUStr, FeaturesStr, Options, RelocModel, CMModel, GetCodeGenOptLevel()); } @@ -386,16 +386,18 @@ Triple ModuleTriple(M->getTargetTriple()); std::string CPUStr, FeaturesStr; TargetMachine *Machine = nullptr; + const TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); + if (ModuleTriple.getArch()) { CPUStr = getCPUStr(); FeaturesStr = getFeaturesStr(); - Machine = GetTargetMachine(ModuleTriple, CPUStr, FeaturesStr); + Machine = GetTargetMachine(ModuleTriple, CPUStr, FeaturesStr, Options); } std::unique_ptr TM(Machine); // Override function attributes. - overrideFunctionAttributes(CPUStr, FeaturesStr, *M); + setFunctionAttributes(CPUStr, FeaturesStr, Options, *M, false); // If the output is set to be emitted to standard out, and standard out is a // console, print out a warning message and refuse to do it. We don't