[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