forked from OSchip/llvm-project
Support for instrumenting only selected files or functions
This change implements support for applying profile instrumentation only to selected files or functions. The implementation uses the sanitizer special case list format to select which files and functions to instrument, and relies on the new noprofile IR attribute to exclude functions from instrumentation. Differential Revision: https://reviews.llvm.org/D94820
This commit is contained in:
parent
32cc5564e2
commit
4edf35f11a
|
@ -2045,6 +2045,12 @@ Set update method of profile counters (atomic,prefer-atomic,single)
|
|||
|
||||
Use instrumentation data for profile-guided optimization. If pathname is a directory, it reads from <pathname>/default.profdata. Otherwise, it reads from file <pathname>.
|
||||
|
||||
.. program:: clang1
|
||||
.. option:: -fprofile-list=<file>
|
||||
.. program:: clang
|
||||
|
||||
Filename defining the list of functions/files to instrument. The file uses the sanitizer special case list format.
|
||||
|
||||
.. option:: -freciprocal-math, -fno-reciprocal-math
|
||||
|
||||
Allow division operations to be reassociated
|
||||
|
|
|
@ -64,6 +64,51 @@ To compile code with coverage enabled, pass ``-fprofile-instr-generate
|
|||
Note that linking together code with and without coverage instrumentation is
|
||||
supported. Uninstrumented code simply won't be accounted for in reports.
|
||||
|
||||
Instrumenting only selected files or functions
|
||||
----------------------------------------------
|
||||
|
||||
Sometimes it's useful to only instrument certain files or functions. For
|
||||
example in automated testing infrastructure, it may be desirable to only
|
||||
instrument files or functions that were modified by a patch to reduce the
|
||||
overhead of instrumenting a full system.
|
||||
|
||||
This can be done using the ``-fprofile-list=file.list`` option. The option
|
||||
can be specified multiple times to pass multiple files:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ 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
|
||||
|
||||
The file uses :doc:`SanitizerSpecialCaseList` format. 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. For example:
|
||||
|
||||
.. 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.
|
||||
|
||||
Running the instrumented program
|
||||
================================
|
||||
|
||||
|
|
|
@ -2268,6 +2268,17 @@ programs using the same instrumentation method as ``-fprofile-generate``.
|
|||
This option currently works with ``-fprofile-arcs`` and ``-fprofile-instr-generate``,
|
||||
but not with ``-fprofile-generate``.
|
||||
|
||||
.. option:: -fprofile-list=<pathname>
|
||||
|
||||
This option can be used to apply profile instrumentation only to selected
|
||||
files or functions. ``pathname`` specifies a file in the sanitizer special
|
||||
case list format which selects which files and functions to instrument.
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ echo "fun:test" > fun.list
|
||||
$ clang++ -O2 -fprofile-instr-generate -fprofile-list=fun.list code.cc -o code
|
||||
|
||||
Disabling Instrumentation
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@ -3740,6 +3751,8 @@ Execute ``clang-cl /?`` to see a list of supported options:
|
|||
Use instrumentation data for profile-guided optimization
|
||||
-fprofile-remapping-file=<file>
|
||||
Use the remappings described in <file> to match the profile data against names in the program
|
||||
-fprofile-list=<file>
|
||||
Filename defining the list of functions/files to instrument
|
||||
-fsanitize-address-field-padding=<value>
|
||||
Level of field padding for AddressSanitizer
|
||||
-fsanitize-address-globals-dead-stripping
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "clang/Basic/Linkage.h"
|
||||
#include "clang/Basic/OperatorKinds.h"
|
||||
#include "clang/Basic/PartialDiagnostic.h"
|
||||
#include "clang/Basic/ProfileList.h"
|
||||
#include "clang/Basic/SanitizerBlacklist.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Basic/Specifiers.h"
|
||||
|
@ -566,6 +567,10 @@ private:
|
|||
/// should be imbued with the XRay "always" or "never" attributes.
|
||||
std::unique_ptr<XRayFunctionFilter> XRayFilter;
|
||||
|
||||
/// ProfileList object that is used by the profile instrumentation
|
||||
/// to decide which entities should be instrumented.
|
||||
std::unique_ptr<ProfileList> ProfList;
|
||||
|
||||
/// The allocator used to create AST objects.
|
||||
///
|
||||
/// AST objects are never destructed; rather, all memory associated with the
|
||||
|
@ -691,6 +696,8 @@ public:
|
|||
return *XRayFilter;
|
||||
}
|
||||
|
||||
const ProfileList &getProfileList() const { return *ProfList; }
|
||||
|
||||
DiagnosticsEngine &getDiagnostics() const;
|
||||
|
||||
FullSourceLoc getFullLoc(SourceLocation Loc) const {
|
||||
|
|
|
@ -285,6 +285,10 @@ public:
|
|||
/// attribute(s).
|
||||
std::vector<std::string> XRayAttrListFiles;
|
||||
|
||||
/// Paths to special case list files specifying which entities
|
||||
/// (files, functions) should or should not be instrumented.
|
||||
std::vector<std::string> ProfileListFiles;
|
||||
|
||||
clang::ObjCRuntime ObjCRuntime;
|
||||
|
||||
CoreFoundationABI CFRuntime = CoreFoundationABI::Unspecified;
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
//===--- ProfileList.h - ProfileList filter ---------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// User-provided filters include/exclude profile instrumentation in certain
|
||||
// functions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_CLANG_BASIC_INSTRPROFLIST_H
|
||||
#define LLVM_CLANG_BASIC_INSTRPROFLIST_H
|
||||
|
||||
#include "clang/Basic/CodeGenOptions.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include <memory>
|
||||
|
||||
namespace llvm {
|
||||
class SpecialCaseList;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
|
||||
class ProfileSpecialCaseList;
|
||||
|
||||
class ProfileList {
|
||||
std::unique_ptr<ProfileSpecialCaseList> SCL;
|
||||
const bool Empty;
|
||||
const bool Default;
|
||||
SourceManager &SM;
|
||||
|
||||
public:
|
||||
ProfileList(ArrayRef<std::string> Paths, SourceManager &SM);
|
||||
~ProfileList();
|
||||
|
||||
bool isEmpty() const { return Empty; }
|
||||
bool getDefault() const { return Default; }
|
||||
|
||||
llvm::Optional<bool>
|
||||
isFunctionExcluded(StringRef FunctionName,
|
||||
CodeGenOptions::ProfileInstrKind Kind) const;
|
||||
llvm::Optional<bool>
|
||||
isLocationExcluded(SourceLocation Loc,
|
||||
CodeGenOptions::ProfileInstrKind Kind) const;
|
||||
llvm::Optional<bool>
|
||||
isFileExcluded(StringRef FileName,
|
||||
CodeGenOptions::ProfileInstrKind Kind) const;
|
||||
};
|
||||
|
||||
} // namespace clang
|
||||
|
||||
#endif
|
|
@ -1151,6 +1151,10 @@ defm pseudo_probe_for_profiling : BoolFOption<"pseudo-probe-for-profiling",
|
|||
def forder_file_instrumentation : Flag<["-"], "forder-file-instrumentation">,
|
||||
Group<f_Group>, Flags<[CC1Option, CoreOption]>,
|
||||
HelpText<"Generate instrumented code to collect order file into default.profraw file (overridden by '=' form of option or LLVM_PROFILE_FILE env var)">;
|
||||
def fprofile_list_EQ : Joined<["-"], "fprofile-list=">,
|
||||
Group<f_Group>, Flags<[CC1Option, CoreOption]>,
|
||||
HelpText<"Filename defining the list of functions/files to instrument">,
|
||||
MarshallingInfoStringVector<LangOpts<"ProfileListFiles">>;
|
||||
|
||||
defm addrsig : BoolFOption<"addrsig",
|
||||
CodeGenOpts<"Addrsig">, DefaultFalse,
|
||||
|
|
|
@ -965,6 +965,7 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM,
|
|||
XRayFilter(new XRayFunctionFilter(LangOpts.XRayAlwaysInstrumentFiles,
|
||||
LangOpts.XRayNeverInstrumentFiles,
|
||||
LangOpts.XRayAttrListFiles, SM)),
|
||||
ProfList(new ProfileList(LangOpts.ProfileListFiles, SM)),
|
||||
PrintingPolicy(LOpts), Idents(idents), Selectors(sels),
|
||||
BuiltinInfo(builtins), DeclarationNames(*this), Comments(SM),
|
||||
CommentCommandTraits(BumpAlloc, LOpts.CommentOpts),
|
||||
|
|
|
@ -59,6 +59,7 @@ add_clang_library(clangBasic
|
|||
OpenCLOptions.cpp
|
||||
OpenMPKinds.cpp
|
||||
OperatorPrecedence.cpp
|
||||
ProfileList.cpp
|
||||
SanitizerBlacklist.cpp
|
||||
SanitizerSpecialCaseList.cpp
|
||||
Sanitizers.cpp
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
//===--- ProfileList.h - ProfileList filter ---------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// User-provided filters include/exclude profile instrumentation in certain
|
||||
// functions or files.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Basic/ProfileList.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "llvm/Support/SpecialCaseList.h"
|
||||
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
namespace clang {
|
||||
|
||||
class ProfileSpecialCaseList : public llvm::SpecialCaseList {
|
||||
public:
|
||||
static std::unique_ptr<ProfileSpecialCaseList>
|
||||
create(const std::vector<std::string> &Paths, llvm::vfs::FileSystem &VFS,
|
||||
std::string &Error);
|
||||
|
||||
static std::unique_ptr<ProfileSpecialCaseList>
|
||||
createOrDie(const std::vector<std::string> &Paths,
|
||||
llvm::vfs::FileSystem &VFS);
|
||||
|
||||
bool isEmpty() const { return Sections.empty(); }
|
||||
|
||||
bool hasPrefix(StringRef Prefix) const {
|
||||
for (auto &SectionIter : Sections)
|
||||
if (SectionIter.Entries.count(Prefix) > 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<ProfileSpecialCaseList>
|
||||
ProfileSpecialCaseList::create(const std::vector<std::string> &Paths,
|
||||
llvm::vfs::FileSystem &VFS,
|
||||
std::string &Error) {
|
||||
auto PSCL = std::make_unique<ProfileSpecialCaseList>();
|
||||
if (PSCL->createInternal(Paths, VFS, Error))
|
||||
return PSCL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<ProfileSpecialCaseList>
|
||||
ProfileSpecialCaseList::createOrDie(const std::vector<std::string> &Paths,
|
||||
llvm::vfs::FileSystem &VFS) {
|
||||
std::string Error;
|
||||
if (auto PSCL = create(Paths, VFS, Error))
|
||||
return PSCL;
|
||||
llvm::report_fatal_error(Error);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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) {}
|
||||
|
||||
ProfileList::~ProfileList() = default;
|
||||
|
||||
static StringRef getSectionName(CodeGenOptions::ProfileInstrKind Kind) {
|
||||
switch (Kind) {
|
||||
case CodeGenOptions::ProfileNone:
|
||||
return "";
|
||||
case CodeGenOptions::ProfileClangInstr:
|
||||
return "clang";
|
||||
case CodeGenOptions::ProfileIRInstr:
|
||||
return "llvm";
|
||||
case CodeGenOptions::ProfileCSIRInstr:
|
||||
return "csllvm";
|
||||
}
|
||||
}
|
||||
|
||||
llvm::Optional<bool>
|
||||
ProfileList::isFunctionExcluded(StringRef FunctionName,
|
||||
CodeGenOptions::ProfileInstrKind Kind) const {
|
||||
StringRef Section = getSectionName(Kind);
|
||||
if (SCL->inSection(Section, "!fun", FunctionName))
|
||||
return true;
|
||||
if (SCL->inSection(Section, "fun", FunctionName))
|
||||
return false;
|
||||
return None;
|
||||
}
|
||||
|
||||
llvm::Optional<bool>
|
||||
ProfileList::isLocationExcluded(SourceLocation Loc,
|
||||
CodeGenOptions::ProfileInstrKind Kind) const {
|
||||
return isFileExcluded(SM.getFilename(SM.getFileLoc(Loc)), Kind);
|
||||
}
|
||||
|
||||
llvm::Optional<bool>
|
||||
ProfileList::isFileExcluded(StringRef FileName,
|
||||
CodeGenOptions::ProfileInstrKind Kind) const {
|
||||
StringRef Section = getSectionName(Kind);
|
||||
if (SCL->inSection(Section, "!src", FileName))
|
||||
return true;
|
||||
if (SCL->inSection(Section, "src", FileName))
|
||||
return false;
|
||||
return None;
|
||||
}
|
|
@ -839,6 +839,10 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
|
|||
}
|
||||
}
|
||||
|
||||
if (CGM.getCodeGenOpts().getProfileInstr() != CodeGenOptions::ProfileNone)
|
||||
if (CGM.isProfileInstrExcluded(Fn, Loc))
|
||||
Fn->addFnAttr(llvm::Attribute::NoProfile);
|
||||
|
||||
unsigned Count, Offset;
|
||||
if (const auto *Attr =
|
||||
D ? D->getAttr<PatchableFunctionEntryAttr>() : nullptr) {
|
||||
|
|
|
@ -1442,7 +1442,8 @@ public:
|
|||
/// Increment the profiler's counter for the given statement by \p StepV.
|
||||
/// If \p StepV is null, the default increment is 1.
|
||||
void incrementProfileCounter(const Stmt *S, llvm::Value *StepV = nullptr) {
|
||||
if (CGM.getCodeGenOpts().hasProfileClangInstr())
|
||||
if (CGM.getCodeGenOpts().hasProfileClangInstr() &&
|
||||
!CurFn->hasFnAttribute(llvm::Attribute::NoProfile))
|
||||
PGO.emitCounterIncrement(Builder, S, StepV);
|
||||
PGO.setCurrentStmt(S);
|
||||
}
|
||||
|
|
|
@ -2563,6 +2563,34 @@ bool CodeGenModule::imbueXRayAttrs(llvm::Function *Fn, SourceLocation Loc,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CodeGenModule::isProfileInstrExcluded(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;
|
||||
CodeGenOptions::ProfileInstrKind Kind = getCodeGenOpts().getProfileInstr();
|
||||
// First, check the function name.
|
||||
Optional<bool> V = ProfileList.isFunctionExcluded(Fn->getName(), Kind);
|
||||
if (V.hasValue())
|
||||
return *V;
|
||||
// Next, check the source location.
|
||||
if (Loc.isValid()) {
|
||||
Optional<bool> V = ProfileList.isLocationExcluded(Loc, Kind);
|
||||
if (V.hasValue())
|
||||
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.hasValue())
|
||||
return *V;
|
||||
}
|
||||
return ProfileList.getDefault();
|
||||
}
|
||||
|
||||
bool CodeGenModule::MustBeEmitted(const ValueDecl *Global) {
|
||||
// Never defer when EmitAllDecls is specified.
|
||||
if (LangOpts.EmitAllDecls)
|
||||
|
|
|
@ -1277,6 +1277,10 @@ public:
|
|||
bool imbueXRayAttrs(llvm::Function *Fn, SourceLocation Loc,
|
||||
StringRef Category = StringRef()) const;
|
||||
|
||||
/// Returns true if function at the given location should be excluded from
|
||||
/// profile instrumentation.
|
||||
bool isProfileInstrExcluded(llvm::Function *Fn, SourceLocation Loc) const;
|
||||
|
||||
SanitizerMetadata *getSanitizerMetadata() {
|
||||
return SanitizerMD.get();
|
||||
}
|
||||
|
|
|
@ -811,6 +811,9 @@ void CodeGenPGO::assignRegionCounters(GlobalDecl GD, llvm::Function *Fn) {
|
|||
if (isa<CXXDestructorDecl>(D) && GD.getDtorType() != Dtor_Base)
|
||||
return;
|
||||
|
||||
if (Fn->hasFnAttribute(llvm::Attribute::NoProfile))
|
||||
return;
|
||||
|
||||
CGM.ClearUnusedCoverageMapping(D);
|
||||
setFuncName(Fn);
|
||||
|
||||
|
|
|
@ -5515,6 +5515,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
|
|||
const XRayArgs &XRay = TC.getXRayArgs();
|
||||
XRay.addArgs(TC, Args, CmdArgs, InputType);
|
||||
|
||||
for (const auto &Filename :
|
||||
Args.getAllArgValues(options::OPT_fprofile_list_EQ)) {
|
||||
if (D.getVFS().exists(Filename))
|
||||
CmdArgs.push_back(Args.MakeArgString("-fprofile-list=" + Filename));
|
||||
else
|
||||
D.Diag(clang::diag::err_drv_no_such_file) << Filename;
|
||||
}
|
||||
|
||||
if (Arg *A = Args.getLastArg(options::OPT_fpatchable_function_entry_EQ)) {
|
||||
StringRef S0 = A->getValue(), S = S0;
|
||||
unsigned Size, Offset = 0;
|
||||
|
|
|
@ -1355,6 +1355,10 @@ static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts,
|
|||
}
|
||||
}
|
||||
|
||||
// -fprofile-list= dependencies.
|
||||
for (const auto &Filename : Args.getAllArgValues(OPT_fprofile_list_EQ))
|
||||
Opts.ExtraDeps.push_back(Filename);
|
||||
|
||||
// Propagate the extra dependencies.
|
||||
for (const auto *A : Args.filtered(OPT_fdepfile_entry)) {
|
||||
Opts.ExtraDeps.push_back(A->getValue());
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
// RUN: %clang_cc1 -fprofile-instrument=clang -emit-llvm %s -o - | FileCheck %s
|
||||
|
||||
// RUN: echo "fun:test1" > %t-func.list
|
||||
// RUN: %clang_cc1 -fprofile-instrument=clang -fprofile-list=%t-func.list -emit-llvm %s -o - | FileCheck %s --check-prefix=FUNC
|
||||
|
||||
// RUN: echo -e "src:%s" | sed -e 's/\\/\\\\/g' > %t-file.list
|
||||
// RUN: %clang_cc1 -fprofile-instrument=clang -fprofile-list=%t-file.list -emit-llvm %s -o - | FileCheck %s --check-prefix=FILE
|
||||
|
||||
// RUN: echo -e "[clang]\nfun:test1\n[llvm]\nfun:test2" > %t-section.list
|
||||
// RUN: %clang_cc1 -fprofile-instrument=llvm -fprofile-list=%t-section.list -emit-llvm %s -o - | FileCheck %s --check-prefix=SECTION
|
||||
|
||||
// RUN: echo -e "fun:test*\n!fun:test1" | sed -e 's/\\/\\\\/g' > %t-exclude.list
|
||||
// RUN: %clang_cc1 -fprofile-instrument=clang -fprofile-list=%t-exclude.list -emit-llvm %s -o - | FileCheck %s --check-prefix=EXCLUDE
|
||||
|
||||
// RUN: echo -e "!fun:test1" | sed -e 's/\\/\\\\/g' > %t-exclude-only.list
|
||||
// RUN: %clang_cc1 -fprofile-instrument=clang -fprofile-list=%t-exclude-only.list -emit-llvm %s -o - | FileCheck %s --check-prefix=EXCLUDE
|
||||
|
||||
unsigned i;
|
||||
|
||||
// CHECK-NOT: noprofile
|
||||
// CHECK: @test1
|
||||
// FUNC-NOT: noprofile
|
||||
// FUNC: @test1
|
||||
// FILE-NOT: noprofile
|
||||
// FILE: @test1
|
||||
// SECTION: noprofile
|
||||
// SECTION: @test1
|
||||
// EXCLUDE: noprofile
|
||||
// EXCLUDE: @test1
|
||||
unsigned test1() {
|
||||
// CHECK: %pgocount = load i64, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__profc_test1, i64 0, i64 0), align 8
|
||||
// FUNC: %pgocount = load i64, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__profc_test1, i64 0, i64 0), align 8
|
||||
// FILE: %pgocount = load i64, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__profc_test1, i64 0, i64 0), align 8
|
||||
// SECTION-NOT: %pgocount = load i64, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__profc_test1, i64 0, i64 0), align 8
|
||||
// EXCLUDE-NOT: %pgocount = load i64, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__profc_test1, i64 0, i64 0), align 8
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
// CHECK-NOT: noprofile
|
||||
// CHECK: @test2
|
||||
// FUNC: noprofile
|
||||
// FUNC: @test2
|
||||
// FILE-NOT: noprofile
|
||||
// FILE: @test2
|
||||
// SECTION-NOT: noprofile
|
||||
// SECTION: @test2
|
||||
// EXCLUDE-NOT: noprofile
|
||||
// EXCLUDE: @test2
|
||||
unsigned test2() {
|
||||
// CHECK: %pgocount = load i64, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__profc_test2, i64 0, i64 0), align 8
|
||||
// FUNC-NOT: %pgocount = load i64, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__profc_test2, i64 0, i64 0), align 8
|
||||
// FILE: %pgocount = load i64, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__profc_test2, i64 0, i64 0), align 8
|
||||
// SECTION: %pgocount = load i64, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__profc_test2, i64 0, i64 0), align 8
|
||||
// EXCLUDE: %pgocount = load i64, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @__profc_test2, i64 0, i64 0), align 8
|
||||
return i - 1;
|
||||
}
|
|
@ -656,6 +656,7 @@ enum AttributeKindCodes {
|
|||
ATTR_KIND_MUSTPROGRESS = 70,
|
||||
ATTR_KIND_NO_CALLBACK = 71,
|
||||
ATTR_KIND_HOT = 72,
|
||||
ATTR_KIND_NO_PROFILE = 73,
|
||||
};
|
||||
|
||||
enum ComdatSelectionKindCodes {
|
||||
|
|
|
@ -148,6 +148,9 @@ def NoSync : EnumAttr<"nosync">;
|
|||
/// Disable Indirect Branch Tracking.
|
||||
def NoCfCheck : EnumAttr<"nocf_check">;
|
||||
|
||||
/// Function should be instrumented.
|
||||
def NoProfile : EnumAttr<"noprofile">;
|
||||
|
||||
/// Function doesn't unwind stack.
|
||||
def NoUnwind : EnumAttr<"nounwind">;
|
||||
|
||||
|
|
|
@ -663,6 +663,7 @@ lltok::Kind LLLexer::LexIdentifier() {
|
|||
KEYWORD(nonlazybind);
|
||||
KEYWORD(nomerge);
|
||||
KEYWORD(nonnull);
|
||||
KEYWORD(noprofile);
|
||||
KEYWORD(noredzone);
|
||||
KEYWORD(noreturn);
|
||||
KEYWORD(nosync);
|
||||
|
|
|
@ -1368,6 +1368,7 @@ bool LLParser::parseFnAttributeValuePairs(AttrBuilder &B,
|
|||
case lltok::kw_noreturn: B.addAttribute(Attribute::NoReturn); break;
|
||||
case lltok::kw_nosync: B.addAttribute(Attribute::NoSync); break;
|
||||
case lltok::kw_nocf_check: B.addAttribute(Attribute::NoCfCheck); break;
|
||||
case lltok::kw_noprofile: B.addAttribute(Attribute::NoProfile); break;
|
||||
case lltok::kw_norecurse: B.addAttribute(Attribute::NoRecurse); break;
|
||||
case lltok::kw_nounwind: B.addAttribute(Attribute::NoUnwind); break;
|
||||
case lltok::kw_null_pointer_is_valid:
|
||||
|
@ -1778,6 +1779,7 @@ bool LLParser::parseOptionalParamAttrs(AttrBuilder &B) {
|
|||
case lltok::kw_noinline:
|
||||
case lltok::kw_nonlazybind:
|
||||
case lltok::kw_nomerge:
|
||||
case lltok::kw_noprofile:
|
||||
case lltok::kw_noredzone:
|
||||
case lltok::kw_noreturn:
|
||||
case lltok::kw_nocf_check:
|
||||
|
@ -1886,6 +1888,7 @@ bool LLParser::parseOptionalReturnAttrs(AttrBuilder &B) {
|
|||
case lltok::kw_noinline:
|
||||
case lltok::kw_nonlazybind:
|
||||
case lltok::kw_nomerge:
|
||||
case lltok::kw_noprofile:
|
||||
case lltok::kw_noredzone:
|
||||
case lltok::kw_noreturn:
|
||||
case lltok::kw_nocf_check:
|
||||
|
|
|
@ -210,6 +210,7 @@ enum Kind {
|
|||
kw_nonlazybind,
|
||||
kw_nomerge,
|
||||
kw_nonnull,
|
||||
kw_noprofile,
|
||||
kw_noredzone,
|
||||
kw_noreturn,
|
||||
kw_nosync,
|
||||
|
|
|
@ -680,6 +680,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
|
|||
return bitc::ATTR_KIND_NOSYNC;
|
||||
case Attribute::NoCfCheck:
|
||||
return bitc::ATTR_KIND_NOCF_CHECK;
|
||||
case Attribute::NoProfile:
|
||||
return bitc::ATTR_KIND_NO_PROFILE;
|
||||
case Attribute::NoUnwind:
|
||||
return bitc::ATTR_KIND_NO_UNWIND;
|
||||
case Attribute::NullPointerIsValid:
|
||||
|
|
|
@ -403,6 +403,8 @@ std::string Attribute::getAsString(bool InAttrGrp) const {
|
|||
return "nocf_check";
|
||||
if (hasAttribute(Attribute::NoRecurse))
|
||||
return "norecurse";
|
||||
if (hasAttribute(Attribute::NoProfile))
|
||||
return "noprofile";
|
||||
if (hasAttribute(Attribute::NoUnwind))
|
||||
return "nounwind";
|
||||
if (hasAttribute(Attribute::OptForFuzzing))
|
||||
|
|
|
@ -1655,6 +1655,7 @@ static bool isFuncOnlyAttr(Attribute::AttrKind Kind) {
|
|||
case Attribute::StrictFP:
|
||||
case Attribute::NullPointerIsValid:
|
||||
case Attribute::MustProgress:
|
||||
case Attribute::NoProfile:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -1591,6 +1591,8 @@ static bool InstrumentAllFunctions(
|
|||
for (auto &F : M) {
|
||||
if (F.isDeclaration())
|
||||
continue;
|
||||
if (F.hasFnAttribute(llvm::Attribute::NoProfile))
|
||||
continue;
|
||||
auto &TLI = LookupTLI(F);
|
||||
auto *BPI = LookupBPI(F);
|
||||
auto *BFI = LookupBFI(F);
|
||||
|
|
|
@ -973,6 +973,7 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs,
|
|||
case Attribute::UWTable:
|
||||
case Attribute::NoCfCheck:
|
||||
case Attribute::MustProgress:
|
||||
case Attribute::NoProfile:
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
; RUN: opt < %s -pgo-instr-gen -S | FileCheck %s
|
||||
; RUN: opt < %s -passes=pgo-instr-gen -S | FileCheck %s
|
||||
|
||||
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
@i = dso_local global i32 0, align 4
|
||||
|
||||
define i32 @test1() {
|
||||
entry:
|
||||
; CHECK: call void @llvm.instrprof.increment
|
||||
%0 = load i32, i32* @i, align 4
|
||||
%add = add i32 %0, 1
|
||||
ret i32 %add
|
||||
}
|
||||
|
||||
define i32 @test2() #0 {
|
||||
entry:
|
||||
; CHECK-NOT: call void @llvm.instrprof.increment
|
||||
%0 = load i32, i32* @i, align 4
|
||||
%sub = sub i32 %0, 1
|
||||
ret i32 %sub
|
||||
}
|
||||
|
||||
attributes #0 = { noprofile }
|
Loading…
Reference in New Issue