Revert "[InstrProf] Add new format for -fprofile-list="

This reverts commit b692312ca4.
Breaks tests on Windows, see https://reviews.llvm.org/D130808#3699952
This commit is contained in:
Nico Weber 2022-08-04 13:04:59 -04:00
parent 07aaa35f74
commit 0eb7d86f58
8 changed files with 72 additions and 178 deletions

View File

@ -2500,66 +2500,43 @@ 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
$ 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
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.
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.
.. code-block:: console
.. code-block:: none
$ cat fun.list
# The following cases are for clang instrumentation.
[clang]
# all functions whose name starts with foo will be instrumented.
fun:foo*
# We might not want to profile functions that are inlined in many places.
function:inlinedLots=skip
# except for foo1 which will be excluded from instrumentation.
!fun:foo1
# We want to forbid profiling where it might be dangerous.
source:lib/unsafe/*.cc=forbid
# every function in path/to/foo.cc will be instrumented.
src:path/to/foo.cc
# Otherwise we allow profiling.
default:allow
# bar will be instrumented only when using backend instrumentation.
# Recognized section names are clang, llvm and csllvm.
[llvm]
fun:bar
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
# all functions whose name starts with foo will be instrumented.
fun:foo*
# 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
# 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
^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -26,38 +26,25 @@ 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; }
ExclusionType getDefault(CodeGenOptions::ProfileInstrKind Kind) const;
bool getDefault() const { return Default; }
llvm::Optional<ExclusionType>
llvm::Optional<bool>
isFunctionExcluded(StringRef FunctionName,
CodeGenOptions::ProfileInstrKind Kind) const;
llvm::Optional<ExclusionType>
llvm::Optional<bool>
isLocationExcluded(SourceLocation Loc,
CodeGenOptions::ProfileInstrKind Kind) const;
llvm::Optional<ExclusionType>
llvm::Optional<bool>
isFileExcluded(StringRef FileName,
CodeGenOptions::ProfileInstrKind Kind) const;
};

View File

@ -66,7 +66,8 @@ 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()), SM(SM) {}
Empty(SCL->isEmpty()),
Default(SCL->hasPrefix("fun") || SCL->hasPrefix("src")), SM(SM) {}
ProfileList::~ProfileList() = default;
@ -84,66 +85,30 @@ static StringRef getSectionName(CodeGenOptions::ProfileInstrKind Kind) {
llvm_unreachable("Unhandled CodeGenOptions::ProfileInstrKind enum");
}
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>
llvm::Optional<bool>
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 Forbid;
return true;
if (SCL->inSection(Section, "fun", FunctionName))
return Allow;
return false;
return None;
}
llvm::Optional<ProfileList::ExclusionType>
llvm::Optional<bool>
ProfileList::isLocationExcluded(SourceLocation Loc,
CodeGenOptions::ProfileInstrKind Kind) const {
return isFileExcluded(SM.getFilename(SM.getFileLoc(Loc)), Kind);
}
llvm::Optional<ProfileList::ExclusionType>
llvm::Optional<bool>
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 Forbid;
return true;
if (SCL->inSection(Section, "src", FileName))
return Allow;
return false;
return None;
}

View File

@ -851,18 +851,9 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
}
}
if (CGM.getCodeGenOpts().getProfileInstr() != CodeGenOptions::ProfileNone) {
switch (CGM.isFunctionBlockedFromProfileInstr(Fn, Loc)) {
case ProfileList::Skip:
Fn->addFnAttr(llvm::Attribute::SkipProfile);
break;
case ProfileList::Forbid:
if (CGM.getCodeGenOpts().getProfileInstr() != CodeGenOptions::ProfileNone)
if (CGM.isFunctionBlockedFromProfileInstr(Fn, Loc))
Fn->addFnAttr(llvm::Attribute::NoProfile);
break;
case ProfileList::Allow:
break;
}
}
unsigned Count, Offset;
if (const auto *Attr =

View File

@ -2895,44 +2895,46 @@ bool CodeGenModule::imbueXRayAttrs(llvm::Function *Fn, SourceLocation Loc,
return true;
}
ProfileList::ExclusionType
CodeGenModule::isFunctionBlockedByProfileList(llvm::Function *Fn,
SourceLocation Loc) const {
bool 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 ProfileList::Allow;
return false;
CodeGenOptions::ProfileInstrKind Kind = getCodeGenOpts().getProfileInstr();
// First, check the function name.
if (auto V = ProfileList.isFunctionExcluded(Fn->getName(), Kind))
Optional<bool> V = ProfileList.isFunctionExcluded(Fn->getName(), Kind);
if (V)
return *V;
// Next, check the source location.
if (Loc.isValid())
if (auto V = ProfileList.isLocationExcluded(Loc, Kind))
if (Loc.isValid()) {
Optional<bool> V = ProfileList.isLocationExcluded(Loc, Kind);
if (V)
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()))
if (auto V = ProfileList.isFileExcluded(MainFile->getName(), Kind))
if (const auto *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
Optional<bool> V = ProfileList.isFileExcluded(MainFile->getName(), Kind);
if (V)
return *V;
return ProfileList.getDefault(Kind);
}
return ProfileList.getDefault();
}
ProfileList::ExclusionType
CodeGenModule::isFunctionBlockedFromProfileInstr(llvm::Function *Fn,
SourceLocation Loc) const {
auto V = isFunctionBlockedByProfileList(Fn, Loc);
if (V != ProfileList::Allow)
return V;
bool CodeGenModule::isFunctionBlockedFromProfileInstr(
llvm::Function *Fn, SourceLocation Loc) const {
if (isFunctionBlockedByProfileList(Fn, Loc))
return true;
auto NumGroups = getCodeGenOpts().ProfileTotalFunctionGroups;
if (NumGroups > 1) {
auto Group = llvm::crc32(arrayRefFromStringRef(Fn->getName())) % NumGroups;
if (Group != getCodeGenOpts().ProfileSelectedFunctionGroup)
return ProfileList::Skip;
return true;
}
return ProfileList::Allow;
return false;
}
bool CodeGenModule::MustBeEmitted(const ValueDecl *Global) {

View File

@ -1351,14 +1351,13 @@ public:
/// \returns true if \p Fn at \p Loc should be excluded from profile
/// instrumentation by the SCL passed by \p -fprofile-list.
ProfileList::ExclusionType
isFunctionBlockedByProfileList(llvm::Function *Fn, SourceLocation Loc) const;
bool isFunctionBlockedByProfileList(llvm::Function *Fn,
SourceLocation Loc) const;
/// \returns true if \p Fn at \p Loc should be excluded from profile
/// instrumentation.
ProfileList::ExclusionType
isFunctionBlockedFromProfileInstr(llvm::Function *Fn,
SourceLocation Loc) const;
bool isFunctionBlockedFromProfileInstr(llvm::Function *Fn,
SourceLocation Loc) const;
SanitizerMetadata *getSanitizerMetadata() {
return SanitizerMD.get();

View File

@ -1,27 +0,0 @@
// 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; }

View File

@ -4,21 +4,21 @@
// Group 0
// SELECT1: skipprofile
// SELECT2: skipprofile
// SELECT1: noprofile
// SELECT2: noprofile
// CHECK: define {{.*}} @hoo()
void hoo() {}
// Group 1
// SELECT0: skipprofile
// SELECT0: noprofile
// SELECT2: skipprofile
// SELECT2: noprofile
// CHECK: define {{.*}} @goo()
void goo() {}
// Group 2
// SELECT0: skipprofile
// SELECT1: skipprofile
// SELECT0: noprofile
// SELECT1: noprofile
// CHECK: define {{.*}} @boo()
void boo() {}