[clang] b692312 - [InstrProf] Add new format for -fprofile-list=

Ellis Hoag via cfe-commits cfe-commits at lists.llvm.org
Thu Aug 4 08:49:47 PDT 2022


Author: Ellis Hoag
Date: 2022-08-04T08:49:43-07:00
New Revision: b692312ca432d9a379f67a8d83177a6f1722baaa

URL: https://github.com/llvm/llvm-project/commit/b692312ca432d9a379f67a8d83177a6f1722baaa
DIFF: https://github.com/llvm/llvm-project/commit/b692312ca432d9a379f67a8d83177a6f1722baaa.diff

LOG: [InstrProf] Add new format for -fprofile-list=

In D130807 we added the `skipprofile` attribute. This commit
changes the format so we can either `forbid` or `skip` profiling
functions by adding the `noprofile` or `skipprofile` attributes,
respectively. The behavior of the original format remains
unchanged.

Also, add the `skipprofile` attribute when using
`-fprofile-function-groups`.

Reviewed By: phosek

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

Added: 
    clang/test/CodeGen/profile-filter-new.c

Modified: 
    clang/docs/UsersManual.rst
    clang/include/clang/Basic/ProfileList.h
    clang/lib/Basic/ProfileList.cpp
    clang/lib/CodeGen/CodeGenFunction.cpp
    clang/lib/CodeGen/CodeGenModule.cpp
    clang/lib/CodeGen/CodeGenModule.h
    clang/test/CodeGen/profile-function-groups.c

Removed: 
    


################################################################################
diff  --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst
index 15df488e802de..f9ccca65f3889 100644
--- a/clang/docs/UsersManual.rst
+++ b/clang/docs/UsersManual.rst
@@ -2500,43 +2500,66 @@ This can be done using the ``-fprofile-list`` option.
 
   .. code-block:: console
 
-    $ echo "fun:test" > fun.list
     $ clang++ -O2 -fprofile-instr-generate -fprofile-list=fun.list code.cc -o code
 
-The option can be specified multiple times to pass multiple files.
+  The option can be specified multiple times to pass multiple files.
 
