[Clang][Codegen] Add GNU function attribute 'no_profile' and lower it to noprofile
authorNick Desaulniers <ndesaulniers@google.com>
Fri, 18 Jun 2021 20:33:44 +0000 (13:33 -0700)
committerNick Desaulniers <ndesaulniers@google.com>
Fri, 18 Jun 2021 20:42:32 +0000 (13:42 -0700)
noprofile IR attribute already exists to prevent profiling with PGO;
emit that when a function uses the newly added no_profile function
attribute.

The Linux kernel would like to avoid compiler generated code in
functions annotated with such attribute. We already respect this for
libcalls to fentry() and mcount().

Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80223
Link: https://lore.kernel.org/lkml/CAKwvOdmPTi93n2L0_yQkrzLdmpxzrOR7zggSzonyaw2PGshApw@mail.gmail.com/
Reviewed By: MaskRay, void, phosek, aaron.ballman

Differential Revision: https://reviews.llvm.org/D104475

clang/include/clang/Basic/Attr.td
clang/include/clang/Basic/AttrDocs.td
clang/lib/CodeGen/CodeGenFunction.cpp
clang/test/CodeGen/no_profile.c [new file with mode: 0644]
clang/test/Misc/pragma-attribute-supported-attributes-list.test
clang/test/Sema/no_profile-attribute.c [new file with mode: 0644]

index 7146210..8829b4b 100644 (file)
@@ -1970,6 +1970,13 @@ def NoInstrumentFunction : InheritableAttr {
   let SimpleHandler = 1;
 }
 
+def NoProfileFunction : InheritableAttr {
+  let Spellings = [Clang<"no_profile">];
+  let Subjects = SubjectList<[Function]>;
+  let Documentation = [NoProfileDocs];
+  let SimpleHandler = 1;
+}
+
 def NotTailCalled : InheritableAttr {
   let Spellings = [Clang<"not_tail_called">];
   let Subjects = SubjectList<[Function]>;
index 6594e77..6173c8c 100644 (file)
@@ -2559,6 +2559,17 @@ This attribute accepts a single parameter that must be one of the following:
   }];
 }
 
+def NoProfileDocs : Documentation {
+  let Category = DocCatFunction;
+  let Content = [{
+Use the ``no_profile`` attribute on a function declaration to denote that the
+compiler should not instrument the function with profile-related
+instrumentation, such as via the
+``-fprofile-generate`` / ``-fprofile-instr-generate`` /
+``-fcs-profile-generate`` / ``-fprofile-arcs`` flags.
+}];
+}
+
 def NoSanitizeDocs : Documentation {
   let Category = DocCatFunction;
   let Content = [{
index 518305e..97288d0 100644 (file)
@@ -893,6 +893,9 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
   if (D && D->hasAttr<CFICanonicalJumpTableAttr>())
     Fn->addFnAttr("cfi-canonical-jump-table");
 
+  if (D && D->hasAttr<NoProfileFunctionAttr>())
+    Fn->addFnAttr(llvm::Attribute::NoProfile);
+
   if (getLangOpts().OpenCL) {
     // Add metadata for a kernel function.
     if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
diff --git a/clang/test/CodeGen/no_profile.c b/clang/test/CodeGen/no_profile.c
new file mode 100644 (file)
index 0000000..5ac116b
--- /dev/null
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fprofile-instrument=llvm -disable-llvm-passes \
+// RUN:   -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -fprofile-instrument=csllvm -disable-llvm-passes \
+// RUN:   -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -fprofile-instrument=clang -disable-llvm-passes \
+// RUN:   -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -fprofile-arcs -disable-llvm-passes \
+// RUN:   -emit-llvm -o - %s | FileCheck %s
+int g(int);
+
+void __attribute__((no_profile)) no_instr() {
+// CHECK: define {{.*}} void @no_instr() [[ATTR:#[0-9]+]]
+}
+
+void instr(void) {
+// CHECK: define {{.*}} void @instr() [[ATTR2:#[0-9]+]]
+}
+// CHECK: attributes [[ATTR]] = {{.*}} noprofile
+// CHECK: attributes [[ATTR2]] = {
+// CHECK-NOT: noprofile
+// CHECK: }
index 8256f12..290306b 100644 (file)
@@ -99,6 +99,7 @@
 // CHECK-NEXT: NoMerge (SubjectMatchRule_function)
 // CHECK-NEXT: NoMicroMips (SubjectMatchRule_function)
 // CHECK-NEXT: NoMips16 (SubjectMatchRule_function)
+// CHECK-NEXT: NoProfileFunction (SubjectMatchRule_function)
 // CHECK-NEXT: NoSanitize (SubjectMatchRule_function, SubjectMatchRule_objc_method, SubjectMatchRule_variable_is_global)
 // CHECK-NEXT: NoSanitizeSpecific (SubjectMatchRule_function, SubjectMatchRule_variable_is_global)
 // CHECK-NEXT: NoSpeculativeLoadHardening (SubjectMatchRule_function, SubjectMatchRule_objc_method)
diff --git a/clang/test/Sema/no_profile-attribute.c b/clang/test/Sema/no_profile-attribute.c
new file mode 100644 (file)
index 0000000..b3c073f
--- /dev/null
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify
+__attribute__((no_profile))
+void no_profile0(void);
+#if !__has_attribute(no_profile)
+#error "Where did the no_profile function attribute go?"
+#endif
+
+void no_profile1(__attribute__((no_profile)) int param); // expected-warning {{'no_profile' attribute only applies to functions}}
+__attribute__((no_profile(""))) // expected-error {{'no_profile' attribute takes no arguments}}
+void no_profile2(void);
+void no_profile3(void) {
+  __attribute__((no_profile)); // expected-error {{'no_profile' attribute cannot be applied to a statement}}
+}