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)
|
if (CodeGenOpts.UnwindTables)
|
||||||
getModule().setUwtable();
|
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();
|
SimplifyPersonality();
|
||||||
|
|
||||||
if (getCodeGenOpts().EmitDeclMetadata)
|
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.
|
can prove that the function does not execute any convergent operations.
|
||||||
Similarly, the optimizer may remove ``convergent`` on calls/invokes when it
|
Similarly, the optimizer may remove ``convergent`` on calls/invokes when it
|
||||||
can prove that the call/invoke cannot call a convergent function.
|
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``
|
``hot``
|
||||||
This attribute indicates that this function is a hot spot of the program
|
This attribute indicates that this function is a hot spot of the program
|
||||||
execution. The function will be optimized more aggressively and will be
|
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
|
contain a flag with the ID ``!"foo"`` that has the value '1' after linking is
|
||||||
performed.
|
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
|
Objective-C Garbage Collection Module Flags Metadata
|
||||||
----------------------------------------------------
|
----------------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ Optional<CodeGenFileType> getExplicitFileType();
|
||||||
|
|
||||||
CodeGenFileType getFileType();
|
CodeGenFileType getFileType();
|
||||||
|
|
||||||
llvm::FramePointer::FP getFramePointerUsage();
|
FramePointerKind getFramePointerUsage();
|
||||||
|
|
||||||
bool getEnableUnsafeFPMath();
|
bool getEnableUnsafeFPMath();
|
||||||
|
|
||||||
|
|
|
@ -890,6 +890,11 @@ public:
|
||||||
bool getUwtable() const;
|
bool getUwtable() const;
|
||||||
void setUwtable();
|
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
|
/// @name Utility functions for querying and setting the build SDK version
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
|
|
|
@ -66,10 +66,8 @@ namespace llvm {
|
||||||
CGFT_Null // Do not emit any output.
|
CGFT_Null // Do not emit any output.
|
||||||
};
|
};
|
||||||
|
|
||||||
// Specify effect of frame pointer elimination optimization.
|
// Specify what functions should keep the frame pointer.
|
||||||
namespace FramePointer {
|
enum class FramePointerKind { None, NonLeaf, All };
|
||||||
enum FP {All, NonLeaf, None};
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end llvm namespace
|
} // end llvm namespace
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ CGOPT(ThreadModel::Model, ThreadModel)
|
||||||
CGOPT_EXP(CodeModel::Model, CodeModel)
|
CGOPT_EXP(CodeModel::Model, CodeModel)
|
||||||
CGOPT(ExceptionHandling, ExceptionModel)
|
CGOPT(ExceptionHandling, ExceptionModel)
|
||||||
CGOPT_EXP(CodeGenFileType, FileType)
|
CGOPT_EXP(CodeGenFileType, FileType)
|
||||||
CGOPT(FramePointer::FP, FramePointerUsage)
|
CGOPT(FramePointerKind, FramePointerUsage)
|
||||||
CGOPT(bool, EnableUnsafeFPMath)
|
CGOPT(bool, EnableUnsafeFPMath)
|
||||||
CGOPT(bool, EnableNoInfsFPMath)
|
CGOPT(bool, EnableNoInfsFPMath)
|
||||||
CGOPT(bool, EnableNoNaNsFPMath)
|
CGOPT(bool, EnableNoNaNsFPMath)
|
||||||
|
@ -183,16 +183,16 @@ codegen::RegisterCodeGenFlags::RegisterCodeGenFlags() {
|
||||||
"Emit nothing, for performance testing")));
|
"Emit nothing, for performance testing")));
|
||||||
CGBINDOPT(FileType);
|
CGBINDOPT(FileType);
|
||||||
|
|
||||||
static cl::opt<FramePointer::FP> FramePointerUsage(
|
static cl::opt<FramePointerKind> FramePointerUsage(
|
||||||
"frame-pointer",
|
"frame-pointer",
|
||||||
cl::desc("Specify frame pointer elimination optimization"),
|
cl::desc("Specify frame pointer elimination optimization"),
|
||||||
cl::init(FramePointer::None),
|
cl::init(FramePointerKind::None),
|
||||||
cl::values(
|
cl::values(
|
||||||
clEnumValN(FramePointer::All, "all",
|
clEnumValN(FramePointerKind::All, "all",
|
||||||
"Disable frame pointer elimination"),
|
"Disable frame pointer elimination"),
|
||||||
clEnumValN(FramePointer::NonLeaf, "non-leaf",
|
clEnumValN(FramePointerKind::NonLeaf, "non-leaf",
|
||||||
"Disable frame pointer elimination for non-leaf frame"),
|
"Disable frame pointer elimination for non-leaf frame"),
|
||||||
clEnumValN(FramePointer::None, "none",
|
clEnumValN(FramePointerKind::None, "none",
|
||||||
"Enable frame pointer elimination")));
|
"Enable frame pointer elimination")));
|
||||||
CGBINDOPT(FramePointerUsage);
|
CGBINDOPT(FramePointerUsage);
|
||||||
|
|
||||||
|
@ -662,11 +662,11 @@ void codegen::setFunctionAttributes(StringRef CPU, StringRef Features,
|
||||||
}
|
}
|
||||||
if (FramePointerUsageView->getNumOccurrences() > 0 &&
|
if (FramePointerUsageView->getNumOccurrences() > 0 &&
|
||||||
!F.hasFnAttribute("frame-pointer")) {
|
!F.hasFnAttribute("frame-pointer")) {
|
||||||
if (getFramePointerUsage() == FramePointer::All)
|
if (getFramePointerUsage() == FramePointerKind::All)
|
||||||
NewAttrs.addAttribute("frame-pointer", "all");
|
NewAttrs.addAttribute("frame-pointer", "all");
|
||||||
else if (getFramePointerUsage() == FramePointer::NonLeaf)
|
else if (getFramePointerUsage() == FramePointerKind::NonLeaf)
|
||||||
NewAttrs.addAttribute("frame-pointer", "non-leaf");
|
NewAttrs.addAttribute("frame-pointer", "non-leaf");
|
||||||
else if (getFramePointerUsage() == FramePointer::None)
|
else if (getFramePointerUsage() == FramePointerKind::None)
|
||||||
NewAttrs.addAttribute("frame-pointer", "none");
|
NewAttrs.addAttribute("frame-pointer", "none");
|
||||||
}
|
}
|
||||||
if (DisableTailCallsView->getNumOccurrences() > 0)
|
if (DisableTailCallsView->getNumOccurrences() > 0)
|
||||||
|
|
|
@ -335,8 +335,21 @@ Function *Function::createWithDefaultAttr(FunctionType *Ty,
|
||||||
unsigned AddrSpace, const Twine &N,
|
unsigned AddrSpace, const Twine &N,
|
||||||
Module *M) {
|
Module *M) {
|
||||||
auto *F = new Function(Ty, Linkage, AddrSpace, N, M);
|
auto *F = new Function(Ty, Linkage, AddrSpace, N, M);
|
||||||
|
AttrBuilder B;
|
||||||
if (M->getUwtable())
|
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;
|
return F;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -676,6 +676,16 @@ bool Module::getUwtable() const {
|
||||||
|
|
||||||
void Module::setUwtable() { addModuleFlag(ModFlagBehavior::Max, "uwtable", 1); }
|
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) {
|
void Module::setSDKVersion(const VersionTuple &V) {
|
||||||
SmallVector<unsigned, 3> Entries;
|
SmallVector<unsigned, 3> Entries;
|
||||||
Entries.push_back(V.getMajor());
|
Entries.push_back(V.getMajor());
|
||||||
|
|
|
@ -10,12 +10,15 @@ entry:
|
||||||
ret i32 %tmp
|
ret i32 %tmp
|
||||||
}
|
}
|
||||||
|
|
||||||
!llvm.module.flags = !{!0}
|
!llvm.module.flags = !{!0, !1}
|
||||||
|
|
||||||
;; Due to -fasynchronous-unwind-tables.
|
;; Due to -fasynchronous-unwind-tables.
|
||||||
!0 = !{i32 7, !"uwtable", i32 1}
|
!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.
|
;; Set the uwtable attribute on ctor/dtor.
|
||||||
; CHECK: define internal void @asan.module_ctor() #[[#ATTR:]]
|
; CHECK: define internal void @asan.module_ctor() #[[#ATTR:]]
|
||||||
; CHECK: define internal void @asan.module_dtor() #[[#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