-.. code-block:: console
+  .. code-block:: console
+
+    $ clang++ -O2 -fprofile-instr-generate -fcoverage-mapping -fprofile-list=fun.list -fprofile-list=code.list code.cc -o code
+
+Supported sections are ``[clang]``, ``[llvm]``, and ``[csllvm]`` representing
+clang PGO, IRPGO, and CSIRPGO, respectively. Supported prefixes are ``function``
+and ``source``. Supported categories are ``allow``, ``skip``, and ``forbid``.
+``skip`` adds the ``skipprofile`` attribute while ``forbid`` adds the
+``noprofile`` attribute to the appropriate function. Use
+``default:<allow|skip|forbid>`` to specify the default category.
+
+  .. code-block:: console
+
+    $ cat fun.list
+    # The following cases are for clang instrumentation.
+    [clang]
+
+    # We might not want to profile functions that are inlined in many places.
+    function:inlinedLots=skip
+
+    # We want to forbid profiling where it might be dangerous.
+    source:lib/unsafe/*.cc=forbid
 
-    $ echo "!fun:*test*" > fun.list
-    $ echo "src:code.cc" > src.list
-    % clang++ -O2 -fprofile-instr-generate -fcoverage-mapping -fprofile-list=fun.list -fprofile-list=code.list code.cc -o code
+    # Otherwise we allow profiling.
+    default:allow
 
-To filter individual functions or entire source files using ``fun:<name>`` or
-``src:<file>`` respectively. To exclude a function or a source file, use
-``!fun:<name>`` or ``!src:<file>`` respectively. The format also supports
-wildcard expansion. The compiler generated functions are assumed to be located
-in the main source file.  It is also possible to restrict the filter to a
-particular instrumentation type by using a named section.
+Older Prefixes
+""""""""""""""
+  An older format is also supported, but it is only able to add the
+  ``noprofile`` attribute.
+  To filter individual functions or entire source files use ``fun:<name>`` or
+  ``src:<file>`` respectively. To exclude a function or a source file, use
+  ``!fun:<name>`` or ``!src:<file>`` respectively. The format also supports
+  wildcard expansion. The compiler generated functions are assumed to be located
+  in the main source file.  It is also possible to restrict the filter to a
+  particular instrumentation type by using a named section.
 
-.. code-block:: none
+  .. code-block:: none
 
-  # all functions whose name starts with foo will be instrumented.
-  fun:foo*
+    # all functions whose name starts with foo will be instrumented.
+    fun:foo*
 
-  # except for foo1 which will be excluded from instrumentation.
-  !fun:foo1
+    # except for foo1 which will be excluded from instrumentation.
+    !fun:foo1
 
-  # every function in path/to/foo.cc will be instrumented.
-  src:path/to/foo.cc
+    # every function in path/to/foo.cc will be instrumented.
+    src:path/to/foo.cc
 
-  # bar will be instrumented only when using backend instrumentation.
-  # Recognized section names are clang, llvm and csllvm.
-  [llvm]
-  fun:bar
+    # bar will be instrumented only when using backend instrumentation.
+    # Recognized section names are clang, llvm and csllvm.
+    [llvm]
+    fun:bar
 
-When the file contains only excludes, all files and functions except for the
-excluded ones will be instrumented. Otherwise, only the files and functions
-specified will be instrumented.
+  When the file contains only excludes, all files and functions except for the
+  excluded ones will be instrumented. Otherwise, only the files and functions
+  specified will be instrumented.
 
 Instrument function groups
 ^^^^^^^^^^^^^^^^^^^^^^^^^^

diff  --git a/clang/include/clang/Basic/ProfileList.h b/clang/include/clang/Basic/ProfileList.h
index aa472f126818d..f7768004b23b0 100644
--- a/clang/include/clang/Basic/ProfileList.h
+++ b/clang/include/clang/Basic/ProfileList.h
@@ -26,25 +26,38 @@ namespace clang {
 class ProfileSpecialCaseList;
 
 class ProfileList {
+public:
+  /// Represents if an how something should be excluded from profiling.
+  enum ExclusionType {
+    /// Profiling is allowed.
+    Allow,
+    /// Profiling is skipped using the \p skipprofile attribute.
+    Skip,
+    /// Profiling is forbidden using the \p noprofile attribute.
+    Forbid,
+  };
+
+private:
   std::unique_ptr<ProfileSpecialCaseList> SCL;
   const bool Empty;
-  const bool Default;
   SourceManager &SM;
+  llvm::Optional<ExclusionType> inSection(StringRef Section, StringRef Prefix,
+                                          StringRef Query) const;
 
 public:
   ProfileList(ArrayRef<std::string> Paths, SourceManager &SM);
   ~ProfileList();
 
   bool isEmpty() const { return Empty; }
-  bool getDefault() const { return Default; }
+  ExclusionType getDefault(CodeGenOptions::ProfileInstrKind Kind) const;
 
-  llvm::Optional<bool>
+  llvm::Optional<ExclusionType>
   isFunctionExcluded(StringRef FunctionName,
                      CodeGenOptions::ProfileInstrKind Kind) const;
-  llvm::Optional<bool>
+  llvm::Optional<ExclusionType>
   isLocationExcluded(SourceLocation Loc,
                      CodeGenOptions::ProfileInstrKind Kind) const;
-  llvm::Optional<bool>
+  llvm::Optional<ExclusionType>
   isFileExcluded(StringRef FileName,
                  CodeGenOptions::ProfileInstrKind Kind) const;
 };

diff  --git a/clang/lib/Basic/ProfileList.cpp b/clang/lib/Basic/ProfileList.cpp
index 9c88559d1c333..4c17a540aad66 100644
--- a/clang/lib/Basic/ProfileList.cpp
+++ b/clang/lib/Basic/ProfileList.cpp
@@ -66,8 +66,7 @@ ProfileSpecialCaseList::createOrDie(const std::vector<std::string> &Paths,
 ProfileList::ProfileList(ArrayRef<std::string> Paths, SourceManager &SM)
     : SCL(ProfileSpecialCaseList::createOrDie(
           Paths, SM.getFileManager().getVirtualFileSystem())),
-      Empty(SCL->isEmpty()),
-      Default(SCL->hasPrefix("fun") || SCL->hasPrefix("src")), SM(SM) {}
+      Empty(SCL->isEmpty()), SM(SM) {}
 
 ProfileList::~ProfileList() = default;
 
@@ -85,30 +84,66 @@ static StringRef getSectionName(CodeGenOptions::ProfileInstrKind Kind) {
   llvm_unreachable("Unhandled CodeGenOptions::ProfileInstrKind enum");
 }
 
-llvm::Optional<bool>
+ProfileList::ExclusionType
+ProfileList::getDefault(CodeGenOptions::ProfileInstrKind Kind) const {
+  StringRef Section = getSectionName(Kind);
+  // Check for "default:<type>"
+  if (SCL->inSection(Section, "default", "allow"))
+    return Allow;
+  if (SCL->inSection(Section, "default", "skip"))
+    return Skip;
+  if (SCL->inSection(Section, "default", "forbid"))
+    return Forbid;
+  // If any cases use "fun" or "src", set the default to FORBID.
+  if (SCL->hasPrefix("fun") || SCL->hasPrefix("src"))
+    return Forbid;
+  return Allow;
+}
+
+llvm::Optional<ProfileList::ExclusionType>
+ProfileList::inSection(StringRef Section, StringRef Prefix,
+                       StringRef Query) const {
+  if (SCL->inSection(Section, Prefix, Query, "allow"))
+    return Allow;
+  if (SCL->inSection(Section, Prefix, Query, "skip"))
+    return Skip;
+  if (SCL->inSection(Section, Prefix, Query, "forbid"))
+    return Forbid;
+  if (SCL->inSection(Section, Prefix, Query))
+    return Allow;
+  return None;
+}
+
+llvm::Optional<ProfileList::ExclusionType>
 ProfileList::isFunctionExcluded(StringRef FunctionName,
                                 CodeGenOptions::ProfileInstrKind Kind) const {
   StringRef Section = getSectionName(Kind);
+  // Check for "function:<regex>=<case>"
+  if (auto V = inSection(Section, "function", FunctionName))
+    return V;
   if (SCL->inSection(Section, "!fun", FunctionName))
-    return true;
+    return Forbid;
   if (SCL->inSection(Section, "fun", FunctionName))
-    return false;
+    return Allow;
   return None;
 }
 
-llvm::Optional<bool>
+llvm::Optional<ProfileList::ExclusionType>
 ProfileList::isLocationExcluded(SourceLocation Loc,
                                 CodeGenOptions::ProfileInstrKind Kind) const {
   return isFileExcluded(SM.getFilename(SM.getFileLoc(Loc)), Kind);
 }
 
-llvm::Optional<bool>
+llvm::Optional<ProfileList::ExclusionType>
 ProfileList::isFileExcluded(StringRef FileName,
                             CodeGenOptions::ProfileInstrKind Kind) const {
   StringRef Section = getSectionName(Kind);
+  // Check for "source:<regex>=<case>"
+  if (auto V = inSection(Section, "source", FileName))
+    return V;
   if (SCL->inSection(Section, "!src", FileName))
-    return true;
+    return Forbid;
   if (SCL->inSection(Section, "src", FileName))
-    return false;
+    return Allow;
   return None;
 }

diff  --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index d2f251521ff5a..7997a07ebe1d7 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -851,9 +851,18 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
     }
   }
 
-  if (CGM.getCodeGenOpts().getProfileInstr() != CodeGenOptions::ProfileNone)
-    if (CGM.isFunctionBlockedFromProfileInstr(Fn, Loc))
+  if (CGM.getCodeGenOpts().getProfileInstr() != CodeGenOptions::ProfileNone) {
+    switch (CGM.isFunctionBlockedFromProfileInstr(Fn, Loc)) {
+    case ProfileList::Skip:
+      Fn->addFnAttr(llvm::Attribute::SkipProfile);
+      break;
+    case ProfileList::Forbid:
       Fn->addFnAttr(llvm::Attribute::NoProfile);
+      break;
+    case ProfileList::Allow:
+      break;
+    }
+  }
 
   unsigned Count, Offset;
   if (const auto *Attr =

diff  --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 537cb78611b4b..8771f9e7f56d2 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -2895,46 +2895,44 @@ bool CodeGenModule::imbueXRayAttrs(llvm::Function *Fn, SourceLocation Loc,
   return true;
 }
 
-bool CodeGenModule::isFunctionBlockedByProfileList(llvm::Function *Fn,
-                                                   SourceLocation Loc) const {
+ProfileList::ExclusionType
+CodeGenModule::isFunctionBlockedByProfileList(llvm::Function *Fn,
+                                              SourceLocation Loc) const {
   const auto &ProfileList = getContext().getProfileList();
   // If the profile list is empty, then instrument everything.
   if (ProfileList.isEmpty())
-    return false;
+    return ProfileList::Allow;
   CodeGenOptions::ProfileInstrKind Kind = getCodeGenOpts().getProfileInstr();
   // First, check the function name.
-  Optional<bool> V = ProfileList.isFunctionExcluded(Fn->getName(), Kind);
-  if (V)
+  if (auto V = ProfileList.isFunctionExcluded(Fn->getName(), Kind))
     return *V;
   // Next, check the source location.
-  if (Loc.isValid()) {
-    Optional<bool> V = ProfileList.isLocationExcluded(Loc, Kind);
-    if (V)
+  if (Loc.isValid())
+    if (auto V = ProfileList.isLocationExcluded(Loc, Kind))
       return *V;
-  }
   // If location is unknown, this may be a compiler-generated function. Assume
   // it's located in the main file.
   auto &SM = Context.getSourceManager();
-  if (const auto *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
-    Optional<bool> V = ProfileList.isFileExcluded(MainFile->getName(), Kind);
-    if (V)
+  if (const auto *MainFile = SM.getFileEntryForID(SM.getMainFileID()))
+    if (auto V = ProfileList.isFileExcluded(MainFile->getName(), Kind))
       return *V;
-  }
-  return ProfileList.getDefault();
+  return ProfileList.getDefault(Kind);
 }
 
-bool CodeGenModule::isFunctionBlockedFromProfileInstr(
-    llvm::Function *Fn, SourceLocation Loc) const {
-  if (isFunctionBlockedByProfileList(Fn, Loc))
-    return true;
+ProfileList::ExclusionType
+CodeGenModule::isFunctionBlockedFromProfileInstr(llvm::Function *Fn,
+                                                 SourceLocation Loc) const {
+  auto V = isFunctionBlockedByProfileList(Fn, Loc);
+  if (V != ProfileList::Allow)
+    return V;
 
   auto NumGroups = getCodeGenOpts().ProfileTotalFunctionGroups;
   if (NumGroups > 1) {
     auto Group = llvm::crc32(arrayRefFromStringRef(Fn->getName())) % NumGroups;
     if (Group != getCodeGenOpts().ProfileSelectedFunctionGroup)
-      return true;
+      return ProfileList::Skip;
   }
-  return false;
+  return ProfileList::Allow;
 }
 
 bool CodeGenModule::MustBeEmitted(const ValueDecl *Global) {

diff  --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index 5fbcc5ad1f5fe..14c791f4bce57 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -1351,13 +1351,14 @@ class CodeGenModule : public CodeGenTypeCache {
 
   /// \returns true if \p Fn at \p Loc should be excluded from profile
   /// instrumentation by the SCL passed by \p -fprofile-list.
-  bool isFunctionBlockedByProfileList(llvm::Function *Fn,
-                                      SourceLocation Loc) const;
+  ProfileList::ExclusionType
+  isFunctionBlockedByProfileList(llvm::Function *Fn, SourceLocation Loc) const;
 
   /// \returns true if \p Fn at \p Loc should be excluded from profile
   /// instrumentation.
-  bool isFunctionBlockedFromProfileInstr(llvm::Function *Fn,
-                                         SourceLocation Loc) const;
+  ProfileList::ExclusionType
+  isFunctionBlockedFromProfileInstr(llvm::Function *Fn,
+                                    SourceLocation Loc) const;
 
   SanitizerMetadata *getSanitizerMetadata() {
     return SanitizerMD.get();

diff  --git a/clang/test/CodeGen/profile-filter-new.c b/clang/test/CodeGen/profile-filter-new.c
new file mode 100644
index 0000000000000..c6fdc31abbc21
--- /dev/null
+++ b/clang/test/CodeGen/profile-filter-new.c
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -fprofile-instrument=llvm -emit-llvm %s -o - | FileCheck %s --implicit-check-not="; {{.* (noprofile|skipprofile)}}"
+
+// RUN: echo -e "[llvm]\nfunction:foo=skip" > %t0.list
+// RUN: %clang_cc1 -fprofile-instrument=llvm -fprofile-list=%t0.list -emit-llvm %s -o - | FileCheck %s --implicit-check-not="; {{.* (noprofile|skipprofile)}}" --check-prefixes=CHECK,SKIP-FOO
+
+// RUN: echo -e "[csllvm]\nfunction:bar=forbid" > %t1.list
+// RUN: %clang_cc1 -fprofile-instrument=csllvm -fprofile-list=%t1.list -emit-llvm %s -o - | FileCheck %s --implicit-check-not="; {{.* (noprofile|skipprofile)}}" --check-prefixes=CHECK,FORBID-BAR
+// RUN: %clang_cc1 -fprofile-instrument=llvm -fprofile-list=%t1.list -emit-llvm %s -o - | FileCheck %s --implicit-check-not="; {{.* (noprofile|skipprofile)}}"
+
+// RUN: echo -e "[llvm]\ndefault:forbid\nfunction:foo=allow" > %t2.list
+// RUN: %clang_cc1 -fprofile-instrument=llvm -fprofile-list=%t2.list -emit-llvm %s -o - | FileCheck %s --implicit-check-not="; {{.* (noprofile|skipprofile)}}" --check-prefixes=CHECK,FORBID
+
+// RUN: echo -e "[llvm]\nsource:%s=forbid\nfunction:foo=allow" | sed -e 's/\\/\\\\/g' > %t2.list
+// RUN: %clang_cc1 -fprofile-instrument=llvm -fprofile-list=%t2.list -emit-llvm %s -o - | FileCheck %s --implicit-check-not="; {{.* (noprofile|skipprofile)}}" --check-prefixes=CHECK,FORBID
+
+// SKIP-FOO: skipprofile
+// CHECK-LABEL: define {{.*}} @foo
+int foo(int a) { return 4 * a + 1; }
+
+// FORBID-BAR: noprofile
+// FORBID: noprofile
+// CHECK-LABEL: define {{.*}} @bar
+int bar(int a) { return 4 * a + 2; }
+
+// FORBID: noprofile
+// CHECK-LABEL: define {{.*}} @goo
+int goo(int a) { return 4 * a + 3; }

diff  --git a/clang/test/CodeGen/profile-function-groups.c b/clang/test/CodeGen/profile-function-groups.c
index 232abd767a8fd..052e867645944 100644
--- a/clang/test/CodeGen/profile-function-groups.c
+++ b/clang/test/CodeGen/profile-function-groups.c
@@ -4,21 +4,21 @@
 
 // Group 0
 
-// SELECT1: noprofile
-// SELECT2: noprofile
+// SELECT1: skipprofile
+// SELECT2: skipprofile
 // CHECK: define {{.*}} @hoo()
 void hoo() {}
 
 // Group 1
-// SELECT0: noprofile
+// SELECT0: skipprofile
 
-// SELECT2: noprofile
+// SELECT2: skipprofile
 // CHECK: define {{.*}} @goo()
 void goo() {}
 
 // Group 2
-// SELECT0: noprofile
-// SELECT1: noprofile
+// SELECT0: skipprofile
+// SELECT1: skipprofile
 
 // CHECK: define {{.*}} @boo()
 void boo() {}


        


More information about the cfe-commits mailing list