forked from OSchip/llvm-project
[IR][sanitizer] Add module flag "frame-pointer" and set it for cc1 -mframe-pointer={non-leaf,all}
The Linux kernel objtool diagnostic `call without frame pointer save/setup` arise in multiple instrumentation passes (asan/tsan/gcov). With the mechanism introduced in D100251, it's trivial to respect the command line -m[no-]omit-leaf-frame-pointer/-f[no-]omit-frame-pointer, so let's do it. Fix: https://github.com/ClangBuiltLinux/linux/issues/1236 (tsan) Fix: https://github.com/ClangBuiltLinux/linux/issues/1238 (asan) Also document the function attribute "frame-pointer" which is long overdue. Differential Revision: https://reviews.llvm.org/D101016
This commit is contained in:
parent
879cbac08b
commit
2786e673c7
|
@ -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)
|
||||
|
|
|
@ -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" }
|
|
@ -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
|
||||
----------------------------------------------------
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ Optional<CodeGenFileType> getExplicitFileType();
|
|||
|
||||
CodeGenFileType getFileType();
|
||||
|
||||
llvm::FramePointer::FP getFramePointerUsage();
|
||||
FramePointerKind getFramePointerUsage();
|
||||
|
||||
bool getEnableUnsafeFPMath();
|
||||
|
||||
|
|
|
@ -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
|
||||
/// @{
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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<FramePointer::FP> FramePointerUsage(
|
||||
static cl::opt<FramePointerKind> 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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<ConstantAsMetadata>(getModuleFlag("frame-pointer"));
|
||||
return static_cast<FramePointerKind>(
|
||||
Val ? cast<ConstantInt>(Val->getValue())->getZExtValue() : 0);
|
||||
}
|
||||
|
||||
void Module::setFramePointer(FramePointerKind Kind) {
|
||||
addModuleFlag(ModFlagBehavior::Max, "frame-pointer", static_cast<int>(Kind));
|
||||
}
|
||||
|
||||
void Module::setSDKVersion(const VersionTuple &V) {
|
||||
SmallVector<unsigned, 3> Entries;
|
||||
Entries.push_back(V.getMajor());
|
||||
|
|
|
@ -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" }
|
Loading…
Reference in New Issue