phosek updated this revision to Diff 317796.
phosek marked 3 inline comments as done.
Herald added a reviewer: jansvoboda11.

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D94820/new/

https://reviews.llvm.org/D94820

Files:
  clang/docs/SourceBasedCodeCoverage.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
@@ -974,6 +974,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
@@ -1639,6 +1639,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,53 @@
+// 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
+
+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
@@ -1341,6 +1341,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
@@ -5495,6 +5495,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,12 @@
   bool imbueXRayAttrs(llvm::Function *Fn, SourceLocation Loc,
                       StringRef Category = StringRef()) const;
 
+  /// Returns true if profile instrumentation should be applied to the function
+  /// at the given location. The optional section name parameter can be used to
+  /// to also consider specific instrumentations.
+  bool isProfileInstrumented(llvm::Function *Fn, SourceLocation Loc,
+                             StringRef Section = StringRef()) const;
+
   SanitizerMetadata *getSanitizerMetadata() {
     return SanitizerMD.get();
   }
Index: clang/lib/CodeGen/CodeGenModule.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenModule.cpp
+++ clang/lib/CodeGen/CodeGenModule.cpp
@@ -2561,6 +2561,38 @@
   return true;
 }
 
+bool CodeGenModule::isProfileInstrumented(llvm::Function *Fn,
+                                          SourceLocation Loc,
+                                          StringRef Section) const {
+  if (getCodeGenOpts().hasProfileClangInstr())
+    return false;
+  const auto &ProfileList = getContext().getProfileList();
+  // If the profile list is empty, then instrument everything.
+  if (ProfileList.isEmpty())
+    return true;
+  // Check function first.
+  Optional<bool> V =
+      ProfileList.shouldInstrumentFunction(Fn->getName(), Section);
+  if (V.hasValue())
+    return *V;
+  // Check location next.
+  if (Loc.isValid()) {
+    Optional<bool> V = ProfileList.shouldInstrumentLocation(Loc, Section);
+    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.shouldInstrumentFile(MainFile->getName(), Section);
+    if (V.hasValue())
+      return *V;
+  }
+  return false;
+}
+
 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,23 @@
     }
   }
 
+  if (CGM.getCodeGenOpts().getProfileInstr() != CodeGenOptions::ProfileNone) {
+    auto SectionName = [&]() {
+      switch (CGM.getCodeGenOpts().getProfileInstr()) {
+      case CodeGenOptions::ProfileClangInstr:
+        return "clang";
+      case CodeGenOptions::ProfileIRInstr:
+        return "llvm";
+      case CodeGenOptions::ProfileCSIRInstr:
+        return "csllvm";
+      default:
+        llvm_unreachable("unknown instrumentation type");
+      }
+    };
+    if (!CGM.isProfileInstrumented(Fn, Loc, SectionName()))
+      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,54 @@
+//===--- 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;
+
+ProfileList::ProfileList(ArrayRef<std::string> Paths, SourceManager &SM)
+    : Empty(Paths.empty()),
+      SCL(llvm::SpecialCaseList::createOrDie(
+          Paths, SM.getFileManager().getVirtualFileSystem())),
+      SM(SM) {}
+
+ProfileList::~ProfileList() = default;
+
+llvm::Optional<bool>
+ProfileList::shouldInstrumentFunction(StringRef FunctionName,
+                                      StringRef Section) const {
+  if (SCL->inSection(Section, "!fun", FunctionName))
+    return false;
+  if (SCL->inSection(Section, "fun", FunctionName))
+    return true;
+  return None;
+}
+
+llvm::Optional<bool>
+ProfileList::shouldInstrumentLocation(SourceLocation Loc,
+                                      StringRef Section) const {
+  return shouldInstrumentFile(SM.getFilename(SM.getFileLoc(Loc)), Section);
+}
+
+llvm::Optional<bool>
+ProfileList::shouldInstrumentFile(StringRef FileName, StringRef Section) const {
+  if (SCL->inSection(Section, "!src", FileName))
+    return false;
+  if (SCL->inSection(Section, "src", FileName))
+    return true;
+  return None;
+}
Index: clang/lib/Basic/CMakeLists.txt
===================================================================
--- clang/lib/Basic/CMakeLists.txt
+++ clang/lib/Basic/CMakeLists.txt
@@ -58,6 +58,7 @@
   ObjCRuntime.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
@@ -1176,6 +1176,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", DefaultsToFalse,
Index: clang/include/clang/Basic/ProfileList.h
===================================================================
--- /dev/null
+++ clang/include/clang/Basic/ProfileList.h
@@ -0,0 +1,52 @@
+//===--- 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/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 {
+  const bool Empty;
+  std::unique_ptr<llvm::SpecialCaseList> SCL;
+  SourceManager &SM;
+
+public:
+  ProfileList(ArrayRef<std::string> Paths, SourceManager &SM);
+  ~ProfileList();
+
+  bool isEmpty() const { return Empty; }
+
+  llvm::Optional<bool> shouldInstrumentFunction(StringRef FunctionName,
+                                                StringRef Section) const;
+  llvm::Optional<bool> shouldInstrumentLocation(SourceLocation Loc,
+                                                StringRef Section) const;
+  llvm::Optional<bool> shouldInstrumentFile(StringRef FileName,
+                                            StringRef Section) const;
+};
+
+} // namespace clang
+
+#endif
Index: clang/include/clang/Basic/LangOptions.h
===================================================================
--- clang/include/clang/Basic/LangOptions.h
+++ clang/include/clang/Basic/LangOptions.h
@@ -281,6 +281,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/SourceBasedCodeCoverage.rst
===================================================================
--- clang/docs/SourceBasedCodeCoverage.rst
+++ clang/docs/SourceBasedCodeCoverage.rst
@@ -64,6 +64,46 @@
 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. When set, only
+the files and functions specified in ``file.list`` will be instrumented.  The
+option can be specified multiple times to pass multiple files:
+
+.. code-block:: console
+
+    % clang++ -fprofile-instr-generate -fcoverage-mapping -fprofile-list=file1.list -fprofile-list=file2.list foo.cc -o foo
+
+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
+
 Running the instrumented program
 ================================
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to