xref: /freebsd/contrib/llvm-project/clang/lib/Basic/ProfileList.cpp (revision e64bea71c21eb42e97aa615188ba91f6cce0d36d)
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 <optional>
20 
21 using namespace clang;
22 
23 namespace clang {
24 
25 class ProfileSpecialCaseList : public llvm::SpecialCaseList {
26 public:
27   static std::unique_ptr<ProfileSpecialCaseList>
28   create(const std::vector<std::string> &Paths, llvm::vfs::FileSystem &VFS,
29          std::string &Error);
30 
31   static std::unique_ptr<ProfileSpecialCaseList>
32   createOrDie(const std::vector<std::string> &Paths,
33               llvm::vfs::FileSystem &VFS);
34 
35   bool isEmpty() const { return Sections.empty(); }
36 
37   bool hasPrefix(StringRef Prefix) const {
38     for (const auto &It : Sections)
39       if (It.Entries.count(Prefix) > 0)
40         return true;
41     return false;
42   }
43 };
44 
45 std::unique_ptr<ProfileSpecialCaseList>
46 ProfileSpecialCaseList::create(const std::vector<std::string> &Paths,
47                                llvm::vfs::FileSystem &VFS, std::string &Error) {
48   auto PSCL = std::make_unique<ProfileSpecialCaseList>();
49   if (PSCL->createInternal(Paths, VFS, Error))
50     return PSCL;
51   return nullptr;
52 }
53 
54 std::unique_ptr<ProfileSpecialCaseList>
55 ProfileSpecialCaseList::createOrDie(const std::vector<std::string> &Paths,
56                                     llvm::vfs::FileSystem &VFS) {
57   std::string Error;
58   if (auto PSCL = create(Paths, VFS, Error))
59     return PSCL;
60   llvm::report_fatal_error(llvm::Twine(Error));
61 }
62 
63 } // namespace clang
64 
65 ProfileList::ProfileList(ArrayRef<std::string> Paths, SourceManager &SM)
66     : SCL(ProfileSpecialCaseList::createOrDie(
67           Paths, SM.getFileManager().getVirtualFileSystem())),
68       Empty(SCL->isEmpty()), SM(SM) {}
69 
70 ProfileList::~ProfileList() = default;
71 
72 static StringRef getSectionName(llvm::driver::ProfileInstrKind Kind) {
73   switch (Kind) {
74   case llvm::driver::ProfileInstrKind::ProfileNone:
75     return "";
76   case llvm::driver::ProfileInstrKind::ProfileClangInstr:
77     return "clang";
78   case llvm::driver::ProfileInstrKind::ProfileIRInstr:
79     return "llvm";
80   case llvm::driver::ProfileInstrKind::ProfileCSIRInstr:
81     return "csllvm";
82   case llvm::driver::ProfileInstrKind::ProfileIRSampleColdCov:
83     return "sample-coldcov";
84   }
85   llvm_unreachable("Unhandled llvm::driver::ProfileInstrKind enum");
86 }
87 
88 ProfileList::ExclusionType
89 ProfileList::getDefault(llvm::driver::ProfileInstrKind Kind) const {
90   StringRef Section = getSectionName(Kind);
91   // Check for "default:<type>"
92   if (SCL->inSection(Section, "default", "allow"))
93     return Allow;
94   if (SCL->inSection(Section, "default", "skip"))
95     return Skip;
96   if (SCL->inSection(Section, "default", "forbid"))
97     return Forbid;
98   // If any cases use "fun" or "src", set the default to FORBID.
99   if (SCL->hasPrefix("fun") || SCL->hasPrefix("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, "allow"))
108     return Allow;
109   if (SCL->inSection(Section, Prefix, Query, "skip"))
110     return Skip;
111   if (SCL->inSection(Section, Prefix, Query, "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                                 llvm::driver::ProfileInstrKind Kind) const {
121   StringRef Section = getSectionName(Kind);
122   // Check for "function:<regex>=<case>"
123   if (auto V = inSection(Section, "function", FunctionName))
124     return V;
125   if (SCL->inSection(Section, "!fun", FunctionName))
126     return Forbid;
127   if (SCL->inSection(Section, "fun", FunctionName))
128     return Allow;
129   return std::nullopt;
130 }
131 
132 std::optional<ProfileList::ExclusionType>
133 ProfileList::isLocationExcluded(SourceLocation Loc,
134                                 llvm::driver::ProfileInstrKind Kind) const {
135   return isFileExcluded(SM.getFilename(SM.getFileLoc(Loc)), Kind);
136 }
137 
138 std::optional<ProfileList::ExclusionType>
139 ProfileList::isFileExcluded(StringRef FileName,
140                             llvm::driver::ProfileInstrKind Kind) const {
141   StringRef Section = getSectionName(Kind);
142   // Check for "source:<regex>=<case>"
143   if (auto V = inSection(Section, "source", FileName))
144     return V;
145   if (SCL->inSection(Section, "!src", FileName))
146     return Forbid;
147   if (SCL->inSection(Section, "src", FileName))
148     return Allow;
149   return std::nullopt;
150 }
151