This revision was automatically updated to reflect the committed changes.
Closed by commit rG4edf35f11a9e: Support for instrumenting only selected files
or functions (authored by phosek).
Changed prior to commit:
https://reviews.llvm.org/D94820?vs=318257&id=319359#toc
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D94820/new/
https://reviews.llvm.org/D94820
Files:
clang/docs/ClangCommandLineReference.rst
clang/docs/SourceBasedCodeCoverage.rst
clang/docs/UsersManual.rst
clang/include/clang/AST/ASTContext.h
clang/include/clang/Basic/LangOptions.h
clang/include/clang/Basic/ProfileList.h
clang/include/clang/Driver/Options.td
clang/lib/AST/ASTContext.cpp
clang/lib/Basic/CMakeLists.txt
clang/lib/Basic/ProfileList.cpp
clang/lib/CodeGen/CodeGenFunction.cpp
clang/lib/CodeGen/CodeGenFunction.h
clang/lib/CodeGen/CodeGenModule.cpp
clang/lib/CodeGen/CodeGenModule.h
clang/lib/CodeGen/CodeGenPGO.cpp
clang/lib/Driver/ToolChains/Clang.cpp
clang/lib/Frontend/CompilerInvocation.cpp
clang/test/CodeGen/profile-filter.c
llvm/include/llvm/Bitcode/LLVMBitCodes.h
llvm/include/llvm/IR/Attributes.td
llvm/lib/AsmParser/LLLexer.cpp
llvm/lib/AsmParser/LLParser.cpp
llvm/lib/AsmParser/LLToken.h
llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
llvm/lib/IR/Attributes.cpp
llvm/lib/IR/Verifier.cpp
llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp
llvm/lib/Transforms/Utils/CodeExtractor.cpp
llvm/test/Transforms/PGOProfile/noprofile.ll
Index: llvm/test/Transforms/PGOProfile/noprofile.ll
===================================================================
--- /dev/null
+++ llvm/test/Transforms/PGOProfile/noprofile.ll
@@ -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 }
Index: llvm/lib/Transforms/Utils/CodeExtractor.cpp
===================================================================
--- llvm/lib/Transforms/Utils/CodeExtractor.cpp
+++ llvm/lib/Transforms/Utils/CodeExtractor.cpp
@@ -973,6 +973,7 @@
case Attribute::UWTable:
case Attribute::NoCfCheck:
case Attribute::MustProgress:
+ case Attribute::NoProfile:
break;
}
Index: llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp
===================================================================
--- llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp
+++ llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp
@@ -1591,6 +1591,8 @@
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);
Index: llvm/lib/IR/Verifier.cpp
===================================================================
--- llvm/lib/IR/Verifier.cpp
+++ llvm/lib/IR/Verifier.cpp
@@ -1655,6 +1655,7 @@
case Attribute::StrictFP:
case Attribute::NullPointerIsValid:
case Attribute::MustProgress:
+ case Attribute::NoProfile:
return true;
default:
break;
Index: llvm/lib/IR/Attributes.cpp
===================================================================
--- llvm/lib/IR/Attributes.cpp
+++ llvm/lib/IR/Attributes.cpp
@@ -403,6 +403,8 @@
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))
Index: llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
===================================================================
--- llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -680,6 +680,8 @@
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:
Index: llvm/lib/AsmParser/LLToken.h
===================================================================
--- llvm/lib/AsmParser/LLToken.h
+++ llvm/lib/AsmParser/LLToken.h
@@ -210,6 +210,7 @@
kw_nonlazybind,
kw_nomerge,
kw_nonnull,
+ kw_noprofile,
kw_noredzone,
kw_noreturn,
kw_nosync,
Index: llvm/lib/AsmParser/LLParser.cpp
===================================================================
--- llvm/lib/AsmParser/LLParser.cpp
+++ llvm/lib/AsmParser/LLParser.cpp
@@ -1368,6 +1368,7 @@
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 @@
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 @@
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:
Index: llvm/lib/AsmParser/LLLexer.cpp
===================================================================
--- llvm/lib/AsmParser/LLLexer.cpp
+++ llvm/lib/AsmParser/LLLexer.cpp
@@ -663,6 +663,7 @@
KEYWORD(nonlazybind);
KEYWORD(nomerge);
KEYWORD(nonnull);
+ KEYWORD(noprofile);
KEYWORD(noredzone);
KEYWORD(noreturn);
KEYWORD(nosync);
Index: llvm/include/llvm/IR/Attributes.td
===================================================================
--- llvm/include/llvm/IR/Attributes.td
+++ llvm/include/llvm/IR/Attributes.td
@@ -148,6 +148,9 @@
/// 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">;
Index: llvm/include/llvm/Bitcode/LLVMBitCodes.h
===================================================================
--- llvm/include/llvm/Bitcode/LLVMBitCodes.h
+++ llvm/include/llvm/Bitcode/LLVMBitCodes.h
@@ -656,6 +656,7 @@
ATTR_KIND_MUSTPROGRESS = 70,
ATTR_KIND_NO_CALLBACK = 71,
ATTR_KIND_HOT = 72,
+ ATTR_KIND_NO_PROFILE = 73,
};
enum ComdatSelectionKindCodes {
Index: clang/test/CodeGen/profile-filter.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/profile-filter.c
@@ -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;
+}
Index: clang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- clang/lib/Frontend/CompilerInvocation.cpp
+++ clang/lib/Frontend/CompilerInvocation.cpp
@@ -1355,6 +1355,10 @@
}
}
+ // -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());
Index: clang/lib/Driver/ToolChains/Clang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Clang.cpp
+++ clang/lib/Driver/ToolChains/Clang.cpp
@@ -5515,6 +5515,14 @@
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;
Index: clang/lib/CodeGen/CodeGenPGO.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenPGO.cpp
+++ clang/lib/CodeGen/CodeGenPGO.cpp
@@ -811,6 +811,9 @@
if (isa<CXXDestructorDecl>(D) && GD.getDtorType() != Dtor_Base)
return;
+ if (Fn->hasFnAttribute(llvm::Attribute::NoProfile))
+ return;
+
CGM.ClearUnusedCoverageMapping(D);
setFuncName(Fn);
Index: clang/lib/CodeGen/CodeGenModule.h
===================================================================
--- clang/lib/CodeGen/CodeGenModule.h
+++ clang/lib/CodeGen/CodeGenModule.h
@@ -1277,6 +1277,10 @@
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();
}
Index: clang/lib/CodeGen/CodeGenModule.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenModule.cpp
+++ clang/lib/CodeGen/CodeGenModule.cpp
@@ -2563,6 +2563,34 @@
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)
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -1442,7 +1442,8 @@
/// 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);
}
Index: clang/lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.cpp
+++ clang/lib/CodeGen/CodeGenFunction.cpp
@@ -839,6 +839,10 @@
}
}
+ 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) {
Index: clang/lib/Basic/ProfileList.cpp
===================================================================
--- /dev/null
+++ clang/lib/Basic/ProfileList.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;
+}
Index: clang/lib/Basic/CMakeLists.txt
===================================================================
--- clang/lib/Basic/CMakeLists.txt
+++ clang/lib/Basic/CMakeLists.txt
@@ -59,6 +59,7 @@
OpenCLOptions.cpp
OpenMPKinds.cpp
OperatorPrecedence.cpp
+ ProfileList.cpp
SanitizerBlacklist.cpp
SanitizerSpecialCaseList.cpp
Sanitizers.cpp
Index: clang/lib/AST/ASTContext.cpp
===================================================================
--- clang/lib/AST/ASTContext.cpp
+++ clang/lib/AST/ASTContext.cpp
@@ -965,6 +965,7 @@
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),
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -1151,6 +1151,10 @@
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,
Index: clang/include/clang/Basic/ProfileList.h
===================================================================
--- /dev/null
+++ clang/include/clang/Basic/ProfileList.h
@@ -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
Index: clang/include/clang/Basic/LangOptions.h
===================================================================
--- clang/include/clang/Basic/LangOptions.h
+++ clang/include/clang/Basic/LangOptions.h
@@ -285,6 +285,10 @@
/// 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;
Index: clang/include/clang/AST/ASTContext.h
===================================================================
--- clang/include/clang/AST/ASTContext.h
+++ clang/include/clang/AST/ASTContext.h
@@ -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 @@
/// 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 @@
return *XRayFilter;
}
+ const ProfileList &getProfileList() const { return *ProfList; }
+
DiagnosticsEngine &getDiagnostics() const;
FullSourceLoc getFullLoc(SourceLocation Loc) const {
Index: clang/docs/UsersManual.rst
===================================================================
--- clang/docs/UsersManual.rst
+++ clang/docs/UsersManual.rst
@@ -2268,6 +2268,17 @@
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 @@
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
Index: clang/docs/SourceBasedCodeCoverage.rst
===================================================================
--- clang/docs/SourceBasedCodeCoverage.rst
+++ clang/docs/SourceBasedCodeCoverage.rst
@@ -64,6 +64,51 @@
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
================================
Index: clang/docs/ClangCommandLineReference.rst
===================================================================
--- clang/docs/ClangCommandLineReference.rst
+++ clang/docs/ClangCommandLineReference.rst
@@ -2045,6 +2045,12 @@
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
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits