diff --git a/clang/include/clang/CodeGen/BackendUtil.h b/clang/include/clang/CodeGen/BackendUtil.h --- a/clang/include/clang/CodeGen/BackendUtil.h +++ b/clang/include/clang/CodeGen/BackendUtil.h @@ -16,8 +16,12 @@ namespace llvm { class BitcodeModule; template class Expected; + template class IntrusiveRefCntPtr; class Module; class MemoryBufferRef; + namespace vfs { + class FileSystem; + } // namespace vfs } namespace clang { @@ -40,6 +44,7 @@ const CodeGenOptions &CGOpts, const TargetOptions &TOpts, const LangOptions &LOpts, StringRef TDesc, llvm::Module *M, BackendAction Action, + llvm::IntrusiveRefCntPtr VFS, std::unique_ptr OS); void EmbedBitcode(llvm::Module *M, const CodeGenOptions &CGOpts, diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -52,6 +52,7 @@ #include "llvm/Support/TimeProfiler.h" #include "llvm/Support/Timer.h" #include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" @@ -123,6 +124,7 @@ const clang::TargetOptions &TargetOpts; const LangOptions &LangOpts; Module *TheModule; + IntrusiveRefCntPtr VFS; Timer CodeGenerationTime; @@ -187,9 +189,10 @@ const HeaderSearchOptions &HeaderSearchOpts, const CodeGenOptions &CGOpts, const clang::TargetOptions &TOpts, - const LangOptions &LOpts, Module *M) + const LangOptions &LOpts, Module *M, + IntrusiveRefCntPtr VFS) : Diags(_Diags), HSOpts(HeaderSearchOpts), CodeGenOpts(CGOpts), - TargetOpts(TOpts), LangOpts(LOpts), TheModule(M), + TargetOpts(TOpts), LangOpts(LOpts), TheModule(M), VFS(std::move(VFS)), CodeGenerationTime("codegen", "Code Generation Time"), TargetTriple(TheModule->getTargetTriple()) {} @@ -767,32 +770,33 @@ if (CodeGenOpts.hasProfileIRInstr()) // -fprofile-generate. - PGOOpt = PGOOptions(CodeGenOpts.InstrProfileOutput.empty() - ? getDefaultProfileGenName() - : CodeGenOpts.InstrProfileOutput, - "", "", PGOOptions::IRInstr, PGOOptions::NoCSAction, - CodeGenOpts.DebugInfoForProfiling); + PGOOpt = PGOOptions( + CodeGenOpts.InstrProfileOutput.empty() ? getDefaultProfileGenName() + : CodeGenOpts.InstrProfileOutput, + "", "", nullptr, PGOOptions::IRInstr, PGOOptions::NoCSAction, + CodeGenOpts.DebugInfoForProfiling); else if (CodeGenOpts.hasProfileIRUse()) { // -fprofile-use. auto CSAction = CodeGenOpts.hasProfileCSIRUse() ? PGOOptions::CSIRUse : PGOOptions::NoCSAction; - PGOOpt = PGOOptions(CodeGenOpts.ProfileInstrumentUsePath, "", - CodeGenOpts.ProfileRemappingFile, PGOOptions::IRUse, - CSAction, CodeGenOpts.DebugInfoForProfiling); + PGOOpt = + PGOOptions(CodeGenOpts.ProfileInstrumentUsePath, "", + CodeGenOpts.ProfileRemappingFile, VFS, PGOOptions::IRUse, + CSAction, CodeGenOpts.DebugInfoForProfiling); } else if (!CodeGenOpts.SampleProfileFile.empty()) // -fprofile-sample-use PGOOpt = PGOOptions( CodeGenOpts.SampleProfileFile, "", CodeGenOpts.ProfileRemappingFile, - PGOOptions::SampleUse, PGOOptions::NoCSAction, + VFS, PGOOptions::SampleUse, PGOOptions::NoCSAction, CodeGenOpts.DebugInfoForProfiling, CodeGenOpts.PseudoProbeForProfiling); else if (CodeGenOpts.PseudoProbeForProfiling) // -fpseudo-probe-for-profiling - PGOOpt = - PGOOptions("", "", "", PGOOptions::NoAction, PGOOptions::NoCSAction, - CodeGenOpts.DebugInfoForProfiling, true); + PGOOpt = PGOOptions("", "", "", nullptr, PGOOptions::NoAction, + PGOOptions::NoCSAction, + CodeGenOpts.DebugInfoForProfiling, true); else if (CodeGenOpts.DebugInfoForProfiling) // -fdebug-info-for-profiling - PGOOpt = PGOOptions("", "", "", PGOOptions::NoAction, + PGOOpt = PGOOptions("", "", "", nullptr, PGOOptions::NoAction, PGOOptions::NoCSAction, true); // Check to see if we want to generate a CS profile. @@ -810,12 +814,13 @@ : CodeGenOpts.InstrProfileOutput; PGOOpt->CSAction = PGOOptions::CSIRInstr; } else - PGOOpt = PGOOptions("", - CodeGenOpts.InstrProfileOutput.empty() - ? getDefaultProfileGenName() - : CodeGenOpts.InstrProfileOutput, - "", PGOOptions::NoAction, PGOOptions::CSIRInstr, - CodeGenOpts.DebugInfoForProfiling); + PGOOpt = + PGOOptions("", + CodeGenOpts.InstrProfileOutput.empty() + ? getDefaultProfileGenName() + : CodeGenOpts.InstrProfileOutput, + "", nullptr, PGOOptions::NoAction, PGOOptions::CSIRInstr, + CodeGenOpts.DebugInfoForProfiling); } if (TM) TM->setPGOOption(PGOOpt); @@ -1219,9 +1224,9 @@ const HeaderSearchOptions &HeaderOpts, const CodeGenOptions &CGOpts, const clang::TargetOptions &TOpts, - const LangOptions &LOpts, - StringRef TDesc, Module *M, - BackendAction Action, + const LangOptions &LOpts, StringRef TDesc, + Module *M, BackendAction Action, + IntrusiveRefCntPtr VFS, std::unique_ptr OS) { llvm::TimeTraceScope TimeScope("Backend"); @@ -1264,7 +1269,7 @@ } } - EmitAssemblyHelper AsmHelper(Diags, HeaderOpts, CGOpts, TOpts, LOpts, M); + EmitAssemblyHelper AsmHelper(Diags, HeaderOpts, CGOpts, TOpts, LOpts, M, VFS); AsmHelper.EmitAssembly(Action, std::move(OS)); // Verify clang's TargetInfo DataLayout against the LLVM TargetMachine's diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -115,6 +115,7 @@ const LangOptions &LangOpts; std::unique_ptr AsmOutStream; ASTContext *Context; + IntrusiveRefCntPtr FS; Timer LLVMIRGeneration; unsigned LLVMIRGenerationRefCount; @@ -147,7 +148,7 @@ public: BackendConsumer(BackendAction Action, DiagnosticsEngine &Diags, - IntrusiveRefCntPtr FS, + IntrusiveRefCntPtr VFS, const HeaderSearchOptions &HeaderSearchOpts, const PreprocessorOptions &PPOpts, const CodeGenOptions &CodeGenOpts, @@ -158,10 +159,10 @@ CoverageSourceInfo *CoverageInfo = nullptr) : Diags(Diags), Action(Action), HeaderSearchOpts(HeaderSearchOpts), CodeGenOpts(CodeGenOpts), TargetOpts(TargetOpts), LangOpts(LangOpts), - AsmOutStream(std::move(OS)), Context(nullptr), + AsmOutStream(std::move(OS)), Context(nullptr), FS(VFS), LLVMIRGeneration("irgen", "LLVM IR Generation Time"), LLVMIRGenerationRefCount(0), - Gen(CreateLLVMCodeGen(Diags, InFile, std::move(FS), HeaderSearchOpts, + Gen(CreateLLVMCodeGen(Diags, InFile, std::move(VFS), HeaderSearchOpts, PPOpts, CodeGenOpts, C, CoverageInfo)), LinkModules(std::move(LinkModules)) { TimerIsEnabled = CodeGenOpts.TimePasses; @@ -173,7 +174,7 @@ // to use the clang diagnostic handler for IR input files. It avoids // initializing the OS field. BackendConsumer(BackendAction Action, DiagnosticsEngine &Diags, - IntrusiveRefCntPtr FS, + IntrusiveRefCntPtr VFS, const HeaderSearchOptions &HeaderSearchOpts, const PreprocessorOptions &PPOpts, const CodeGenOptions &CodeGenOpts, @@ -183,10 +184,10 @@ CoverageSourceInfo *CoverageInfo = nullptr) : Diags(Diags), Action(Action), HeaderSearchOpts(HeaderSearchOpts), CodeGenOpts(CodeGenOpts), TargetOpts(TargetOpts), LangOpts(LangOpts), - Context(nullptr), + Context(nullptr), FS(VFS), LLVMIRGeneration("irgen", "LLVM IR Generation Time"), LLVMIRGenerationRefCount(0), - Gen(CreateLLVMCodeGen(Diags, "", std::move(FS), HeaderSearchOpts, + Gen(CreateLLVMCodeGen(Diags, "", std::move(VFS), HeaderSearchOpts, PPOpts, CodeGenOpts, C, CoverageInfo)), LinkModules(std::move(LinkModules)), CurLinkModule(Module) { TimerIsEnabled = CodeGenOpts.TimePasses; @@ -381,7 +382,7 @@ EmitBackendOutput(Diags, HeaderSearchOpts, CodeGenOpts, TargetOpts, LangOpts, C.getTargetInfo().getDataLayoutString(), - getModule(), Action, std::move(AsmOutStream)); + getModule(), Action, FS, std::move(AsmOutStream)); Ctx.setDiagnosticHandler(std::move(OldDiagnosticHandler)); @@ -1238,10 +1239,10 @@ std::unique_ptr OptRecordFile = std::move(*OptRecordFileOrErr); - EmitBackendOutput(Diagnostics, CI.getHeaderSearchOpts(), CodeGenOpts, - TargetOpts, CI.getLangOpts(), - CI.getTarget().getDataLayoutString(), TheModule.get(), BA, - std::move(OS)); + EmitBackendOutput( + Diagnostics, CI.getHeaderSearchOpts(), CodeGenOpts, TargetOpts, + CI.getLangOpts(), CI.getTarget().getDataLayoutString(), TheModule.get(), + BA, CI.getFileManager().getVirtualFileSystemPtr(), std::move(OS)); if (OptRecordFile) OptRecordFile->keep(); } diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -107,11 +107,11 @@ const CodeGenOptions &CGO, llvm::Module &M, DiagnosticsEngine &diags, CoverageSourceInfo *CoverageInfo) - : Context(C), LangOpts(C.getLangOpts()), FS(std::move(FS)), - HeaderSearchOpts(HSO), PreprocessorOpts(PPO), CodeGenOpts(CGO), - TheModule(M), Diags(diags), Target(C.getTargetInfo()), - ABI(createCXXABI(*this)), VMContext(M.getContext()), Types(*this), - VTables(*this), SanitizerMD(new SanitizerMetadata(*this)) { + : Context(C), LangOpts(C.getLangOpts()), FS(FS), HeaderSearchOpts(HSO), + PreprocessorOpts(PPO), CodeGenOpts(CGO), TheModule(M), Diags(diags), + Target(C.getTargetInfo()), ABI(createCXXABI(*this)), + VMContext(M.getContext()), Types(*this), VTables(*this), + SanitizerMD(new SanitizerMetadata(*this)) { // Initialize the type cache. llvm::LLVMContext &LLVMContext = M.getContext(); @@ -185,7 +185,8 @@ if (CodeGenOpts.hasProfileClangUse()) { auto ReaderOrErr = llvm::IndexedInstrProfReader::create( - CodeGenOpts.ProfileInstrumentUsePath, CodeGenOpts.ProfileRemappingFile); + CodeGenOpts.ProfileInstrumentUsePath, *FS, + CodeGenOpts.ProfileRemappingFile); // We're checking for profile read errors in CompilerInvocation, so if // there was an error it should've already been caught. If it hasn't been // somehow, trip an assertion. diff --git a/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp b/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp --- a/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp +++ b/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp @@ -320,7 +320,7 @@ clang::EmitBackendOutput( Diags, HeaderSearchOpts, CodeGenOpts, TargetOpts, LangOpts, Ctx.getTargetInfo().getDataLayoutString(), M.get(), - BackendAction::Backend_EmitLL, + BackendAction::Backend_EmitLL, FS, std::make_unique(Buffer)); llvm::dbgs() << Buffer; }); @@ -329,7 +329,7 @@ clang::EmitBackendOutput(Diags, HeaderSearchOpts, CodeGenOpts, TargetOpts, LangOpts, Ctx.getTargetInfo().getDataLayoutString(), M.get(), - BackendAction::Backend_EmitObj, std::move(OS)); + BackendAction::Backend_EmitObj, FS, std::move(OS)); // Free the memory for the temporary buffer. llvm::SmallVector Empty; diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1304,8 +1304,9 @@ // Set the profile kind using fprofile-instrument-use-path. static void setPGOUseInstrumentor(CodeGenOptions &Opts, const Twine &ProfileName, + llvm::vfs::FileSystem &FS, DiagnosticsEngine &Diags) { - auto ReaderOrErr = llvm::IndexedInstrProfReader::create(ProfileName); + auto ReaderOrErr = llvm::IndexedInstrProfReader::create(ProfileName, FS); if (auto E = ReaderOrErr.takeError()) { unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, "Error in reading profile %0: %1"); @@ -1724,9 +1725,6 @@ : codegenoptions::DebugTemplateNamesKind::Mangled); } - if (!Opts.ProfileInstrumentUsePath.empty()) - setPGOUseInstrumentor(Opts, Opts.ProfileInstrumentUsePath, Diags); - if (const Arg *A = Args.getLastArg(OPT_ftime_report, OPT_ftime_report_EQ)) { Opts.TimePasses = true; @@ -1962,8 +1960,8 @@ Opts.OptimizationRemarkAnalysis.hasValidPattern(); bool UsingSampleProfile = !Opts.SampleProfileFile.empty(); - bool UsingProfile = UsingSampleProfile || - (Opts.getProfileUse() != CodeGenOptions::ProfileNone); + bool UsingProfile = + UsingSampleProfile || !Opts.ProfileInstrumentUsePath.empty(); if (Opts.DiagnosticsWithHotness && !UsingProfile && // An IR file will contain PGO as metadata @@ -4563,6 +4561,17 @@ append_range(Res.getCodeGenOpts().CommandLineArgs, CommandLineArgs); } + // Set PGOOptions. Need to create a temporary VFS to read the profile + // to determine the PGO type. + if (!Res.getCodeGenOpts().ProfileInstrumentUsePath.empty()) { + auto FS = + createVFSFromOverlayFiles(Res.getHeaderSearchOpts().VFSOverlayFiles, + Diags, llvm::vfs::getRealFileSystem()); + setPGOUseInstrumentor(Res.getCodeGenOpts(), + Res.getCodeGenOpts().ProfileInstrumentUsePath, *FS, + Diags); + } + FixupInvocation(Res, Diags, Args, DashX); return Diags.getNumErrors() == NumErrorsBefore; diff --git a/llvm/include/llvm/CodeGen/MIRSampleProfile.h b/llvm/include/llvm/CodeGen/MIRSampleProfile.h --- a/llvm/include/llvm/CodeGen/MIRSampleProfile.h +++ b/llvm/include/llvm/CodeGen/MIRSampleProfile.h @@ -14,6 +14,7 @@ #ifndef LLVM_CODEGEN_MIRSAMPLEPROFILE_H #define LLVM_CODEGEN_MIRSAMPLEPROFILE_H +#include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/StringRef.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/Support/Discriminator.h" @@ -26,6 +27,10 @@ class MachineFunction; class Module; +namespace vfs { +class FileSystem; +} // namespace vfs + using namespace sampleprof; class MIRProfileLoader; @@ -41,7 +46,8 @@ /// FS bits will only use the '1' bits in the Mask. MIRProfileLoaderPass(std::string FileName = "", std::string RemappingFileName = "", - FSDiscriminatorPass P = FSDiscriminatorPass::Pass1); + FSDiscriminatorPass P = FSDiscriminatorPass::Pass1, + IntrusiveRefCntPtr FS = nullptr); /// getMachineFunction - Return the last machine function computed. const MachineFunction *getMachineFunction() const { return MF; } diff --git a/llvm/include/llvm/CodeGen/Passes.h b/llvm/include/llvm/CodeGen/Passes.h --- a/llvm/include/llvm/CodeGen/Passes.h +++ b/llvm/include/llvm/CodeGen/Passes.h @@ -31,6 +31,11 @@ class TargetMachine; class raw_ostream; +template class IntrusiveRefCntPtr; +namespace vfs { +class FileSystem; +} // namespace vfs + } // End llvm namespace // List of target independent CodeGen pass IDs. @@ -551,9 +556,10 @@ createMIRAddFSDiscriminatorsPass(sampleprof::FSDiscriminatorPass P); /// Read Flow Sensitive Profile. - FunctionPass *createMIRProfileLoaderPass(std::string File, - std::string RemappingFile, - sampleprof::FSDiscriminatorPass P); + FunctionPass * + createMIRProfileLoaderPass(std::string File, std::string RemappingFile, + sampleprof::FSDiscriminatorPass P, + IntrusiveRefCntPtr FS); /// Creates MIR Debugify pass. \see MachineDebugify.cpp ModulePass *createDebugifyMachineModulePass(); diff --git a/llvm/include/llvm/Passes/PassBuilder.h b/llvm/include/llvm/Passes/PassBuilder.h --- a/llvm/include/llvm/Passes/PassBuilder.h +++ b/llvm/include/llvm/Passes/PassBuilder.h @@ -32,6 +32,10 @@ class AAManager; class TargetMachine; class ModuleSummaryIndex; +template class IntrusiveRefCntPtr; +namespace vfs { +class FileSystem; +} // namespace vfs /// Tunable parameters for passes in the default pipelines. class PipelineTuningOptions { @@ -567,7 +571,8 @@ /// Add PGOInstrumenation passes for O0 only. void addPGOInstrPassesForO0(ModulePassManager &MPM, bool RunProfileGen, bool IsCS, std::string ProfileFile, - std::string ProfileRemappingFile); + std::string ProfileRemappingFile, + IntrusiveRefCntPtr FS); /// Returns PIC. External libraries can use this to register pass /// instrumentation callbacks. @@ -607,7 +612,8 @@ void addPGOInstrPasses(ModulePassManager &MPM, OptimizationLevel Level, bool RunProfileGen, bool IsCS, std::string ProfileFile, std::string ProfileRemappingFile, - ThinOrFullLTOPhase LTOPhase); + ThinOrFullLTOPhase LTOPhase, + IntrusiveRefCntPtr FS); void invokePeepholeEPCallbacks(FunctionPassManager &, OptimizationLevel); // Extension Point callbacks diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h --- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h +++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h @@ -47,6 +47,10 @@ class BuildIDFetcher; } // namespace object +namespace vfs { +class FileSystem; +} // namespace vfs + namespace coverage { class CoverageMappingReader; @@ -616,7 +620,8 @@ /// Ignores non-instrumented object files unless all are not instrumented. static Expected> load(ArrayRef ObjectFilenames, StringRef ProfileFilename, - ArrayRef Arches = std::nullopt, StringRef CompilationDir = "", + vfs::FileSystem &FS, ArrayRef Arches = std::nullopt, + StringRef CompilationDir = "", const object::BuildIDFetcher *BIDFetcher = nullptr); /// The number of functions that couldn't have their profiles mapped. diff --git a/llvm/include/llvm/ProfileData/InstrProfReader.h b/llvm/include/llvm/ProfileData/InstrProfReader.h --- a/llvm/include/llvm/ProfileData/InstrProfReader.h +++ b/llvm/include/llvm/ProfileData/InstrProfReader.h @@ -41,6 +41,10 @@ class InstrProfReader; +namespace vfs { +class FileSystem; +} // namespace vfs + /// A file format agnostic iterator over profiling data. template @@ -190,7 +194,8 @@ /// Factory method to create an appropriately typed reader for the given /// instrprof file. static Expected> - create(const Twine &Path, const InstrProfCorrelator *Correlator = nullptr); + create(const Twine &Path, vfs::FileSystem &FS, + const InstrProfCorrelator *Correlator = nullptr); static Expected> create(std::unique_ptr Buffer, @@ -693,7 +698,8 @@ /// Factory method to create an indexed reader. static Expected> - create(const Twine &Path, const Twine &RemappingPath = ""); + create(const Twine &Path, vfs::FileSystem &FS, + const Twine &RemappingPath = ""); static Expected> create(std::unique_ptr Buffer, diff --git a/llvm/include/llvm/ProfileData/SampleProfReader.h b/llvm/include/llvm/ProfileData/SampleProfReader.h --- a/llvm/include/llvm/ProfileData/SampleProfReader.h +++ b/llvm/include/llvm/ProfileData/SampleProfReader.h @@ -251,6 +251,10 @@ class raw_ostream; class Twine; +namespace vfs { +class FileSystem; +} // namespace vfs + namespace sampleprof { class SampleProfileReader; @@ -270,8 +274,8 @@ /// Create a remapper from the given remapping file. The remapper will /// be used for profile read in by Reader. static ErrorOr> - create(const std::string Filename, SampleProfileReader &Reader, - LLVMContext &C); + create(const std::string Filename, vfs::FileSystem &FS, + SampleProfileReader &Reader, LLVMContext &C); /// Create a remapper from the given Buffer. The remapper will /// be used for profile read in by Reader. @@ -450,7 +454,7 @@ /// Create a remapper underlying if RemapFilename is not empty. /// Parameter P specifies the FSDiscriminatorPass. static ErrorOr> - create(const std::string Filename, LLVMContext &C, + create(const std::string Filename, LLVMContext &C, vfs::FileSystem &FS, FSDiscriminatorPass P = FSDiscriminatorPass::Base, const std::string RemapFilename = ""); @@ -458,7 +462,7 @@ /// Create a remapper underlying if RemapFilename is not empty. /// Parameter P specifies the FSDiscriminatorPass. static ErrorOr> - create(std::unique_ptr &B, LLVMContext &C, + create(std::unique_ptr &B, LLVMContext &C, vfs::FileSystem &FS, FSDiscriminatorPass P = FSDiscriminatorPass::Base, const std::string RemapFilename = ""); diff --git a/llvm/include/llvm/Support/PGOOptions.h b/llvm/include/llvm/Support/PGOOptions.h --- a/llvm/include/llvm/Support/PGOOptions.h +++ b/llvm/include/llvm/Support/PGOOptions.h @@ -14,44 +14,29 @@ #ifndef LLVM_SUPPORT_PGOOPTIONS_H #define LLVM_SUPPORT_PGOOPTIONS_H +#include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/Support/Error.h" namespace llvm { +namespace vfs { +class FileSystem; +} // namespace vfs + /// A struct capturing PGO tunables. struct PGOOptions { enum PGOAction { NoAction, IRInstr, IRUse, SampleUse }; enum CSPGOAction { NoCSAction, CSIRInstr, CSIRUse }; - PGOOptions(std::string ProfileFile = "", std::string CSProfileGenFile = "", - std::string ProfileRemappingFile = "", PGOAction Action = NoAction, - CSPGOAction CSAction = NoCSAction, + PGOOptions(std::string ProfileFile, std::string CSProfileGenFile, + std::string ProfileRemappingFile, + IntrusiveRefCntPtr FS, + PGOAction Action = NoAction, CSPGOAction CSAction = NoCSAction, bool DebugInfoForProfiling = false, - bool PseudoProbeForProfiling = false) - : ProfileFile(ProfileFile), CSProfileGenFile(CSProfileGenFile), - ProfileRemappingFile(ProfileRemappingFile), Action(Action), - CSAction(CSAction), DebugInfoForProfiling(DebugInfoForProfiling || - (Action == SampleUse && - !PseudoProbeForProfiling)), - PseudoProbeForProfiling(PseudoProbeForProfiling) { - // Note, we do allow ProfileFile.empty() for Action=IRUse LTO can - // callback with IRUse action without ProfileFile. - - // If there is a CSAction, PGOAction cannot be IRInstr or SampleUse. - assert(this->CSAction == NoCSAction || - (this->Action != IRInstr && this->Action != SampleUse)); - - // For CSIRInstr, CSProfileGenFile also needs to be nonempty. - assert(this->CSAction != CSIRInstr || !this->CSProfileGenFile.empty()); - - // If CSAction is CSIRUse, PGOAction needs to be IRUse as they share - // a profile. - assert(this->CSAction != CSIRUse || this->Action == IRUse); + bool PseudoProbeForProfiling = false); + PGOOptions(const PGOOptions &); + ~PGOOptions(); + PGOOptions &operator=(const PGOOptions &); - // If neither Action nor CSAction, DebugInfoForProfiling or - // PseudoProbeForProfiling needs to be true. - assert(this->Action != NoAction || this->CSAction != NoCSAction || - this->DebugInfoForProfiling || this->PseudoProbeForProfiling); - } std::string ProfileFile; std::string CSProfileGenFile; std::string ProfileRemappingFile; @@ -59,6 +44,7 @@ CSPGOAction CSAction; bool DebugInfoForProfiling; bool PseudoProbeForProfiling; + IntrusiveRefCntPtr FS; }; } // namespace llvm diff --git a/llvm/include/llvm/Transforms/IPO/SampleProfile.h b/llvm/include/llvm/Transforms/IPO/SampleProfile.h --- a/llvm/include/llvm/Transforms/IPO/SampleProfile.h +++ b/llvm/include/llvm/Transforms/IPO/SampleProfile.h @@ -14,6 +14,7 @@ #ifndef LLVM_TRANSFORMS_IPO_SAMPLEPROFILE_H #define LLVM_TRANSFORMS_IPO_SAMPLEPROFILE_H +#include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/IR/PassManager.h" #include "llvm/Pass.h" #include @@ -22,14 +23,17 @@ class Module; +namespace vfs { +class FileSystem; +} // namespace vfs + /// The sample profiler data loader pass. class SampleProfileLoaderPass : public PassInfoMixin { public: SampleProfileLoaderPass( std::string File = "", std::string RemappingFile = "", - ThinOrFullLTOPhase LTOPhase = ThinOrFullLTOPhase::None) - : ProfileFileName(File), ProfileRemappingFileName(RemappingFile), - LTOPhase(LTOPhase) {} + ThinOrFullLTOPhase LTOPhase = ThinOrFullLTOPhase::None, + IntrusiveRefCntPtr FS = nullptr); PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); @@ -37,6 +41,7 @@ std::string ProfileFileName; std::string ProfileRemappingFileName; const ThinOrFullLTOPhase LTOPhase; + IntrusiveRefCntPtr FS; }; } // end namespace llvm diff --git a/llvm/include/llvm/Transforms/Instrumentation/PGOInstrumentation.h b/llvm/include/llvm/Transforms/Instrumentation/PGOInstrumentation.h --- a/llvm/include/llvm/Transforms/Instrumentation/PGOInstrumentation.h +++ b/llvm/include/llvm/Transforms/Instrumentation/PGOInstrumentation.h @@ -16,6 +16,7 @@ #define LLVM_TRANSFORMS_INSTRUMENTATION_PGOINSTRUMENTATION_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/IR/PassManager.h" #include #include @@ -26,6 +27,10 @@ class Instruction; class Module; +namespace vfs { +class FileSystem; +} // namespace vfs + /// The instrumentation (profile-instr-gen) pass for IR based PGO. // We use this pass to create COMDAT profile variables for context // sensitive PGO (CSPGO). The reason to have a pass for this is CSPGO @@ -58,7 +63,8 @@ class PGOInstrumentationUse : public PassInfoMixin { public: PGOInstrumentationUse(std::string Filename = "", - std::string RemappingFilename = "", bool IsCS = false); + std::string RemappingFilename = "", bool IsCS = false, + IntrusiveRefCntPtr FS = nullptr); PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); @@ -67,6 +73,7 @@ std::string ProfileRemappingFileName; // If this is a context sensitive instrumentation. bool IsCS; + IntrusiveRefCntPtr FS; }; /// The indirect function call promotion pass. diff --git a/llvm/include/llvm/Transforms/Utils/SampleProfileLoaderBaseImpl.h b/llvm/include/llvm/Transforms/Utils/SampleProfileLoaderBaseImpl.h --- a/llvm/include/llvm/Transforms/Utils/SampleProfileLoaderBaseImpl.h +++ b/llvm/include/llvm/Transforms/Utils/SampleProfileLoaderBaseImpl.h @@ -18,6 +18,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" @@ -46,6 +47,10 @@ using namespace sampleprofutil; using ProfileCount = Function::ProfileCount; +namespace vfs { +class FileSystem; +} // namespace vfs + #define DEBUG_TYPE "sample-profile-impl" namespace afdo_detail { @@ -79,8 +84,9 @@ template class SampleProfileLoaderBaseImpl { public: - SampleProfileLoaderBaseImpl(std::string Name, std::string RemapName) - : Filename(Name), RemappingFilename(RemapName) {} + SampleProfileLoaderBaseImpl(std::string Name, std::string RemapName, + IntrusiveRefCntPtr FS) + : Filename(Name), RemappingFilename(RemapName), FS(std::move(FS)) {} void dump() { Reader->dump(); } using InstructionT = typename afdo_detail::IRTraits::InstructionT; @@ -215,6 +221,9 @@ /// Name of the profile remapping file to load. std::string RemappingFilename; + /// VirtualFileSystem to load profile files from. + IntrusiveRefCntPtr FS; + /// Profile Summary Info computed from sample profile. ProfileSummaryInfo *PSI = nullptr; diff --git a/llvm/lib/CodeGen/MIRSampleProfile.cpp b/llvm/lib/CodeGen/MIRSampleProfile.cpp --- a/llvm/lib/CodeGen/MIRSampleProfile.cpp +++ b/llvm/lib/CodeGen/MIRSampleProfile.cpp @@ -26,6 +26,7 @@ #include "llvm/InitializePasses.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Utils/SampleProfileLoaderBaseImpl.h" #include "llvm/Transforms/Utils/SampleProfileLoaderBaseUtil.h" @@ -72,10 +73,11 @@ char &llvm::MIRProfileLoaderPassID = MIRProfileLoaderPass::ID; -FunctionPass *llvm::createMIRProfileLoaderPass(std::string File, - std::string RemappingFile, - FSDiscriminatorPass P) { - return new MIRProfileLoaderPass(File, RemappingFile, P); +FunctionPass * +llvm::createMIRProfileLoaderPass(std::string File, std::string RemappingFile, + FSDiscriminatorPass P, + IntrusiveRefCntPtr FS) { + return new MIRProfileLoaderPass(File, RemappingFile, P, std::move(FS)); } namespace llvm { @@ -136,9 +138,10 @@ assert(LowBit < HighBit && "HighBit needs to be greater than Lowbit"); } - MIRProfileLoader(StringRef Name, StringRef RemapName) - : SampleProfileLoaderBaseImpl(std::string(Name), std::string(RemapName)) { - } + MIRProfileLoader(StringRef Name, StringRef RemapName, + IntrusiveRefCntPtr FS) + : SampleProfileLoaderBaseImpl(std::string(Name), std::string(RemapName), + std::move(FS)) {} void setBranchProbs(MachineFunction &F); bool runOnFunction(MachineFunction &F); @@ -254,8 +257,8 @@ bool MIRProfileLoader::doInitialization(Module &M) { auto &Ctx = M.getContext(); - auto ReaderOrErr = sampleprof::SampleProfileReader::create(Filename, Ctx, P, - RemappingFilename); + auto ReaderOrErr = sampleprof::SampleProfileReader::create( + Filename, Ctx, *FS, P, RemappingFilename); if (std::error_code EC = ReaderOrErr.getError()) { std::string Msg = "Could not open profile: " + EC.message(); Ctx.diagnose(DiagnosticInfoSampleProfile(Filename, Msg)); @@ -291,14 +294,16 @@ } // namespace llvm -MIRProfileLoaderPass::MIRProfileLoaderPass(std::string FileName, - std::string RemappingFileName, - FSDiscriminatorPass P) - : MachineFunctionPass(ID), ProfileFileName(FileName), P(P), - MIRSampleLoader( - std::make_unique(FileName, RemappingFileName)) { +MIRProfileLoaderPass::MIRProfileLoaderPass( + std::string FileName, std::string RemappingFileName, FSDiscriminatorPass P, + IntrusiveRefCntPtr FS) + : MachineFunctionPass(ID), ProfileFileName(FileName), P(P) { LowBit = getFSPassBitBegin(P); HighBit = getFSPassBitEnd(P); + + auto VFS = FS ? std::move(FS) : vfs::getRealFileSystem(); + MIRSampleLoader = std::make_unique( + FileName, RemappingFileName, std::move(VFS)); assert(LowBit < HighBit && "HighBit needs to be greater than Lowbit"); } diff --git a/llvm/lib/CodeGen/TargetPassConfig.cpp b/llvm/lib/CodeGen/TargetPassConfig.cpp --- a/llvm/lib/CodeGen/TargetPassConfig.cpp +++ b/llvm/lib/CodeGen/TargetPassConfig.cpp @@ -42,6 +42,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/Threading.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Target/CGPassBuilderOption.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/Scalar.h" @@ -1149,9 +1150,9 @@ sampleprof::FSDiscriminatorPass::Pass1)); const std::string ProfileFile = getFSProfileFile(TM); if (!ProfileFile.empty() && !DisableRAFSProfileLoader) - addPass( - createMIRProfileLoaderPass(ProfileFile, getFSRemappingFile(TM), - sampleprof::FSDiscriminatorPass::Pass1)); + addPass(createMIRProfileLoaderPass(ProfileFile, getFSRemappingFile(TM), + sampleprof::FSDiscriminatorPass::Pass1, + nullptr)); } // Run register allocation and passes that are tightly coupled with it, @@ -1525,9 +1526,9 @@ sampleprof::FSDiscriminatorPass::Pass2)); const std::string ProfileFile = getFSProfileFile(TM); if (!ProfileFile.empty() && !DisableLayoutFSProfileLoader) - addPass( - createMIRProfileLoaderPass(ProfileFile, getFSRemappingFile(TM), - sampleprof::FSDiscriminatorPass::Pass2)); + addPass(createMIRProfileLoaderPass(ProfileFile, getFSRemappingFile(TM), + sampleprof::FSDiscriminatorPass::Pass2, + nullptr)); } if (addPass(&MachineBlockPlacementID)) { // Run a separate pass to collect block placement statistics. diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp --- a/llvm/lib/LTO/LTOBackend.cpp +++ b/llvm/lib/LTO/LTOBackend.cpp @@ -38,6 +38,7 @@ #include "llvm/Support/Program.h" #include "llvm/Support/ThreadPool.h" #include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/IPO/WholeProgramDevirt.h" @@ -232,21 +233,22 @@ unsigned OptLevel, bool IsThinLTO, ModuleSummaryIndex *ExportSummary, const ModuleSummaryIndex *ImportSummary) { + auto FS = vfs::getRealFileSystem(); std::optional PGOOpt; if (!Conf.SampleProfile.empty()) - PGOOpt = PGOOptions(Conf.SampleProfile, "", Conf.ProfileRemapping, + PGOOpt = PGOOptions(Conf.SampleProfile, "", Conf.ProfileRemapping, FS, PGOOptions::SampleUse, PGOOptions::NoCSAction, true); else if (Conf.RunCSIRInstr) { - PGOOpt = PGOOptions("", Conf.CSIRProfile, Conf.ProfileRemapping, + PGOOpt = PGOOptions("", Conf.CSIRProfile, Conf.ProfileRemapping, FS, PGOOptions::IRUse, PGOOptions::CSIRInstr, Conf.AddFSDiscriminator); } else if (!Conf.CSIRProfile.empty()) { - PGOOpt = PGOOptions(Conf.CSIRProfile, "", Conf.ProfileRemapping, + PGOOpt = PGOOptions(Conf.CSIRProfile, "", Conf.ProfileRemapping, FS, PGOOptions::IRUse, PGOOptions::CSIRUse, Conf.AddFSDiscriminator); NoPGOWarnMismatch = !Conf.PGOWarnMismatch; } else if (Conf.AddFSDiscriminator) { - PGOOpt = PGOOptions("", "", "", PGOOptions::NoAction, + PGOOpt = PGOOptions("", "", "", nullptr, PGOOptions::NoAction, PGOOptions::NoCSAction, true); } TM->setPGOOption(PGOOpt); diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp --- a/llvm/lib/Passes/PassBuilderPipelines.cpp +++ b/llvm/lib/Passes/PassBuilderPipelines.cpp @@ -29,6 +29,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/PGOOptions.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/AggressiveInstCombine/AggressiveInstCombine.h" #include "llvm/Transforms/Coroutines/CoroCleanup.h" @@ -704,7 +705,8 @@ OptimizationLevel Level, bool RunProfileGen, bool IsCS, std::string ProfileFile, std::string ProfileRemappingFile, - ThinOrFullLTOPhase LTOPhase) { + ThinOrFullLTOPhase LTOPhase, + IntrusiveRefCntPtr FS) { assert(Level != OptimizationLevel::O0 && "Not expecting O0 here!"); if (!IsCS && !DisablePreInliner) { InlineParams IP; @@ -742,7 +744,8 @@ if (!RunProfileGen) { assert(!ProfileFile.empty() && "Profile use expecting a profile file!"); - MPM.addPass(PGOInstrumentationUse(ProfileFile, ProfileRemappingFile, IsCS)); + MPM.addPass( + PGOInstrumentationUse(ProfileFile, ProfileRemappingFile, IsCS, FS)); // Cache ProfileSummaryAnalysis once to avoid the potential need to insert // RequireAnalysisPass for PSI before subsequent non-module passes. MPM.addPass(RequireAnalysisPass()); @@ -772,13 +775,14 @@ MPM.addPass(InstrProfiling(Options, IsCS)); } -void PassBuilder::addPGOInstrPassesForO0(ModulePassManager &MPM, - bool RunProfileGen, bool IsCS, - std::string ProfileFile, - std::string ProfileRemappingFile) { +void PassBuilder::addPGOInstrPassesForO0( + ModulePassManager &MPM, bool RunProfileGen, bool IsCS, + std::string ProfileFile, std::string ProfileRemappingFile, + IntrusiveRefCntPtr FS) { if (!RunProfileGen) { assert(!ProfileFile.empty() && "Profile use expecting a profile file!"); - MPM.addPass(PGOInstrumentationUse(ProfileFile, ProfileRemappingFile, IsCS)); + MPM.addPass( + PGOInstrumentationUse(ProfileFile, ProfileRemappingFile, IsCS, FS)); // Cache ProfileSummaryAnalysis once to avoid the potential need to insert // RequireAnalysisPass for PSI before subsequent non-module passes. MPM.addPass(RequireAnalysisPass()); @@ -1064,7 +1068,7 @@ addPGOInstrPasses(MPM, Level, /* RunProfileGen */ PGOOpt->Action == PGOOptions::IRInstr, /* IsCS */ false, PGOOpt->ProfileFile, - PGOOpt->ProfileRemappingFile, Phase); + PGOOpt->ProfileRemappingFile, Phase, PGOOpt->FS); MPM.addPass(PGOIndirectCallPromotion(false, false)); } if (PGOOpt && Phase != ThinOrFullLTOPhase::ThinLTOPostLink && @@ -1278,11 +1282,11 @@ if (PGOOpt->CSAction == PGOOptions::CSIRInstr) addPGOInstrPasses(MPM, Level, /* RunProfileGen */ true, /* IsCS */ true, PGOOpt->CSProfileGenFile, - PGOOpt->ProfileRemappingFile, LTOPhase); + PGOOpt->ProfileRemappingFile, LTOPhase, PGOOpt->FS); else if (PGOOpt->CSAction == PGOOptions::CSIRUse) addPGOInstrPasses(MPM, Level, /* RunProfileGen */ false, /* IsCS */ true, PGOOpt->ProfileFile, - PGOOpt->ProfileRemappingFile, LTOPhase); + PGOOpt->ProfileRemappingFile, LTOPhase, PGOOpt->FS); } // Re-compute GlobalsAA here prior to function passes. This is particularly @@ -1754,12 +1758,12 @@ addPGOInstrPasses(MPM, Level, /* RunProfileGen */ true, /* IsCS */ true, PGOOpt->CSProfileGenFile, PGOOpt->ProfileRemappingFile, - ThinOrFullLTOPhase::FullLTOPostLink); + ThinOrFullLTOPhase::FullLTOPostLink, PGOOpt->FS); else if (PGOOpt->CSAction == PGOOptions::CSIRUse) addPGOInstrPasses(MPM, Level, /* RunProfileGen */ false, /* IsCS */ true, PGOOpt->ProfileFile, PGOOpt->ProfileRemappingFile, - ThinOrFullLTOPhase::FullLTOPostLink); + ThinOrFullLTOPhase::FullLTOPostLink, PGOOpt->FS); } // Break up allocas @@ -1890,7 +1894,8 @@ addPGOInstrPassesForO0( MPM, /* RunProfileGen */ (PGOOpt->Action == PGOOptions::IRInstr), - /* IsCS */ false, PGOOpt->ProfileFile, PGOOpt->ProfileRemappingFile); + /* IsCS */ false, PGOOpt->ProfileFile, PGOOpt->ProfileRemappingFile, + PGOOpt->FS); for (auto &C : PipelineStartEPCallbacks) C(MPM, Level); diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp --- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp @@ -25,6 +25,7 @@ #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -383,10 +384,10 @@ Expected> CoverageMapping::load(ArrayRef ObjectFilenames, - StringRef ProfileFilename, ArrayRef Arches, - StringRef CompilationDir, + StringRef ProfileFilename, vfs::FileSystem &FS, + ArrayRef Arches, StringRef CompilationDir, const object::BuildIDFetcher *BIDFetcher) { - auto ProfileReaderOrErr = IndexedInstrProfReader::create(ProfileFilename); + auto ProfileReaderOrErr = IndexedInstrProfReader::create(ProfileFilename, FS); if (Error E = ProfileReaderOrErr.takeError()) return createFileError(ProfileFilename, std::move(E)); auto ProfileReader = std::move(ProfileReaderOrErr.get()); diff --git a/llvm/lib/ProfileData/InstrProf.cpp b/llvm/lib/ProfileData/InstrProf.cpp --- a/llvm/lib/ProfileData/InstrProf.cpp +++ b/llvm/lib/ProfileData/InstrProf.cpp @@ -42,6 +42,7 @@ #include "llvm/Support/MathExtras.h" #include "llvm/Support/Path.h" #include "llvm/Support/SwapByteOrder.h" +#include "llvm/Support/VirtualFileSystem.h" #include #include #include @@ -1224,7 +1225,10 @@ bool IsCS) { auto getProfileSum = [IsCS](const std::string &Filename, CountSumOrPercent &Sum) -> Error { - auto ReaderOrErr = InstrProfReader::create(Filename); + // This function is only used from llvm-profdata that doesn't use any kind + // of VFS. Just create a default RealFileSystem to read profiles. + auto FS = vfs::getRealFileSystem(); + auto ReaderOrErr = InstrProfReader::create(Filename, *FS); if (Error E = ReaderOrErr.takeError()) { return E; } diff --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp --- a/llvm/lib/ProfileData/InstrProfReader.cpp +++ b/llvm/lib/ProfileData/InstrProfReader.cpp @@ -26,6 +26,7 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SwapByteOrder.h" #include "llvm/Support/SymbolRemappingReader.h" +#include "llvm/Support/VirtualFileSystem.h" #include #include #include @@ -63,9 +64,9 @@ } static Expected> -setupMemoryBuffer(const Twine &Path) { - ErrorOr> BufferOrErr = - MemoryBuffer::getFileOrSTDIN(Path, /*IsText=*/true); +setupMemoryBuffer(const Twine &Filename, vfs::FileSystem &FS) { + auto BufferOrErr = Filename.str() == "-" ? MemoryBuffer::getSTDIN() + : FS.getBufferForFile(Filename); if (std::error_code EC = BufferOrErr.getError()) return errorCodeToError(EC); return std::move(BufferOrErr.get()); @@ -161,10 +162,10 @@ } Expected> -InstrProfReader::create(const Twine &Path, +InstrProfReader::create(const Twine &Path, vfs::FileSystem &FS, const InstrProfCorrelator *Correlator) { // Set up the buffer to read. - auto BufferOrError = setupMemoryBuffer(Path); + auto BufferOrError = setupMemoryBuffer(Path, FS); if (Error E = BufferOrError.takeError()) return std::move(E); return InstrProfReader::create(std::move(BufferOrError.get()), Correlator); @@ -201,9 +202,10 @@ } Expected> -IndexedInstrProfReader::create(const Twine &Path, const Twine &RemappingPath) { +IndexedInstrProfReader::create(const Twine &Path, vfs::FileSystem &FS, + const Twine &RemappingPath) { // Set up the buffer to read. - auto BufferOrError = setupMemoryBuffer(Path); + auto BufferOrError = setupMemoryBuffer(Path, FS); if (Error E = BufferOrError.takeError()) return std::move(E); @@ -211,7 +213,7 @@ std::unique_ptr RemappingBuffer; std::string RemappingPathStr = RemappingPath.str(); if (!RemappingPathStr.empty()) { - auto RemappingBufferOrError = setupMemoryBuffer(RemappingPathStr); + auto RemappingBufferOrError = setupMemoryBuffer(RemappingPathStr, FS); if (Error E = RemappingBufferOrError.takeError()) return std::move(E); RemappingBuffer = std::move(RemappingBufferOrError.get()); diff --git a/llvm/lib/ProfileData/SampleProfReader.cpp b/llvm/lib/ProfileData/SampleProfReader.cpp --- a/llvm/lib/ProfileData/SampleProfReader.cpp +++ b/llvm/lib/ProfileData/SampleProfReader.cpp @@ -35,6 +35,7 @@ #include "llvm/Support/LineIterator.h" #include "llvm/Support/MD5.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -1831,8 +1832,9 @@ /// /// \returns an error code indicating the status of the buffer. static ErrorOr> -setupMemoryBuffer(const Twine &Filename) { - auto BufferOrErr = MemoryBuffer::getFileOrSTDIN(Filename, /*IsText=*/true); +setupMemoryBuffer(const Twine &Filename, vfs::FileSystem &FS) { + auto BufferOrErr = Filename.str() == "-" ? MemoryBuffer::getSTDIN() + : FS.getBufferForFile(Filename); if (std::error_code EC = BufferOrErr.getError()) return EC; auto Buffer = std::move(BufferOrErr.get()); @@ -1853,12 +1855,12 @@ /// \returns an error code indicating the status of the created reader. ErrorOr> SampleProfileReader::create(const std::string Filename, LLVMContext &C, - FSDiscriminatorPass P, + vfs::FileSystem &FS, FSDiscriminatorPass P, const std::string RemapFilename) { - auto BufferOrError = setupMemoryBuffer(Filename); + auto BufferOrError = setupMemoryBuffer(Filename, FS); if (std::error_code EC = BufferOrError.getError()) return EC; - return create(BufferOrError.get(), C, P, RemapFilename); + return create(BufferOrError.get(), C, FS, P, RemapFilename); } /// Create a sample profile remapper from the given input, to remap the @@ -1873,9 +1875,10 @@ /// \returns an error code indicating the status of the created reader. ErrorOr> SampleProfileReaderItaniumRemapper::create(const std::string Filename, + vfs::FileSystem &FS, SampleProfileReader &Reader, LLVMContext &C) { - auto BufferOrError = setupMemoryBuffer(Filename); + auto BufferOrError = setupMemoryBuffer(Filename, FS); if (std::error_code EC = BufferOrError.getError()) return EC; return create(BufferOrError.get(), Reader, C); @@ -1923,7 +1926,7 @@ /// \returns an error code indicating the status of the created reader. ErrorOr> SampleProfileReader::create(std::unique_ptr &B, LLVMContext &C, - FSDiscriminatorPass P, + vfs::FileSystem &FS, FSDiscriminatorPass P, const std::string RemapFilename) { std::unique_ptr Reader; if (SampleProfileReaderRawBinary::hasFormat(*B)) @@ -1940,8 +1943,8 @@ return sampleprof_error::unrecognized_format; if (!RemapFilename.empty()) { - auto ReaderOrErr = - SampleProfileReaderItaniumRemapper::create(RemapFilename, *Reader, C); + auto ReaderOrErr = SampleProfileReaderItaniumRemapper::create( + RemapFilename, FS, *Reader, C); if (std::error_code EC = ReaderOrErr.getError()) { std::string Msg = "Could not create remapper: " + EC.message(); C.diagnose(DiagnosticInfoSampleProfile(RemapFilename, Msg)); diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt --- a/llvm/lib/Support/CMakeLists.txt +++ b/llvm/lib/Support/CMakeLists.txt @@ -195,6 +195,7 @@ NativeFormatting.cpp OptimizedStructLayout.cpp Optional.cpp + PGOOptions.cpp Parallel.cpp PluginLoader.cpp PrettyStackTrace.cpp diff --git a/llvm/lib/Support/PGOOptions.cpp b/llvm/lib/Support/PGOOptions.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Support/PGOOptions.cpp @@ -0,0 +1,52 @@ +//===------ PGOOptions.cpp -- PGO option tunables --------------*- C++ -*--===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/PGOOptions.h" +#include "llvm/Support/VirtualFileSystem.h" + +using namespace llvm; + +PGOOptions::PGOOptions(std::string ProfileFile, std::string CSProfileGenFile, + std::string ProfileRemappingFile, + IntrusiveRefCntPtr FS, PGOAction Action, + CSPGOAction CSAction, bool DebugInfoForProfiling, + bool PseudoProbeForProfiling) + : ProfileFile(ProfileFile), CSProfileGenFile(CSProfileGenFile), + ProfileRemappingFile(ProfileRemappingFile), Action(Action), + CSAction(CSAction), + DebugInfoForProfiling(DebugInfoForProfiling || + (Action == SampleUse && !PseudoProbeForProfiling)), + PseudoProbeForProfiling(PseudoProbeForProfiling), FS(std::move(FS)) { + // Note, we do allow ProfileFile.empty() for Action=IRUse LTO can + // callback with IRUse action without ProfileFile. + + // If there is a CSAction, PGOAction cannot be IRInstr or SampleUse. + assert(this->CSAction == NoCSAction || + (this->Action != IRInstr && this->Action != SampleUse)); + + // For CSIRInstr, CSProfileGenFile also needs to be nonempty. + assert(this->CSAction != CSIRInstr || !this->CSProfileGenFile.empty()); + + // If CSAction is CSIRUse, PGOAction needs to be IRUse as they share + // a profile. + assert(this->CSAction != CSIRUse || this->Action == IRUse); + + // If neither Action nor CSAction, DebugInfoForProfiling or + // PseudoProbeForProfiling needs to be true. + assert(this->Action != NoAction || this->CSAction != NoCSAction || + this->DebugInfoForProfiling || this->PseudoProbeForProfiling); + + // If we need to use the profile, the VFS cannot be nullptr. + assert(this->FS || !(this->Action == IRUse || this->CSAction == CSIRUse)); +} + +PGOOptions::PGOOptions(const PGOOptions &) = default; + +PGOOptions &PGOOptions::operator=(const PGOOptions &O) = default; + +PGOOptions::~PGOOptions() = default; diff --git a/llvm/lib/Target/X86/X86InsertPrefetch.cpp b/llvm/lib/Target/X86/X86InsertPrefetch.cpp --- a/llvm/lib/Target/X86/X86InsertPrefetch.cpp +++ b/llvm/lib/Target/X86/X86InsertPrefetch.cpp @@ -28,6 +28,7 @@ #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/ProfileData/SampleProf.h" #include "llvm/ProfileData/SampleProfReader.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Transforms/IPO/SampleProfile.h" using namespace llvm; using namespace sampleprof; @@ -159,8 +160,10 @@ return false; LLVMContext &Ctx = M.getContext(); + // TODO: Propagate virtual file system into LLVM targets. + auto FS = vfs::getRealFileSystem(); ErrorOr> ReaderOrErr = - SampleProfileReader::create(Filename, Ctx); + SampleProfileReader::create(Filename, Ctx, *FS); if (std::error_code EC = ReaderOrErr.getError()) { std::string Msg = "Could not open profile: " + EC.message(); Ctx.diagnose(DiagnosticInfoSampleProfile(Filename, Msg, diff --git a/llvm/lib/Transforms/IPO/SampleProfile.cpp b/llvm/lib/Transforms/IPO/SampleProfile.cpp --- a/llvm/lib/Transforms/IPO/SampleProfile.cpp +++ b/llvm/lib/Transforms/IPO/SampleProfile.cpp @@ -67,6 +67,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorOr.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/IPO/ProfiledCallGraph.h" @@ -457,10 +458,12 @@ public: SampleProfileLoader( StringRef Name, StringRef RemapName, ThinOrFullLTOPhase LTOPhase, + IntrusiveRefCntPtr FS, std::function GetAssumptionCache, std::function GetTargetTransformInfo, std::function GetTLI) - : SampleProfileLoaderBaseImpl(std::string(Name), std::string(RemapName)), + : SampleProfileLoaderBaseImpl(std::string(Name), std::string(RemapName), + std::move(FS)), GetAC(std::move(GetAssumptionCache)), GetTTI(std::move(GetTargetTransformInfo)), GetTLI(std::move(GetTLI)), LTOPhase(LTOPhase), @@ -1954,7 +1957,7 @@ auto &Ctx = M.getContext(); auto ReaderOrErr = SampleProfileReader::create( - Filename, Ctx, FSDiscriminatorPass::Base, RemappingFilename); + Filename, Ctx, *FS, FSDiscriminatorPass::Base, RemappingFilename); if (std::error_code EC = ReaderOrErr.getError()) { std::string Msg = "Could not open profile: " + EC.message(); Ctx.diagnose(DiagnosticInfoSampleProfile(Filename, Msg)); @@ -2327,6 +2330,11 @@ return emitAnnotations(F); return false; } +SampleProfileLoaderPass::SampleProfileLoaderPass( + std::string File, std::string RemappingFile, ThinOrFullLTOPhase LTOPhase, + IntrusiveRefCntPtr FS) + : ProfileFileName(File), ProfileRemappingFileName(RemappingFile), + LTOPhase(LTOPhase), FS(std::move(FS)) {} PreservedAnalyses SampleProfileLoaderPass::run(Module &M, ModuleAnalysisManager &AM) { @@ -2343,11 +2351,14 @@ return FAM.getResult(F); }; + if (!FS) + FS = vfs::getRealFileSystem(); + SampleProfileLoader SampleLoader( ProfileFileName.empty() ? SampleProfileFile : ProfileFileName, ProfileRemappingFileName.empty() ? SampleProfileRemappingFile : ProfileRemappingFileName, - LTOPhase, GetAssumptionCache, GetTTI, GetTLI); + LTOPhase, FS, GetAssumptionCache, GetTTI, GetTLI); if (!SampleLoader.doInitialization(M, &FAM)) return PreservedAnalyses::all(); diff --git a/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp b/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp --- a/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp +++ b/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp @@ -110,6 +110,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/GraphWriter.h" #include "llvm/Support/HashBuilder.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Instrumentation.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" @@ -2059,6 +2060,7 @@ static bool annotateAllFunctions( Module &M, StringRef ProfileFileName, StringRef ProfileRemappingFileName, + vfs::FileSystem &FS, function_ref LookupTLI, function_ref LookupBPI, function_ref LookupBFI, @@ -2066,8 +2068,8 @@ LLVM_DEBUG(dbgs() << "Read in profile counters: "); auto &Ctx = M.getContext(); // Read the counter array from file. - auto ReaderOrErr = - IndexedInstrProfReader::create(ProfileFileName, ProfileRemappingFileName); + auto ReaderOrErr = IndexedInstrProfReader::create(ProfileFileName, FS, + ProfileRemappingFileName); if (Error E = ReaderOrErr.takeError()) { handleAllErrors(std::move(E), [&](const ErrorInfoBase &EI) { Ctx.diagnose( @@ -2249,15 +2251,18 @@ return true; } -PGOInstrumentationUse::PGOInstrumentationUse(std::string Filename, - std::string RemappingFilename, - bool IsCS) +PGOInstrumentationUse::PGOInstrumentationUse( + std::string Filename, std::string RemappingFilename, bool IsCS, + IntrusiveRefCntPtr VFS) : ProfileFileName(std::move(Filename)), - ProfileRemappingFileName(std::move(RemappingFilename)), IsCS(IsCS) { + ProfileRemappingFileName(std::move(RemappingFilename)), IsCS(IsCS), + FS(std::move(VFS)) { if (!PGOTestProfileFile.empty()) ProfileFileName = PGOTestProfileFile; if (!PGOTestProfileRemappingFile.empty()) ProfileRemappingFileName = PGOTestProfileRemappingFile; + if (!FS) + FS = vfs::getRealFileSystem(); } PreservedAnalyses PGOInstrumentationUse::run(Module &M, @@ -2276,7 +2281,7 @@ auto *PSI = &AM.getResult(M); - if (!annotateAllFunctions(M, ProfileFileName, ProfileRemappingFileName, + if (!annotateAllFunctions(M, ProfileFileName, ProfileRemappingFileName, *FS, LookupTLI, LookupBPI, LookupBFI, PSI, IsCS)) return PreservedAnalyses::all(); diff --git a/llvm/tools/llvm-cov/CodeCoverage.cpp b/llvm/tools/llvm-cov/CodeCoverage.cpp --- a/llvm/tools/llvm-cov/CodeCoverage.cpp +++ b/llvm/tools/llvm-cov/CodeCoverage.cpp @@ -439,8 +439,9 @@ if (modifiedTimeGT(ObjectFilename, PGOFilename)) warning("profile data may be out of date - object is newer", ObjectFilename); + auto FS = vfs::getRealFileSystem(); auto CoverageOrErr = - CoverageMapping::load(ObjectFilenames, PGOFilename, CoverageArches, + CoverageMapping::load(ObjectFilenames, PGOFilename, *FS, CoverageArches, ViewOpts.CompilationDirectory, BIDFetcher.get()); if (Error E = CoverageOrErr.takeError()) { error("Failed to load coverage: " + toString(std::move(E))); diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp --- a/llvm/tools/llvm-profdata/llvm-profdata.cpp +++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp @@ -35,6 +35,7 @@ #include "llvm/Support/Path.h" #include "llvm/Support/ThreadPool.h" #include "llvm/Support/Threading.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/WithColor.h" #include "llvm/Support/raw_ostream.h" #include @@ -226,7 +227,8 @@ OverlapStats &Overlap, const OverlapFuncFilters &FuncFilter, raw_fd_ostream &OS, bool IsCS) { - auto ReaderOrErr = InstrProfReader::create(TestFilename); + auto FS = vfs::getRealFileSystem(); + auto ReaderOrErr = InstrProfReader::create(TestFilename, *FS); if (Error E = ReaderOrErr.takeError()) { // Skip the empty profiles by returning sliently. instrprof_error IPE = InstrProfError::take(std::move(E)); @@ -298,7 +300,8 @@ return; } - auto ReaderOrErr = InstrProfReader::create(Input.Filename, Correlator); + auto FS = vfs::getRealFileSystem(); + auto ReaderOrErr = InstrProfReader::create(Input.Filename, *FS, Correlator); if (Error E = ReaderOrErr.takeError()) { // Skip the empty profiles by returning sliently. instrprof_error IPE = InstrProfError::take(std::move(E)); @@ -838,8 +841,9 @@ // Read sample profile. LLVMContext Context; + auto FS = vfs::getRealFileSystem(); auto ReaderOrErr = sampleprof::SampleProfileReader::create( - SampleFilename.str(), Context, FSDiscriminatorPassOption); + SampleFilename.str(), Context, *FS, FSDiscriminatorPassOption); if (std::error_code EC = ReaderOrErr.getError()) exitWithErrorCode(EC, SampleFilename); auto Reader = std::move(ReaderOrErr.get()); @@ -975,7 +979,8 @@ std::optional ProfileIsProbeBased; std::optional ProfileIsCS; for (const auto &Input : Inputs) { - auto ReaderOrErr = SampleProfileReader::create(Input.Filename, Context, + auto FS = vfs::getRealFileSystem(); + auto ReaderOrErr = SampleProfileReader::create(Input.Filename, Context, *FS, FSDiscriminatorPassOption); if (std::error_code EC = ReaderOrErr.getError()) { warnOrExitGivenError(FailMode, EC, Input.Filename); @@ -2189,12 +2194,13 @@ using namespace sampleprof; LLVMContext Context; - auto BaseReaderOrErr = SampleProfileReader::create(BaseFilename, Context, + auto FS = vfs::getRealFileSystem(); + auto BaseReaderOrErr = SampleProfileReader::create(BaseFilename, Context, *FS, FSDiscriminatorPassOption); if (std::error_code EC = BaseReaderOrErr.getError()) exitWithErrorCode(EC, BaseFilename); - auto TestReaderOrErr = SampleProfileReader::create(TestFilename, Context, + auto TestReaderOrErr = SampleProfileReader::create(TestFilename, Context, *FS, FSDiscriminatorPassOption); if (std::error_code EC = TestReaderOrErr.getError()) exitWithErrorCode(EC, TestFilename); @@ -2372,7 +2378,8 @@ exitWithError("JSON output is not supported for instr profiles"); if (SFormat == ShowFormat::Yaml) exitWithError("YAML output is not supported for instr profiles"); - auto ReaderOrErr = InstrProfReader::create(Filename); + auto FS = vfs::getRealFileSystem(); + auto ReaderOrErr = InstrProfReader::create(Filename, *FS); std::vector Cutoffs = std::move(DetailedSummaryCutoffs); if (ShowDetailedSummary && Cutoffs.empty()) { Cutoffs = ProfileSummaryBuilder::DefaultCutoffs; @@ -2742,8 +2749,9 @@ exitWithError("YAML output is not supported for sample profiles"); using namespace sampleprof; LLVMContext Context; - auto ReaderOrErr = - SampleProfileReader::create(Filename, Context, FSDiscriminatorPassOption); + auto FS = vfs::getRealFileSystem(); + auto ReaderOrErr = SampleProfileReader::create(Filename, Context, *FS, + FSDiscriminatorPassOption); if (std::error_code EC = ReaderOrErr.getError()) exitWithErrorCode(EC, Filename); diff --git a/llvm/tools/llvm-profgen/llvm-profgen.cpp b/llvm/tools/llvm-profgen/llvm-profgen.cpp --- a/llvm/tools/llvm-profgen/llvm-profgen.cpp +++ b/llvm/tools/llvm-profgen/llvm-profgen.cpp @@ -19,6 +19,7 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/TargetSelect.h" +#include "llvm/Support/VirtualFileSystem.h" static cl::OptionCategory ProfGenCategory("ProfGen Options"); @@ -157,7 +158,9 @@ if (SampleProfFilename.getNumOccurrences()) { LLVMContext Context; - auto ReaderOrErr = SampleProfileReader::create(SampleProfFilename, Context); + auto FS = vfs::getRealFileSystem(); + auto ReaderOrErr = + SampleProfileReader::create(SampleProfFilename, Context, *FS); std::unique_ptr Reader = std::move(ReaderOrErr.get()); Reader->read(); diff --git a/llvm/tools/opt/NewPMDriver.cpp b/llvm/tools/opt/NewPMDriver.cpp --- a/llvm/tools/opt/NewPMDriver.cpp +++ b/llvm/tools/opt/NewPMDriver.cpp @@ -31,6 +31,7 @@ #include "llvm/Passes/StandardInstrumentations.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h" @@ -333,22 +334,25 @@ bool EnableDebugify, bool VerifyDIPreserve) { bool VerifyEachPass = VK == VK_VerifyEachPass; + auto FS = vfs::getRealFileSystem(); std::optional P; switch (PGOKindFlag) { case InstrGen: - P = PGOOptions(ProfileFile, "", "", PGOOptions::IRInstr); + P = PGOOptions(ProfileFile, "", "", FS, PGOOptions::IRInstr); break; case InstrUse: - P = PGOOptions(ProfileFile, "", ProfileRemappingFile, PGOOptions::IRUse); + P = PGOOptions(ProfileFile, "", ProfileRemappingFile, FS, + PGOOptions::IRUse); break; case SampleUse: - P = PGOOptions(ProfileFile, "", ProfileRemappingFile, + P = PGOOptions(ProfileFile, "", ProfileRemappingFile, FS, PGOOptions::SampleUse); break; case NoPGO: if (DebugInfoForProfiling || PseudoProbeForProfiling) - P = PGOOptions("", "", "", PGOOptions::NoAction, PGOOptions::NoCSAction, - DebugInfoForProfiling, PseudoProbeForProfiling); + P = PGOOptions("", "", "", nullptr, PGOOptions::NoAction, + PGOOptions::NoCSAction, DebugInfoForProfiling, + PseudoProbeForProfiling); else P = std::nullopt; } @@ -367,7 +371,7 @@ P->CSAction = PGOOptions::CSIRInstr; P->CSProfileGenFile = CSProfileGenFile; } else - P = PGOOptions("", CSProfileGenFile, ProfileRemappingFile, + P = PGOOptions("", CSProfileGenFile, ProfileRemappingFile, FS, PGOOptions::NoAction, PGOOptions::CSIRInstr); } else /* CSPGOKindFlag == CSInstrUse */ { if (!P) { diff --git a/llvm/unittests/ProfileData/SampleProfTest.cpp b/llvm/unittests/ProfileData/SampleProfTest.cpp --- a/llvm/unittests/ProfileData/SampleProfTest.cpp +++ b/llvm/unittests/ProfileData/SampleProfTest.cpp @@ -19,6 +19,7 @@ #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Testing/Support/SupportHelpers.h" #include "gtest/gtest.h" @@ -57,8 +58,9 @@ void readProfile(const Module &M, StringRef Profile, StringRef RemapFile = "") { + auto FS = vfs::getRealFileSystem(); auto ReaderOrErr = SampleProfileReader::create( - std::string(Profile), Context, FSDiscriminatorPass::Base, + std::string(Profile), Context, *FS, FSDiscriminatorPass::Base, std::string(RemapFile)); ASSERT_TRUE(NoError(ReaderOrErr.getError())); Reader = std::move(ReaderOrErr.get());