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