1195098Sed//===--- ProfileList.h - ProfileList filter ---------------------*- C++ -*-===//
2195098Sed//
3195098Sed// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4195098Sed// See https://llvm.org/LICENSE.txt for license information.
5195098Sed// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6195098Sed//
7195098Sed//===----------------------------------------------------------------------===//
8195098Sed//
9195098Sed// User-provided filters include/exclude profile instrumentation in certain
10195098Sed// functions or files.
11198090Srdivacky//
12198090Srdivacky//===----------------------------------------------------------------------===//
13195098Sed
14198090Srdivacky#include "clang/Basic/ProfileList.h"
15218893Sdim#include "clang/Basic/FileManager.h"
16195340Sed#include "clang/Basic/SourceManager.h"
17198090Srdivacky#include "llvm/Support/SpecialCaseList.h"
18226633Sdim
19226633Sdim#include "llvm/Support/raw_ostream.h"
20226633Sdim#include <optional>
21198090Srdivacky
22195098Sedusing namespace clang;
23226633Sdim
24205407Srdivackynamespace clang {
25202878Srdivacky
26224145Sdimclass ProfileSpecialCaseList : public llvm::SpecialCaseList {
27202878Srdivackypublic:
28198090Srdivacky  static std::unique_ptr<ProfileSpecialCaseList>
29198090Srdivacky  create(const std::vector<std::string> &Paths, llvm::vfs::FileSystem &VFS,
30198090Srdivacky         std::string &Error);
31202878Srdivacky
32234353Sdim  static std::unique_ptr<ProfileSpecialCaseList>
33218893Sdim  createOrDie(const std::vector<std::string> &Paths,
34195098Sed              llvm::vfs::FileSystem &VFS);
35195098Sed
36195098Sed  bool isEmpty() const { return Sections.empty(); }
37195098Sed
38198090Srdivacky  bool hasPrefix(StringRef Prefix) const {
39224145Sdim    for (auto &SectionIter : Sections)
40202878Srdivacky      if (SectionIter.Entries.count(Prefix) > 0)
41198090Srdivacky        return true;
42224145Sdim    return false;
43205407Srdivacky  }
44212904Sdim};
45226633Sdim
46218893Sdimstd::unique_ptr<ProfileSpecialCaseList>
47202878SrdivackyProfileSpecialCaseList::create(const std::vector<std::string> &Paths,
48202878Srdivacky                               llvm::vfs::FileSystem &VFS,
49203954Srdivacky                               std::string &Error) {
50203954Srdivacky  auto PSCL = std::make_unique<ProfileSpecialCaseList>();
51203954Srdivacky  if (PSCL->createInternal(Paths, VFS, Error))
52218893Sdim    return PSCL;
53221345Sdim  return nullptr;
54234353Sdim}
55203954Srdivacky
56221345Sdimstd::unique_ptr<ProfileSpecialCaseList>
57221345SdimProfileSpecialCaseList::createOrDie(const std::vector<std::string> &Paths,
58221345Sdim                                    llvm::vfs::FileSystem &VFS) {
59221345Sdim  std::string Error;
60221345Sdim  if (auto PSCL = create(Paths, VFS, Error))
61218893Sdim    return PSCL;
62218893Sdim  llvm::report_fatal_error(llvm::Twine(Error));
63223017Sdim}
64234353Sdim
65234353Sdim}
66223017Sdim
67198090SrdivackyProfileList::ProfileList(ArrayRef<std::string> Paths, SourceManager &SM)
68202878Srdivacky    : SCL(ProfileSpecialCaseList::createOrDie(
69221345Sdim          Paths, SM.getFileManager().getVirtualFileSystem())),
70234353Sdim      Empty(SCL->isEmpty()), SM(SM) {}
71218893Sdim
72226633SdimProfileList::~ProfileList() = default;
73218893Sdim
74205218Srdivackystatic StringRef getSectionName(CodeGenOptions::ProfileInstrKind Kind) {
75218893Sdim  switch (Kind) {
76218893Sdim  case CodeGenOptions::ProfileNone:
77234353Sdim    return "";
78234353Sdim  case CodeGenOptions::ProfileClangInstr:
79203954Srdivacky    return "clang";
80203954Srdivacky  case CodeGenOptions::ProfileIRInstr:
81203954Srdivacky    return "llvm";
82198090Srdivacky  case CodeGenOptions::ProfileCSIRInstr:
83195098Sed    return "csllvm";
84202878Srdivacky  }
85202878Srdivacky  llvm_unreachable("Unhandled CodeGenOptions::ProfileInstrKind enum");
86202878Srdivacky}
87202878Srdivacky
88202878SrdivackyProfileList::ExclusionType
89202878SrdivackyProfileList::getDefault(CodeGenOptions::ProfileInstrKind Kind) const {
90202878Srdivacky  StringRef Section = getSectionName(Kind);
91202878Srdivacky  // Check for "default:<type>"
92202878Srdivacky  if (SCL->inSection(Section, "default", "allow"))
93203954Srdivacky    return Allow;
94203954Srdivacky  if (SCL->inSection(Section, "default", "skip"))
95203954Srdivacky    return Skip;
96203954Srdivacky  if (SCL->inSection(Section, "default", "forbid"))
97218893Sdim    return Forbid;
98206274Srdivacky  // If any cases use "fun" or "src", set the default to FORBID.
99206274Srdivacky  if (SCL->hasPrefix("fun") || SCL->hasPrefix("src"))
100203954Srdivacky    return Forbid;
101202878Srdivacky  return Allow;
102202878Srdivacky}
103202878Srdivacky
104202878Srdivackystd::optional<ProfileList::ExclusionType>
105202878SrdivackyProfileList::inSection(StringRef Section, StringRef Prefix,
106203954Srdivacky                       StringRef Query) const {
107203954Srdivacky  if (SCL->inSection(Section, Prefix, Query, "allow"))
108203954Srdivacky    return Allow;
109203954Srdivacky  if (SCL->inSection(Section, Prefix, Query, "skip"))
110202878Srdivacky    return Skip;
111202878Srdivacky  if (SCL->inSection(Section, Prefix, Query, "forbid"))
112202878Srdivacky    return Forbid;
113202878Srdivacky  if (SCL->inSection(Section, Prefix, Query))
114202878Srdivacky    return Allow;
115202878Srdivacky  return std::nullopt;
116202878Srdivacky}
117202878Srdivacky
118203954Srdivackystd::optional<ProfileList::ExclusionType>
119202878SrdivackyProfileList::isFunctionExcluded(StringRef FunctionName,
120202878Srdivacky                                CodeGenOptions::ProfileInstrKind Kind) const {
121202878Srdivacky  StringRef Section = getSectionName(Kind);
122202878Srdivacky  // Check for "function:<regex>=<case>"
123203954Srdivacky  if (auto V = inSection(Section, "function", FunctionName))
124198090Srdivacky    return V;
125198090Srdivacky  if (SCL->inSection(Section, "!fun", FunctionName))
126195098Sed    return Forbid;
127218893Sdim  if (SCL->inSection(Section, "fun", FunctionName))
128195098Sed    return Allow;
129218893Sdim  return std::nullopt;
130218893Sdim}
131218893Sdim
132218893Sdimstd::optional<ProfileList::ExclusionType>
133218893SdimProfileList::isLocationExcluded(SourceLocation Loc,
134218893Sdim                                CodeGenOptions::ProfileInstrKind Kind) const {
135218893Sdim  return isFileExcluded(SM.getFilename(SM.getFileLoc(Loc)), Kind);
136218893Sdim}
137198090Srdivacky
138221345Sdimstd::optional<ProfileList::ExclusionType>
139221345SdimProfileList::isFileExcluded(StringRef FileName,
140202878Srdivacky                            CodeGenOptions::ProfileInstrKind Kind) const {
141239462Sdim  StringRef Section = getSectionName(Kind);
142218893Sdim  // Check for "source:<regex>=<case>"
143195098Sed  if (auto V = inSection(Section, "source", FileName))
144198090Srdivacky    return V;
145218893Sdim  if (SCL->inSection(Section, "!src", FileName))
146218893Sdim    return Forbid;
147218893Sdim  if (SCL->inSection(Section, "src", FileName))
148224145Sdim    return Allow;
149224145Sdim  return std::nullopt;
150221345Sdim}
151221345Sdim