================ @@ -48,428 +49,369 @@ #include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/YAMLTraits.h" #include "llvm/Transforms/IPO/Internalize.h" +#include "llvm/Transforms/Utils/Cloning.h" -#include <memory> #include <optional> using namespace clang; using namespace llvm; #define DEBUG_TYPE "codegenaction" namespace clang { - class BackendConsumer; - class ClangDiagnosticHandler final : public DiagnosticHandler { - public: - ClangDiagnosticHandler(const CodeGenOptions &CGOpts, BackendConsumer *BCon) - : CodeGenOpts(CGOpts), BackendCon(BCon) {} +class BackendConsumer; +class ClangDiagnosticHandler final : public DiagnosticHandler { +public: + ClangDiagnosticHandler(const CodeGenOptions &CGOpts, BackendConsumer *BCon) + : CodeGenOpts(CGOpts), BackendCon(BCon) {} - bool handleDiagnostics(const DiagnosticInfo &DI) override; + bool handleDiagnostics(const DiagnosticInfo &DI) override; - bool isAnalysisRemarkEnabled(StringRef PassName) const override { - return CodeGenOpts.OptimizationRemarkAnalysis.patternMatches(PassName); - } - bool isMissedOptRemarkEnabled(StringRef PassName) const override { - return CodeGenOpts.OptimizationRemarkMissed.patternMatches(PassName); - } - bool isPassedOptRemarkEnabled(StringRef PassName) const override { - return CodeGenOpts.OptimizationRemark.patternMatches(PassName); - } + bool isAnalysisRemarkEnabled(StringRef PassName) const override { + return CodeGenOpts.OptimizationRemarkAnalysis.patternMatches(PassName); + } + bool isMissedOptRemarkEnabled(StringRef PassName) const override { + return CodeGenOpts.OptimizationRemarkMissed.patternMatches(PassName); + } + bool isPassedOptRemarkEnabled(StringRef PassName) const override { + return CodeGenOpts.OptimizationRemark.patternMatches(PassName); + } - bool isAnyRemarkEnabled() const override { - return CodeGenOpts.OptimizationRemarkAnalysis.hasValidPattern() || - CodeGenOpts.OptimizationRemarkMissed.hasValidPattern() || - CodeGenOpts.OptimizationRemark.hasValidPattern(); - } + bool isAnyRemarkEnabled() const override { + return CodeGenOpts.OptimizationRemarkAnalysis.hasValidPattern() || + CodeGenOpts.OptimizationRemarkMissed.hasValidPattern() || + CodeGenOpts.OptimizationRemark.hasValidPattern(); + } - private: - const CodeGenOptions &CodeGenOpts; - BackendConsumer *BackendCon; - }; +private: + const CodeGenOptions &CodeGenOpts; + BackendConsumer *BackendCon; +}; + +static void reportOptRecordError(Error E, DiagnosticsEngine &Diags, + const CodeGenOptions &CodeGenOpts) { + handleAllErrors( + std::move(E), + [&](const LLVMRemarkSetupFileError &E) { + Diags.Report(diag::err_cannot_open_file) + << CodeGenOpts.OptRecordFile << E.message(); + }, + [&](const LLVMRemarkSetupPatternError &E) { + Diags.Report(diag::err_drv_optimization_remark_pattern) + << E.message() << CodeGenOpts.OptRecordPasses; + }, + [&](const LLVMRemarkSetupFormatError &E) { + Diags.Report(diag::err_drv_optimization_remark_format) + << CodeGenOpts.OptRecordFormat; + }); +} - static void reportOptRecordError(Error E, DiagnosticsEngine &Diags, - const CodeGenOptions &CodeGenOpts) { - handleAllErrors( - std::move(E), - [&](const LLVMRemarkSetupFileError &E) { - Diags.Report(diag::err_cannot_open_file) - << CodeGenOpts.OptRecordFile << E.message(); - }, - [&](const LLVMRemarkSetupPatternError &E) { - Diags.Report(diag::err_drv_optimization_remark_pattern) - << E.message() << CodeGenOpts.OptRecordPasses; - }, - [&](const LLVMRemarkSetupFormatError &E) { - Diags.Report(diag::err_drv_optimization_remark_format) - << CodeGenOpts.OptRecordFormat; - }); - } +BackendConsumer::BackendConsumer(BackendAction Action, DiagnosticsEngine &Diags, + IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, + const HeaderSearchOptions &HeaderSearchOpts, + const PreprocessorOptions &PPOpts, + const CodeGenOptions &CodeGenOpts, + const TargetOptions &TargetOpts, + const LangOptions &LangOpts, + const std::string &InFile, + SmallVector<LinkModule, 4> LinkModules, + std::unique_ptr<raw_pwrite_stream> OS, + LLVMContext &C, + CoverageSourceInfo *CoverageInfo) + : Diags(Diags), Action(Action), HeaderSearchOpts(HeaderSearchOpts), + CodeGenOpts(CodeGenOpts), TargetOpts(TargetOpts), LangOpts(LangOpts), + AsmOutStream(std::move(OS)), Context(nullptr), FS(VFS), + LLVMIRGeneration("irgen", "LLVM IR Generation Time"), + LLVMIRGenerationRefCount(0), + Gen(CreateLLVMCodeGen(Diags, InFile, std::move(VFS), HeaderSearchOpts, + PPOpts, CodeGenOpts, C, CoverageInfo)), + LinkModules(std::move(LinkModules)) { + TimerIsEnabled = CodeGenOpts.TimePasses; + llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses; + llvm::TimePassesPerRun = CodeGenOpts.TimePassesPerRun; +} - class BackendConsumer : public ASTConsumer { - using LinkModule = CodeGenAction::LinkModule; - - virtual void anchor(); - DiagnosticsEngine &Diags; - BackendAction Action; - const HeaderSearchOptions &HeaderSearchOpts; - const CodeGenOptions &CodeGenOpts; - const TargetOptions &TargetOpts; - const LangOptions &LangOpts; - std::unique_ptr<raw_pwrite_stream> AsmOutStream; - ASTContext *Context; - IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS; - - Timer LLVMIRGeneration; - unsigned LLVMIRGenerationRefCount; - - /// True if we've finished generating IR. This prevents us from generating - /// additional LLVM IR after emitting output in HandleTranslationUnit. This - /// can happen when Clang plugins trigger additional AST deserialization. - bool IRGenFinished = false; - - bool TimerIsEnabled = false; - - std::unique_ptr<CodeGenerator> Gen; - - SmallVector<LinkModule, 4> LinkModules; - - // A map from mangled names to their function's source location, used for - // backend diagnostics as the Clang AST may be unavailable. We actually use - // the mangled name's hash as the key because mangled names can be very - // long and take up lots of space. Using a hash can cause name collision, - // but that is rare and the consequences are pointing to a wrong source - // location which is not severe. This is a vector instead of an actual map - // because we optimize for time building this map rather than time - // retrieving an entry, as backend diagnostics are uncommon. - std::vector<std::pair<llvm::hash_code, FullSourceLoc>> - ManglingFullSourceLocs; - - // This is here so that the diagnostic printer knows the module a diagnostic - // refers to. - llvm::Module *CurLinkModule = nullptr; - - public: - BackendConsumer(BackendAction Action, DiagnosticsEngine &Diags, - IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, - const HeaderSearchOptions &HeaderSearchOpts, - const PreprocessorOptions &PPOpts, - const CodeGenOptions &CodeGenOpts, - const TargetOptions &TargetOpts, - const LangOptions &LangOpts, const std::string &InFile, - SmallVector<LinkModule, 4> LinkModules, - std::unique_ptr<raw_pwrite_stream> OS, LLVMContext &C, - CoverageSourceInfo *CoverageInfo = nullptr) - : Diags(Diags), Action(Action), HeaderSearchOpts(HeaderSearchOpts), - CodeGenOpts(CodeGenOpts), TargetOpts(TargetOpts), LangOpts(LangOpts), - AsmOutStream(std::move(OS)), Context(nullptr), FS(VFS), - LLVMIRGeneration("irgen", "LLVM IR Generation Time"), - LLVMIRGenerationRefCount(0), - Gen(CreateLLVMCodeGen(Diags, InFile, std::move(VFS), HeaderSearchOpts, - PPOpts, CodeGenOpts, C, CoverageInfo)), - LinkModules(std::move(LinkModules)) { - TimerIsEnabled = CodeGenOpts.TimePasses; - llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses; - llvm::TimePassesPerRun = CodeGenOpts.TimePassesPerRun; - } +// This constructor is used in installing an empty BackendConsumer +// to use the clang diagnostic handler for IR input files. It avoids +// initializing the OS field. +BackendConsumer::BackendConsumer(BackendAction Action, DiagnosticsEngine &Diags, + IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, + const HeaderSearchOptions &HeaderSearchOpts, + const PreprocessorOptions &PPOpts, + const CodeGenOptions &CodeGenOpts, + const TargetOptions &TargetOpts, + const LangOptions &LangOpts, + llvm::Module *Module, + SmallVector<LinkModule, 4> LinkModules, + LLVMContext &C, + CoverageSourceInfo *CoverageInfo) + : Diags(Diags), Action(Action), HeaderSearchOpts(HeaderSearchOpts), + CodeGenOpts(CodeGenOpts), TargetOpts(TargetOpts), LangOpts(LangOpts), + Context(nullptr), FS(VFS), + LLVMIRGeneration("irgen", "LLVM IR Generation Time"), + LLVMIRGenerationRefCount(0), + Gen(CreateLLVMCodeGen(Diags, "", std::move(VFS), HeaderSearchOpts, + PPOpts, CodeGenOpts, C, CoverageInfo)), + LinkModules(std::move(LinkModules)), CurLinkModule(Module) { + TimerIsEnabled = CodeGenOpts.TimePasses; + llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses; + llvm::TimePassesPerRun = CodeGenOpts.TimePassesPerRun; +} - // This constructor is used in installing an empty BackendConsumer - // to use the clang diagnostic handler for IR input files. It avoids - // initializing the OS field. - BackendConsumer(BackendAction Action, DiagnosticsEngine &Diags, - IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, - const HeaderSearchOptions &HeaderSearchOpts, - const PreprocessorOptions &PPOpts, - const CodeGenOptions &CodeGenOpts, - const TargetOptions &TargetOpts, - const LangOptions &LangOpts, llvm::Module *Module, - SmallVector<LinkModule, 4> LinkModules, LLVMContext &C, - CoverageSourceInfo *CoverageInfo = nullptr) - : Diags(Diags), Action(Action), HeaderSearchOpts(HeaderSearchOpts), - CodeGenOpts(CodeGenOpts), TargetOpts(TargetOpts), LangOpts(LangOpts), - Context(nullptr), FS(VFS), - LLVMIRGeneration("irgen", "LLVM IR Generation Time"), - LLVMIRGenerationRefCount(0), - Gen(CreateLLVMCodeGen(Diags, "", std::move(VFS), HeaderSearchOpts, - PPOpts, CodeGenOpts, C, CoverageInfo)), - LinkModules(std::move(LinkModules)), CurLinkModule(Module) { - TimerIsEnabled = CodeGenOpts.TimePasses; - llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses; - llvm::TimePassesPerRun = CodeGenOpts.TimePassesPerRun; - } - llvm::Module *getModule() const { return Gen->GetModule(); } - std::unique_ptr<llvm::Module> takeModule() { - return std::unique_ptr<llvm::Module>(Gen->ReleaseModule()); - } +llvm::Module* BackendConsumer::getModule() const { + return Gen->GetModule(); +} - CodeGenerator *getCodeGenerator() { return Gen.get(); } +std::unique_ptr<llvm::Module> BackendConsumer::takeModule() { + return std::unique_ptr<llvm::Module>(Gen->ReleaseModule()); +} - void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) override { - Gen->HandleCXXStaticMemberVarInstantiation(VD); - } +CodeGenerator* BackendConsumer::getCodeGenerator() { + return Gen.get(); +} - void Initialize(ASTContext &Ctx) override { - assert(!Context && "initialized multiple times"); +void BackendConsumer::HandleCXXStaticMemberVarInstantiation(VarDecl *VD) { + Gen->HandleCXXStaticMemberVarInstantiation(VD); +} - Context = &Ctx; +void BackendConsumer::Initialize(ASTContext &Ctx) { + assert(!Context && "initialized multiple times"); - if (TimerIsEnabled) - LLVMIRGeneration.startTimer(); + Context = &Ctx; - Gen->Initialize(Ctx); + if (TimerIsEnabled) + LLVMIRGeneration.startTimer(); - if (TimerIsEnabled) - LLVMIRGeneration.stopTimer(); - } + Gen->Initialize(Ctx); - bool HandleTopLevelDecl(DeclGroupRef D) override { - PrettyStackTraceDecl CrashInfo(*D.begin(), SourceLocation(), - Context->getSourceManager(), - "LLVM IR generation of declaration"); + if (TimerIsEnabled) + LLVMIRGeneration.stopTimer(); +} - // Recurse. - if (TimerIsEnabled) { - LLVMIRGenerationRefCount += 1; - if (LLVMIRGenerationRefCount == 1) - LLVMIRGeneration.startTimer(); - } +bool BackendConsumer::HandleTopLevelDecl(DeclGroupRef D) { + PrettyStackTraceDecl CrashInfo(*D.begin(), SourceLocation(), + Context->getSourceManager(), + "LLVM IR generation of declaration"); - Gen->HandleTopLevelDecl(D); + // Recurse. + if (TimerIsEnabled) { + LLVMIRGenerationRefCount += 1; + if (LLVMIRGenerationRefCount == 1) + LLVMIRGeneration.startTimer(); + } - if (TimerIsEnabled) { - LLVMIRGenerationRefCount -= 1; - if (LLVMIRGenerationRefCount == 0) - LLVMIRGeneration.stopTimer(); - } + Gen->HandleTopLevelDecl(D); - return true; - } + if (TimerIsEnabled) { + LLVMIRGenerationRefCount -= 1; + if (LLVMIRGenerationRefCount == 0) + LLVMIRGeneration.stopTimer(); + } - void HandleInlineFunctionDefinition(FunctionDecl *D) override { - PrettyStackTraceDecl CrashInfo(D, SourceLocation(), - Context->getSourceManager(), - "LLVM IR generation of inline function"); - if (TimerIsEnabled) - LLVMIRGeneration.startTimer(); + return true; +} - Gen->HandleInlineFunctionDefinition(D); +void BackendConsumer::HandleInlineFunctionDefinition(FunctionDecl *D) { + PrettyStackTraceDecl CrashInfo(D, SourceLocation(), + Context->getSourceManager(), + "LLVM IR generation of inline function"); + if (TimerIsEnabled) + LLVMIRGeneration.startTimer(); - if (TimerIsEnabled) - LLVMIRGeneration.stopTimer(); - } + Gen->HandleInlineFunctionDefinition(D); - void HandleInterestingDecl(DeclGroupRef D) override { - // Ignore interesting decls from the AST reader after IRGen is finished. - if (!IRGenFinished) - HandleTopLevelDecl(D); - } + if (TimerIsEnabled) + LLVMIRGeneration.stopTimer(); +} - // Links each entry in LinkModules into our module. Returns true on error. - bool LinkInModules(llvm::Module *M) { - for (auto &LM : LinkModules) { - assert(LM.Module && "LinkModule does not actually have a module"); - if (LM.PropagateAttrs) - for (Function &F : *LM.Module) { - // Skip intrinsics. Keep consistent with how intrinsics are created - // in LLVM IR. - if (F.isIntrinsic()) - continue; - CodeGen::mergeDefaultFunctionDefinitionAttributes( - F, CodeGenOpts, LangOpts, TargetOpts, LM.Internalize); - } - - CurLinkModule = LM.Module.get(); - - bool Err; - if (LM.Internalize) { - Err = Linker::linkModules( - *M, std::move(LM.Module), LM.LinkFlags, - [](llvm::Module &M, const llvm::StringSet<> &GVS) { - internalizeModule(M, [&GVS](const llvm::GlobalValue &GV) { - return !GV.hasName() || (GVS.count(GV.getName()) == 0); - }); - }); - } else { - Err = Linker::linkModules(*M, std::move(LM.Module), LM.LinkFlags); - } +void BackendConsumer::HandleInterestingDecl(DeclGroupRef D) { + // Ignore interesting decls from the AST reader after IRGen is finished. + if (!IRGenFinished) + HandleTopLevelDecl(D); +} - if (Err) - return true; - } - LinkModules.clear(); - return false; // success - } +// Links each entry in LinkModules into our module. Returns true on error. +bool BackendConsumer::LinkInModules(llvm::Module *M, bool ShouldLinkFiles) { - void HandleTranslationUnit(ASTContext &C) override { - { - llvm::TimeTraceScope TimeScope("Frontend"); - PrettyStackTraceString CrashInfo("Per-file LLVM IR generation"); - if (TimerIsEnabled) { - LLVMIRGenerationRefCount += 1; - if (LLVMIRGenerationRefCount == 1) - LLVMIRGeneration.startTimer(); - } + for (auto &LM : LinkModules) { + assert(LM.Module && "LinkModule does not actually have a module"); - Gen->HandleTranslationUnit(C); - if (TimerIsEnabled) { - LLVMIRGenerationRefCount -= 1; - if (LLVMIRGenerationRefCount == 0) - LLVMIRGeneration.stopTimer(); - } + // If ShouldLinkFiles is not set, skip files added via the + // -mlink-bitcode-files, only linking -mlink-builtin-bitcode + if (!LM.Internalize && !ShouldLinkFiles) + continue; - IRGenFinished = true; - } - // Silently ignore if we weren't initialized for some reason. - if (!getModule()) - return; - - LLVMContext &Ctx = getModule()->getContext(); - std::unique_ptr<DiagnosticHandler> OldDiagnosticHandler = - Ctx.getDiagnosticHandler(); - Ctx.setDiagnosticHandler(std::make_unique<ClangDiagnosticHandler>( - CodeGenOpts, this)); - - Expected<std::unique_ptr<llvm::ToolOutputFile>> OptRecordFileOrErr = - setupLLVMOptimizationRemarks( - Ctx, CodeGenOpts.OptRecordFile, CodeGenOpts.OptRecordPasses, - CodeGenOpts.OptRecordFormat, CodeGenOpts.DiagnosticsWithHotness, - CodeGenOpts.DiagnosticsHotnessThreshold); - - if (Error E = OptRecordFileOrErr.takeError()) { - reportOptRecordError(std::move(E), Diags, CodeGenOpts); - return; + if (LM.PropagateAttrs) + for (Function &F : *LM.Module) { + // Skip intrinsics. Keep consistent with how intrinsics are created + // in LLVM IR. + if (F.isIntrinsic()) + continue; + CodeGen::mergeDefaultFunctionDefinitionAttributes( + F, CodeGenOpts, LangOpts, TargetOpts, LM.Internalize); } - std::unique_ptr<llvm::ToolOutputFile> OptRecordFile = - std::move(*OptRecordFileOrErr); + CurLinkModule = LM.Module.get(); + + // TODO: If CloneModule() is updated to support cloning of unmaterialized + // modules, we can remove this + bool Err; + if (Error E = CurLinkModule->materializeAll()) + return false; + + // Create a Clone to move to the linker, which preserves the original + // linking modules, allowing them to be linked again in the future + // TODO: Add a ShouldCleanup option to make Cloning optional. When + // set, we can pass the original modules to the linker for cleanup + std::unique_ptr<llvm::Module> Clone = llvm::CloneModule(*LM.Module); + + if (LM.Internalize) { + Err = Linker::linkModules( + *M, std::move(Clone), LM.LinkFlags, + [](llvm::Module &M, const llvm::StringSet<> &GVS) { + + internalizeModule(M, [&GVS](const llvm::GlobalValue &GV) { + return !GV.hasName() || + (GVS.count(GV.getName()) == 0); + }); + }); + } else + Err = Linker::linkModules(*M, std::move(Clone), LM.LinkFlags); + + if (Err) ---------------- jhuber6 wrote:
Where do we do the attribute propagation now? https://github.com/llvm/llvm-project/pull/69371 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits