diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -744,6 +744,18 @@ 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 --- /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 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -1529,6 +1529,16 @@ 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,19 @@ 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. + +- "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 --- a/llvm/include/llvm/CodeGen/CommandFlags.h +++ b/llvm/include/llvm/CodeGen/CommandFlags.h @@ -53,7 +53,7 @@ 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 --- a/llvm/include/llvm/IR/Module.h +++ b/llvm/include/llvm/IR/Module.h @@ -890,6 +890,11 @@ 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 --- a/llvm/include/llvm/Support/CodeGen.h +++ b/llvm/include/llvm/Support/CodeGen.h @@ -66,10 +66,8 @@ 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 --- a/llvm/lib/CodeGen/CommandFlags.cpp +++ b/llvm/lib/CodeGen/CommandFlags.cpp @@ -53,7 +53,7 @@ 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 @@ "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 @@ } 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 --- a/llvm/lib/IR/Function.cpp +++ b/llvm/lib/IR/Function.cpp @@ -335,8 +335,21 @@ 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 --- a/llvm/lib/IR/Module.cpp +++ b/llvm/lib/IR/Module.cpp @@ -676,6 +676,16 @@ 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 rename from llvm/test/Instrumentation/AddressSanitizer/uwtable.ll rename to llvm/test/Instrumentation/AddressSanitizer/module-flags.ll --- a/llvm/test/Instrumentation/AddressSanitizer/uwtable.ll +++ b/llvm/test/Instrumentation/AddressSanitizer/module-flags.ll @@ -10,12 +10,15 @@ 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" }