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 36e8d8bef9SDimitry Andric bool isEmpty() const { return Sections.empty(); } 37e8d8bef9SDimitry Andric 38e8d8bef9SDimitry 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> 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> 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 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 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 89bdd1243dSDimitry 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> 105bdd1243dSDimitry 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> 119e8d8bef9SDimitry 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> 133e8d8bef9SDimitry 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> 139e8d8bef9SDimitry 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