diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 6b966e7ca133..fd5975b4f545 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -744,6 +744,18 @@ void CodeGenModule::Release() { if (CodeGenOpts.UnwindTables) getModule().setUwtable(); + switch (CodeGenOpts.getFramePointer()) { + case CodeGenOptions::FramePointerKind::None: + // 0 ("none") is the default. + break; + case CodeGenOptions::FramePointerKind::NonLeaf: + getModule().setFramePointer(llvm::FramePointerKind::NonLeaf); + break; + case CodeGenOptions::FramePointerKind::All: + getModule().setFramePointer(llvm::FramePointerKind::All); + break; + } + SimplifyPersonality(); if (getCodeGenOpts().EmitDeclMetadata) diff --git a/clang/test/CodeGen/asan-frame-pointer.cpp b/clang/test/CodeGen/asan-frame-pointer.cpp new file mode 100644 index 000000000000..ed3624f3146e --- /dev/null +++ b/clang/test/CodeGen/asan-frame-pointer.cpp @@ -0,0 +1,19 @@ +/// -mframe-pointer=none sets the module flag "frame-pointer" (merge behavior: max). +/// asan synthesized ctor/dtor get the "frame-pointer" function attribute if not zero (default). +// RUN: %clang_cc1 -emit-llvm -fsanitize=address -mframe-pointer=none %s -o - | FileCheck %s --check-prefix=NONE +// RUN: %clang_cc1 -emit-llvm -fsanitize=address -mframe-pointer=non-leaf %s -o - | FileCheck %s --check-prefix=NONLEAF +// RUN: %clang_cc1 -emit-llvm -fsanitize=address -mframe-pointer=all %s -o - | FileCheck %s --check-prefix=ALL + +int global; + +// NONE: define internal void @asan.module_ctor() #[[#ATTR:]] { +// NONE: define internal void @asan.module_dtor() #[[#ATTR]] { +// NONE: attributes #[[#ATTR]] = { nounwind } + +// NONLEAF: define internal void @asan.module_ctor() #[[#ATTR:]] { +// NONLEAF: define internal void @asan.module_dtor() #[[#ATTR]] { +// NONLEAF: attributes #[[#ATTR]] = { nounwind "frame-pointer"="non-leaf" } + +// ALL: define internal void @asan.module_ctor() #[[#ATTR:]] { +// ALL: define internal void @asan.module_dtor() #[[#ATTR]] { +// ALL: attributes #[[#ATTR]] = { nounwind "frame-pointer"="all" } diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index e6760f847d9f..6770ad8b78c5 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -1529,6 +1529,16 @@ example: can prove that the function does not execute any convergent operations. Similarly, the optimizer may remove ``convergent`` on calls/invokes when it can prove that the call/invoke cannot call a convergent function. +``"frame-pointer"`` + This attribute tells the code generator whether the function + should keep the frame pointer. The code generator may emit the frame pointer + even if this attribute says the frame pointer can be eliminated. + The allowed string values are: + + * ``"none"`` (default) - the frame pointer can be eliminated. + * ``"non-leaf"`` - the frame pointer should be kept if the function calls + other functions. + * ``"all"`` - the frame pointer should be kept. ``hot`` This attribute indicates that this function is a hot spot of the program execution. The function will be optimized more aggressively and will be @@ -6994,6 +7004,24 @@ An example of module flags: contain a flag with the ID ``!"foo"`` that has the value '1' after linking is performed. +Synthesized Functions Module Flags Metadata +------------------------------------------- + +These metadata specify the default attributes synthesized functions should have. +These metadata are currently respected by a few instrumentation passes, such as +sanitizers. + +These metadata correspond to a few function attributes with significant code +generation behaviors. Function attributes with just optimization purposes +should not be listed because the performance impact of these synthesized +functions is small. + +- "frame-pointer": **Max**. The value can be 0, 1, or 2. A synthesized function + will get the "frame-pointer" function attribute, with value being "none", + "non-leaf", or "all", respectively. +- "uwtable": **Max**. The value can be 0 or 1. If the value is 1, a synthesized + function will get the ``uwtable`` function attribute. + Objective-C Garbage Collection Module Flags Metadata ---------------------------------------------------- diff --git a/llvm/include/llvm/CodeGen/CommandFlags.h b/llvm/include/llvm/CodeGen/CommandFlags.h index e18ee3644536..69ce85e6d7ec 100644 --- a/llvm/include/llvm/CodeGen/CommandFlags.h +++ b/llvm/include/llvm/CodeGen/CommandFlags.h @@ -53,7 +53,7 @@ Optional getExplicitFileType(); CodeGenFileType getFileType(); -llvm::FramePointer::FP getFramePointerUsage(); +FramePointerKind getFramePointerUsage(); bool getEnableUnsafeFPMath(); diff --git a/llvm/include/llvm/IR/Module.h b/llvm/include/llvm/IR/Module.h index a4ad9d3f28e2..a71a4c06914a 100644 --- a/llvm/include/llvm/IR/Module.h +++ b/llvm/include/llvm/IR/Module.h @@ -890,6 +890,11 @@ public: bool getUwtable() const; void setUwtable(); + /// Get/set whether synthesized functions should get the "frame-pointer" + /// attribute. + FramePointerKind getFramePointer() const; + void setFramePointer(FramePointerKind Kind); + /// @name Utility functions for querying and setting the build SDK version /// @{ diff --git a/llvm/include/llvm/Support/CodeGen.h b/llvm/include/llvm/Support/CodeGen.h index e2aa2b68b9d2..9e66d84e185d 100644 --- a/llvm/include/llvm/Support/CodeGen.h +++ b/llvm/include/llvm/Support/CodeGen.h @@ -66,10 +66,8 @@ namespace llvm { CGFT_Null // Do not emit any output. }; - // Specify effect of frame pointer elimination optimization. - namespace FramePointer { - enum FP {All, NonLeaf, None}; - } + // Specify what functions should keep the frame pointer. + enum class FramePointerKind { None, NonLeaf, All }; } // end llvm namespace diff --git a/llvm/lib/CodeGen/CommandFlags.cpp b/llvm/lib/CodeGen/CommandFlags.cpp index de560559b6fe..76d871978532 100644 --- a/llvm/lib/CodeGen/CommandFlags.cpp +++ b/llvm/lib/CodeGen/CommandFlags.cpp @@ -53,7 +53,7 @@ CGOPT(ThreadModel::Model, ThreadModel) CGOPT_EXP(CodeModel::Model, CodeModel) CGOPT(ExceptionHandling, ExceptionModel) CGOPT_EXP(CodeGenFileType, FileType) -CGOPT(FramePointer::FP, FramePointerUsage) +CGOPT(FramePointerKind, FramePointerUsage) CGOPT(bool, EnableUnsafeFPMath) CGOPT(bool, EnableNoInfsFPMath) CGOPT(bool, EnableNoNaNsFPMath) @@ -183,16 +183,16 @@ codegen::RegisterCodeGenFlags::RegisterCodeGenFlags() { "Emit nothing, for performance testing"))); CGBINDOPT(FileType); - static cl::opt FramePointerUsage( + static cl::opt FramePointerUsage( "frame-pointer", cl::desc("Specify frame pointer elimination optimization"), - cl::init(FramePointer::None), + cl::init(FramePointerKind::None), cl::values( - clEnumValN(FramePointer::All, "all", + clEnumValN(FramePointerKind::All, "all", "Disable frame pointer elimination"), - clEnumValN(FramePointer::NonLeaf, "non-leaf", + clEnumValN(FramePointerKind::NonLeaf, "non-leaf", "Disable frame pointer elimination for non-leaf frame"), - clEnumValN(FramePointer::None, "none", + clEnumValN(FramePointerKind::None, "none", "Enable frame pointer elimination"))); CGBINDOPT(FramePointerUsage); @@ -662,11 +662,11 @@ void codegen::setFunctionAttributes(StringRef CPU, StringRef Features, } if (FramePointerUsageView->getNumOccurrences() > 0 && !F.hasFnAttribute("frame-pointer")) { - if (getFramePointerUsage() == FramePointer::All) + if (getFramePointerUsage() == FramePointerKind::All) NewAttrs.addAttribute("frame-pointer", "all"); - else if (getFramePointerUsage() == FramePointer::NonLeaf) + else if (getFramePointerUsage() == FramePointerKind::NonLeaf) NewAttrs.addAttribute("frame-pointer", "non-leaf"); - else if (getFramePointerUsage() == FramePointer::None) + else if (getFramePointerUsage() == FramePointerKind::None) NewAttrs.addAttribute("frame-pointer", "none"); } if (DisableTailCallsView->getNumOccurrences() > 0) diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp index 32c7b876115e..0887b5c5e8e0 100644 --- a/llvm/lib/IR/Function.cpp +++ b/llvm/lib/IR/Function.cpp @@ -335,8 +335,21 @@ Function *Function::createWithDefaultAttr(FunctionType *Ty, unsigned AddrSpace, const Twine &N, Module *M) { auto *F = new Function(Ty, Linkage, AddrSpace, N, M); + AttrBuilder B; if (M->getUwtable()) - F->addAttribute(AttributeList::FunctionIndex, Attribute::UWTable); + B.addAttribute(Attribute::UWTable); + switch (M->getFramePointer()) { + case FramePointerKind::None: + // 0 ("none") is the default. + break; + case FramePointerKind::NonLeaf: + B.addAttribute("frame-pointer", "non-leaf"); + break; + case FramePointerKind::All: + B.addAttribute("frame-pointer", "all"); + break; + } + F->addAttributes(AttributeList::FunctionIndex, B); return F; } diff --git a/llvm/lib/IR/Module.cpp b/llvm/lib/IR/Module.cpp index b5108f7a3ebe..726ac6ab8251 100644 --- a/llvm/lib/IR/Module.cpp +++ b/llvm/lib/IR/Module.cpp @@ -676,6 +676,16 @@ bool Module::getUwtable() const { void Module::setUwtable() { addModuleFlag(ModFlagBehavior::Max, "uwtable", 1); } +FramePointerKind Module::getFramePointer() const { + auto *Val = cast_or_null(getModuleFlag("frame-pointer")); + return static_cast( + Val ? cast(Val->getValue())->getZExtValue() : 0); +} + +void Module::setFramePointer(FramePointerKind Kind) { + addModuleFlag(ModFlagBehavior::Max, "frame-pointer", static_cast(Kind)); +} + void Module::setSDKVersion(const VersionTuple &V) { SmallVector Entries; Entries.push_back(V.getMajor()); diff --git a/llvm/test/Instrumentation/AddressSanitizer/uwtable.ll b/llvm/test/Instrumentation/AddressSanitizer/module-flags.ll similarity index 72% rename from llvm/test/Instrumentation/AddressSanitizer/uwtable.ll rename to llvm/test/Instrumentation/AddressSanitizer/module-flags.ll index 09b7c3608c5e..ca3c6f3051f1 100644 --- a/llvm/test/Instrumentation/AddressSanitizer/uwtable.ll +++ b/llvm/test/Instrumentation/AddressSanitizer/module-flags.ll @@ -10,12 +10,15 @@ entry: ret i32 %tmp } -!llvm.module.flags = !{!0} +!llvm.module.flags = !{!0, !1} ;; Due to -fasynchronous-unwind-tables. !0 = !{i32 7, !"uwtable", i32 1} +;; Due to -fno-omit-frame-pointer. +!1 = !{i32 7, !"frame-pointer", i32 2} + ;; Set the uwtable attribute on ctor/dtor. ; CHECK: define internal void @asan.module_ctor() #[[#ATTR:]] ; CHECK: define internal void @asan.module_dtor() #[[#ATTR]] -; CHECK: attributes #[[#ATTR]] = { nounwind uwtable } +; CHECK: attributes #[[#ATTR]] = { nounwind uwtable "frame-pointer"="all" }