1a9ac8606Spatrick //===--- ProfileList.h - ProfileList filter ---------------------*- C++ -*-===//
2a9ac8606Spatrick //
3a9ac8606Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a9ac8606Spatrick // See https://llvm.org/LICENSE.txt for license information.
5a9ac8606Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a9ac8606Spatrick //
7a9ac8606Spatrick //===----------------------------------------------------------------------===//
8a9ac8606Spatrick //
9a9ac8606Spatrick // User-provided filters include/exclude profile instrumentation in certain
10a9ac8606Spatrick // functions or files.
11a9ac8606Spatrick //
12a9ac8606Spatrick //===----------------------------------------------------------------------===//
13a9ac8606Spatrick
14a9ac8606Spatrick #include "clang/Basic/ProfileList.h"
15a9ac8606Spatrick #include "clang/Basic/FileManager.h"
16a9ac8606Spatrick #include "clang/Basic/SourceManager.h"
17a9ac8606Spatrick #include "llvm/Support/SpecialCaseList.h"
18a9ac8606Spatrick
19a9ac8606Spatrick #include "llvm/Support/raw_ostream.h"
20*12c85518Srobert #include <optional>
21a9ac8606Spatrick
22a9ac8606Spatrick using namespace clang;
23a9ac8606Spatrick
24a9ac8606Spatrick namespace clang {
25a9ac8606Spatrick
26a9ac8606Spatrick class ProfileSpecialCaseList : public llvm::SpecialCaseList {
27a9ac8606Spatrick public:
28a9ac8606Spatrick static std::unique_ptr<ProfileSpecialCaseList>
29a9ac8606Spatrick create(const std::vector<std::string> &Paths, llvm::vfs::FileSystem &VFS,
30a9ac8606Spatrick std::string &Error);
31a9ac8606Spatrick
32a9ac8606Spatrick static std::unique_ptr<ProfileSpecialCaseList>
33a9ac8606Spatrick createOrDie(const std::vector<std::string> &Paths,
34a9ac8606Spatrick llvm::vfs::FileSystem &VFS);
35a9ac8606Spatrick
isEmpty() const36a9ac8606Spatrick bool isEmpty() const { return Sections.empty(); }
37a9ac8606Spatrick
hasPrefix(StringRef Prefix) const38a9ac8606Spatrick bool hasPrefix(StringRef Prefix) const {
39a9ac8606Spatrick for (auto &SectionIter : Sections)
40a9ac8606Spatrick if (SectionIter.Entries.count(Prefix) > 0)
41a9ac8606Spatrick return true;
42a9ac8606Spatrick return false;
43a9ac8606Spatrick }
44a9ac8606Spatrick };
45a9ac8606Spatrick
46a9ac8606Spatrick std::unique_ptr<ProfileSpecialCaseList>
create(const std::vector<std::string> & Paths,llvm::vfs::FileSystem & VFS,std::string & Error)47a9ac8606Spatrick ProfileSpecialCaseList::create(const std::vector<std::string> &Paths,
48a9ac8606Spatrick llvm::vfs::FileSystem &VFS,
49a9ac8606Spatrick std::string &Error) {
50a9ac8606Spatrick auto PSCL = std::make_unique<ProfileSpecialCaseList>();
51a9ac8606Spatrick if (PSCL->createInternal(Paths, VFS, Error))
52a9ac8606Spatrick return PSCL;
53a9ac8606Spatrick return nullptr;
54a9ac8606Spatrick }
55a9ac8606Spatrick
56a9ac8606Spatrick std::unique_ptr<ProfileSpecialCaseList>
createOrDie(const std::vector<std::string> & Paths,llvm::vfs::FileSystem & VFS)57a9ac8606Spatrick ProfileSpecialCaseList::createOrDie(const std::vector<std::string> &Paths,
58a9ac8606Spatrick llvm::vfs::FileSystem &VFS) {
59a9ac8606Spatrick std::string Error;
60a9ac8606Spatrick if (auto PSCL = create(Paths, VFS, Error))
61a9ac8606Spatrick return PSCL;
62*12c85518Srobert llvm::report_fatal_error(llvm::Twine(Error));
63a9ac8606Spatrick }
64a9ac8606Spatrick
65a9ac8606Spatrick }
66a9ac8606Spatrick
ProfileList(ArrayRef<std::string> Paths,SourceManager & SM)67a9ac8606Spatrick ProfileList::ProfileList(ArrayRef<std::string> Paths, SourceManager &SM)
68a9ac8606Spatrick : SCL(ProfileSpecialCaseList::createOrDie(
69a9ac8606Spatrick Paths, SM.getFileManager().getVirtualFileSystem())),
70*12c85518Srobert Empty(SCL->isEmpty()), SM(SM) {}
71a9ac8606Spatrick
72a9ac8606Spatrick ProfileList::~ProfileList() = default;
73a9ac8606Spatrick
getSectionName(CodeGenOptions::ProfileInstrKind Kind)74a9ac8606Spatrick static StringRef getSectionName(CodeGenOptions::ProfileInstrKind Kind) {
75a9ac8606Spatrick switch (Kind) {
76a9ac8606Spatrick case CodeGenOptions::ProfileNone:
77a9ac8606Spatrick return "";
78a9ac8606Spatrick case CodeGenOptions::ProfileClangInstr:
79a9ac8606Spatrick return "clang";
80a9ac8606Spatrick case CodeGenOptions::ProfileIRInstr:
81a9ac8606Spatrick return "llvm";
82a9ac8606Spatrick case CodeGenOptions::ProfileCSIRInstr:
83a9ac8606Spatrick return "csllvm";
84a9ac8606Spatrick }
85a9ac8606Spatrick llvm_unreachable("Unhandled CodeGenOptions::ProfileInstrKind enum");
86a9ac8606Spatrick }
87a9ac8606Spatrick
88*12c85518Srobert ProfileList::ExclusionType
getDefault(CodeGenOptions::ProfileInstrKind Kind) const89*12c85518Srobert ProfileList::getDefault(CodeGenOptions::ProfileInstrKind Kind) const {
90*12c85518Srobert StringRef Section = getSectionName(Kind);
91*12c85518Srobert // Check for "default:<type>"
92*12c85518Srobert if (SCL->inSection(Section, "default", "allow"))
93*12c85518Srobert return Allow;
94*12c85518Srobert if (SCL->inSection(Section, "default", "skip"))
95*12c85518Srobert return Skip;
96*12c85518Srobert if (SCL->inSection(Section, "default", "forbid"))
97*12c85518Srobert return Forbid;
98*12c85518Srobert // If any cases use "fun" or "src", set the default to FORBID.
99*12c85518Srobert if (SCL->hasPrefix("fun") || SCL->hasPrefix("src"))
100*12c85518Srobert return Forbid;
101*12c85518Srobert return Allow;
102*12c85518Srobert }
103*12c85518Srobert
104*12c85518Srobert std::optional<ProfileList::ExclusionType>
inSection(StringRef Section,StringRef Prefix,StringRef Query) const105*12c85518Srobert ProfileList::inSection(StringRef Section, StringRef Prefix,
106*12c85518Srobert StringRef Query) const {
107*12c85518Srobert if (SCL->inSection(Section, Prefix, Query, "allow"))
108*12c85518Srobert return Allow;
109*12c85518Srobert if (SCL->inSection(Section, Prefix, Query, "skip"))
110*12c85518Srobert return Skip;
111*12c85518Srobert if (SCL->inSection(Section, Prefix, Query, "forbid"))
112*12c85518Srobert return Forbid;
113*12c85518Srobert if (SCL->inSection(Section, Prefix, Query))
114*12c85518Srobert return Allow;
115*12c85518Srobert return std::nullopt;
116*12c85518Srobert }
117*12c85518Srobert
118*12c85518Srobert std::optional<ProfileList::ExclusionType>
isFunctionExcluded(StringRef FunctionName,CodeGenOptions::ProfileInstrKind Kind) const119a9ac8606Spatrick ProfileList::isFunctionExcluded(StringRef FunctionName,
120a9ac8606Spatrick CodeGenOptions::ProfileInstrKind Kind) const {
121a9ac8606Spatrick StringRef Section = getSectionName(Kind);
122*12c85518Srobert // Check for "function:<regex>=<case>"
123*12c85518Srobert if (auto V = inSection(Section, "function", FunctionName))
124*12c85518Srobert return V;
125a9ac8606Spatrick if (SCL->inSection(Section, "!fun", FunctionName))
126*12c85518Srobert return Forbid;
127a9ac8606Spatrick if (SCL->inSection(Section, "fun", FunctionName))
128*12c85518Srobert return Allow;
129*12c85518Srobert return std::nullopt;
130a9ac8606Spatrick }
131a9ac8606Spatrick
132*12c85518Srobert std::optional<ProfileList::ExclusionType>
isLocationExcluded(SourceLocation Loc,CodeGenOptions::ProfileInstrKind Kind) const133a9ac8606Spatrick ProfileList::isLocationExcluded(SourceLocation Loc,
134a9ac8606Spatrick CodeGenOptions::ProfileInstrKind Kind) const {
135a9ac8606Spatrick return isFileExcluded(SM.getFilename(SM.getFileLoc(Loc)), Kind);
136a9ac8606Spatrick }
137a9ac8606Spatrick
138*12c85518Srobert std::optional<ProfileList::ExclusionType>
isFileExcluded(StringRef FileName,CodeGenOptions::ProfileInstrKind Kind) const139a9ac8606Spatrick ProfileList::isFileExcluded(StringRef FileName,
140a9ac8606Spatrick CodeGenOptions::ProfileInstrKind Kind) const {
141a9ac8606Spatrick StringRef Section = getSectionName(Kind);
142*12c85518Srobert // Check for "source:<regex>=<case>"
143*12c85518Srobert if (auto V = inSection(Section, "source", FileName))
144*12c85518Srobert return V;
145a9ac8606Spatrick if (SCL->inSection(Section, "!src", FileName))
146*12c85518Srobert return Forbid;
147a9ac8606Spatrick if (SCL->inSection(Section, "src", FileName))
148*12c85518Srobert return Allow;
149*12c85518Srobert return std::nullopt;
150a9ac8606Spatrick }
151