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