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