[clang] 2786e67 - [IR][sanitizer] Add module flag "frame-pointer" and set it for cc1 -mframe-pointer={non-leaf,all}
Fangrui Song via cfe-commits
cfe-commits at lists.llvm.org
Thu Apr 22 18:07:34 PDT 2021
Author: Fangrui Song
Date: 2021-04-22T18:07:30-07:00
New Revision: 2786e673c7d67ffca531ef38d679620ee3048a1e
URL: https://github.com/llvm/llvm-project/commit/2786e673c7d67ffca531ef38d679620ee3048a1e
DIFF: https://github.com/llvm/llvm-project/commit/2786e673c7d67ffca531ef38d679620ee3048a1e.diff
LOG: [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
Added:
clang/test/CodeGen/asan-frame-pointer.cpp
llvm/test/Instrumentation/AddressSanitizer/module-flags.ll
Modified:
clang/lib/CodeGen/CodeGenModule.cpp
llvm/docs/LangRef.rst
llvm/include/llvm/CodeGen/CommandFlags.h
llvm/include/llvm/IR/Module.h
llvm/include/llvm/Support/CodeGen.h
llvm/lib/CodeGen/CommandFlags.cpp
llvm/lib/IR/Function.cpp
llvm/lib/IR/Module.cpp
Removed:
llvm/test/Instrumentation/AddressSanitizer/uwtable.ll
################################################################################
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 6b966e7ca1338..fd5975b4f545a 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 0000000000000..ed3624f3146eb
--- /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 e6760f847d9f1..6770ad8b78c54 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 e18ee36445363..69ce85e6d7ec8 100644
--- a/llvm/include/llvm/CodeGen/CommandFlags.h
+++ b/llvm/include/llvm/CodeGen/CommandFlags.h
@@ -53,7 +53,7 @@ Optional<CodeGenFileType> 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 a4ad9d3f28e2d..a71a4c06914a2 100644
--- a/llvm/include/llvm/IR/Module.h
+++ b/llvm/include/llvm/IR/Module.h
@@ -890,6 +890,11 @@ class Module {
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 e2aa2b68b9d24..9e66d84e185dd 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 de560559b6fe0..76d871978532f 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<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)
diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp
index 32c7b876115ec..0887b5c5e8e06 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 b5108f7a3ebe9..726ac6ab82513 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<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());
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 09b7c3608c5ee..ca3c6f3051f1a 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" }
More information about the cfe-commits
mailing list