llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Jacob Lambert (lamb-j) <details> <summary>Changes</summary> This set of patches updates device library linking and optimization to do the following: Link Optimize Link (New) This handles the edge case where optimization introduces new device library functions, such as a fused sincos() from separate sin() and cos() calls. The second link step ensures the sincos() definition is also linked in from the device libraries. --- Patch is 51.23 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/69371.diff 6 Files Affected: - (added) clang/lib/CodeGen/BackendConsumer.h (+166) - (modified) clang/lib/CodeGen/BackendUtil.cpp (+42-30) - (modified) clang/lib/CodeGen/CMakeLists.txt (+1) - (modified) clang/lib/CodeGen/CodeGenAction.cpp (+303-361) - (added) clang/lib/CodeGen/LinkInModulesPass.cpp (+29) - (added) clang/lib/CodeGen/LinkInModulesPass.h (+43) ``````````diff diff --git a/clang/lib/CodeGen/BackendConsumer.h b/clang/lib/CodeGen/BackendConsumer.h new file mode 100644 index 000000000000000..72a814cd43d738d --- /dev/null +++ b/clang/lib/CodeGen/BackendConsumer.h @@ -0,0 +1,166 @@ +//===--- BackendConsumer.h - LLVM BackendConsumer Header File -------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_CODEGEN_BACKENDCONSUMER_H +#define LLVM_CLANG_LIB_CODEGEN_BACKENDCONSUMER_H + +#include "clang/CodeGen/BackendUtil.h" +#include "clang/CodeGen/CodeGenAction.h" + +#include "llvm/IR/DiagnosticInfo.h" +#include "llvm/Support/Timer.h" + +namespace llvm { + class DiagnosticInfoDontCall; +} + +namespace clang { +class ASTContext; +class CodeGenAction; +class CoverageSourceInfo; + +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; + + llvm::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, llvm::LLVMContext &C, + CoverageSourceInfo *CoverageInfo = nullptr); + + // 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, llvm::LLVMContext &C, + CoverageSourceInfo *CoverageInfo = nullptr); + + llvm::Module *getModule() const; + std::unique_ptr<llvm::Module> takeModule(); + + CodeGenerator *getCodeGenerator(); + + void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) override; + void Initialize(ASTContext &Ctx) override; + bool HandleTopLevelDecl(DeclGroupRef D) override; + void HandleInlineFunctionDefinition(FunctionDecl *D) override; + void HandleInterestingDecl(DeclGroupRef D) override; + void HandleTranslationUnit(ASTContext &C) override; + void HandleTagDeclDefinition(TagDecl *D) override; + void HandleTagDeclRequiredDefinition(const TagDecl *D) override; + void CompleteTentativeDefinition(VarDecl *D) override; + void CompleteExternalDeclaration(VarDecl *D) override; + void AssignInheritanceModel(CXXRecordDecl *RD) override; + void HandleVTable(CXXRecordDecl *RD) override; + + + // Links each entry in LinkModules into our module. Returns true on error. + bool LinkInModules(llvm::Module *M, bool ShouldLinkFiles = true); + + /// Get the best possible source location to represent a diagnostic that + /// may have associated debug info. + const FullSourceLoc getBestLocationFromDebugLoc( + const llvm::DiagnosticInfoWithLocationBase &D, + bool &BadDebugInfo, StringRef &Filename, + unsigned &Line, unsigned &Column) const; + + std::optional<FullSourceLoc> getFunctionSourceLocation( + const llvm::Function &F) const; + + void DiagnosticHandlerImpl(const llvm::DiagnosticInfo &DI); + /// Specialized handler for InlineAsm diagnostic. + /// \return True if the diagnostic has been successfully reported, false + /// otherwise. + bool InlineAsmDiagHandler(const llvm::DiagnosticInfoInlineAsm &D); + /// Specialized handler for diagnostics reported using SMDiagnostic. + void SrcMgrDiagHandler(const llvm::DiagnosticInfoSrcMgr &D); + /// Specialized handler for StackSize diagnostic. + /// \return True if the diagnostic has been successfully reported, false + /// otherwise. + bool StackSizeDiagHandler(const llvm::DiagnosticInfoStackSize &D); + /// Specialized handler for ResourceLimit diagnostic. + /// \return True if the diagnostic has been successfully reported, false + /// otherwise. + bool ResourceLimitDiagHandler(const llvm::DiagnosticInfoResourceLimit &D); + + /// Specialized handler for unsupported backend feature diagnostic. + void UnsupportedDiagHandler(const llvm::DiagnosticInfoUnsupported &D); + /// Specialized handlers for optimization remarks. + /// Note that these handlers only accept remarks and they always handle + /// them. + void EmitOptimizationMessage(const llvm::DiagnosticInfoOptimizationBase &D, + unsigned DiagID); + void + OptimizationRemarkHandler(const llvm::DiagnosticInfoOptimizationBase &D); + void OptimizationRemarkHandler( + const llvm::OptimizationRemarkAnalysisFPCommute &D); + void OptimizationRemarkHandler( + const llvm::OptimizationRemarkAnalysisAliasing &D); + void OptimizationFailureHandler( + const llvm::DiagnosticInfoOptimizationFailure &D); + void DontCallDiagHandler(const llvm::DiagnosticInfoDontCall &D); + /// Specialized handler for misexpect warnings. + /// Note that misexpect remarks are emitted through ORE + void MisExpectDiagHandler(const llvm::DiagnosticInfoMisExpect &D); +}; + +} // namespace clang +#endif diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index d066819871dfde3..894daced377fb55 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -6,6 +6,8 @@ // //===----------------------------------------------------------------------===// +#include "BackendConsumer.h" +#include "LinkInModulesPass.h" #include "clang/CodeGen/BackendUtil.h" #include "clang/Basic/CodeGenOptions.h" #include "clang/Basic/Diagnostic.h" @@ -112,7 +114,7 @@ class EmitAssemblyHelper { const CodeGenOptions &CodeGenOpts; const clang::TargetOptions &TargetOpts; const LangOptions &LangOpts; - Module *TheModule; + llvm::Module *TheModule; IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS; Timer CodeGenerationTime; @@ -155,10 +157,10 @@ class EmitAssemblyHelper { return F; } - void - RunOptimizationPipeline(BackendAction Action, + void RunOptimizationPipeline(BackendAction Action, std::unique_ptr<raw_pwrite_stream> &OS, - std::unique_ptr<llvm::ToolOutputFile> &ThinLinkOS); + std::unique_ptr<llvm::ToolOutputFile> &ThinLinkOS, + BackendConsumer *BC); void RunCodegenPipeline(BackendAction Action, std::unique_ptr<raw_pwrite_stream> &OS, std::unique_ptr<llvm::ToolOutputFile> &DwoOS); @@ -178,7 +180,7 @@ class EmitAssemblyHelper { const HeaderSearchOptions &HeaderSearchOpts, const CodeGenOptions &CGOpts, const clang::TargetOptions &TOpts, - const LangOptions &LOpts, Module *M, + const LangOptions &LOpts, llvm::Module *M, IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) : Diags(_Diags), HSOpts(HeaderSearchOpts), CodeGenOpts(CGOpts), TargetOpts(TOpts), LangOpts(LOpts), TheModule(M), VFS(std::move(VFS)), @@ -194,7 +196,8 @@ class EmitAssemblyHelper { // Emit output using the new pass manager for the optimization pipeline. void EmitAssembly(BackendAction Action, - std::unique_ptr<raw_pwrite_stream> OS); + std::unique_ptr<raw_pwrite_stream> OS, + BackendConsumer *BC); }; } @@ -690,7 +693,7 @@ static void addSanitizers(const Triple &TargetTriple, // the logic of the original code, but operates on "shadow" values. It // can benefit from re-running some general purpose optimization // passes. - MPM.addPass(RequireAnalysisPass<GlobalsAA, Module>()); + MPM.addPass(RequireAnalysisPass<GlobalsAA, llvm::Module>()); FunctionPassManager FPM; FPM.addPass(EarlyCSEPass(true /* Enable mem-ssa. */)); FPM.addPass(InstCombinePass()); @@ -749,7 +752,7 @@ static void addSanitizers(const Triple &TargetTriple, SanitizersCallback(NewMPM, Level); if (!NewMPM.isEmpty()) { // Sanitizers can abandon<GlobalsAA>. - NewMPM.addPass(RequireAnalysisPass<GlobalsAA, Module>()); + NewMPM.addPass(RequireAnalysisPass<GlobalsAA, llvm::Module>()); MPM.addPass(std::move(NewMPM)); } }); @@ -761,7 +764,7 @@ static void addSanitizers(const Triple &TargetTriple, void EmitAssemblyHelper::RunOptimizationPipeline( BackendAction Action, std::unique_ptr<raw_pwrite_stream> &OS, - std::unique_ptr<llvm::ToolOutputFile> &ThinLinkOS) { + std::unique_ptr<llvm::ToolOutputFile> &ThinLinkOS, BackendConsumer *BC) { std::optional<PGOOptions> PGOOpt; if (CodeGenOpts.hasProfileIRInstr()) @@ -1035,6 +1038,12 @@ void EmitAssemblyHelper::RunOptimizationPipeline( } } + // Re-link against any bitcodes supplied via the -mlink-builtin-bitcode option + // Some optimizations may generate new function calls that would not have + // been linked pre-optimization (i.e. fused sincos calls generated by + // AMDGPULibCalls::fold_sincos.) + MPM.addPass(LinkInModulesPass(BC, false)); + // Add a verifier pass if requested. We don't have to do this if the action // requires code generation because there will already be a verifier pass in // the code-generation pipeline. @@ -1046,7 +1055,7 @@ void EmitAssemblyHelper::RunOptimizationPipeline( if (Action == Backend_EmitBC || Action == Backend_EmitLL) { if (CodeGenOpts.PrepareForThinLTO && !CodeGenOpts.DisableLLVMPasses) { if (!TheModule->getModuleFlag("EnableSplitLTOUnit")) - TheModule->addModuleFlag(Module::Error, "EnableSplitLTOUnit", + TheModule->addModuleFlag(llvm::Module::Error, "EnableSplitLTOUnit", CodeGenOpts.EnableSplitLTOUnit); if (Action == Backend_EmitBC) { if (!CodeGenOpts.ThinLinkBitcodeFile.empty()) { @@ -1055,7 +1064,7 @@ void EmitAssemblyHelper::RunOptimizationPipeline( return; } if (CodeGenOpts.UnifiedLTO) - TheModule->addModuleFlag(Module::Error, "UnifiedLTO", uint32_t(1)); + TheModule->addModuleFlag(llvm::Module::Error, "UnifiedLTO", uint32_t(1)); MPM.addPass(ThinLTOBitcodeWriterPass( *OS, ThinLinkOS ? &ThinLinkOS->os() : nullptr)); } else { @@ -1069,12 +1078,12 @@ void EmitAssemblyHelper::RunOptimizationPipeline( bool EmitLTOSummary = shouldEmitRegularLTOSummary(); if (EmitLTOSummary) { if (!TheModule->getModuleFlag("ThinLTO") && !CodeGenOpts.UnifiedLTO) - TheModule->addModuleFlag(Module::Error, "ThinLTO", uint32_t(0)); + TheModule->addModuleFlag(llvm::Module::Error, "ThinLTO", uint32_t(0)); if (!TheModule->getModuleFlag("EnableSplitLTOUnit")) - TheModule->addModuleFlag(Module::Error, "EnableSplitLTOUnit", + TheModule->addModuleFlag(llvm::Module::Error, "EnableSplitLTOUnit", uint32_t(1)); if (CodeGenOpts.UnifiedLTO) - TheModule->addModuleFlag(Module::Error, "UnifiedLTO", uint32_t(1)); + TheModule->addModuleFlag(llvm::Module::Error, "UnifiedLTO", uint32_t(1)); } if (Action == Backend_EmitBC) MPM.addPass(BitcodeWriterPass(*OS, CodeGenOpts.EmitLLVMUseLists, @@ -1088,13 +1097,13 @@ void EmitAssemblyHelper::RunOptimizationPipeline( // Set module flags, like EnableSplitLTOUnit and UnifiedLTO, since FatLTO // uses a different action than Backend_EmitBC or Backend_EmitLL. if (!TheModule->getModuleFlag("ThinLTO")) - TheModule->addModuleFlag(Module::Error, "ThinLTO", + TheModule->addModuleFlag(llvm::Module::Error, "ThinLTO", uint32_t(CodeGenOpts.PrepareForThinLTO)); if (!TheModule->getModuleFlag("EnableSplitLTOUnit")) - TheModule->addModuleFlag(Module::Error, "EnableSplitLTOUnit", + TheModule->addModuleFlag(llvm::Module::Error, "EnableSplitLTOUnit", uint32_t(CodeGenOpts.EnableSplitLTOUnit)); if (CodeGenOpts.UnifiedLTO && !TheModule->getModuleFlag("UnifiedLTO")) - TheModule->addModuleFlag(Module::Error, "UnifiedLTO", uint32_t(1)); + TheModule->addModuleFlag(llvm::Module::Error, "UnifiedLTO", uint32_t(1)); } // Print a textual, '-passes=' compatible, representation of pipeline if @@ -1160,7 +1169,8 @@ void EmitAssemblyHelper::RunCodegenPipeline( } void EmitAssemblyHelper::EmitAssembly(BackendAction Action, - std::unique_ptr<raw_pwrite_stream> OS) { + std::unique_ptr<raw_pwrite_stream> OS, + BackendConsumer *BC) { TimeRegion Region(CodeGenOpts.TimePasses ? &CodeGenerationTime : nullptr); setCommandLineOpts(CodeGenOpts); @@ -1176,7 +1186,7 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action, cl::PrintOptionValues(); std::unique_ptr<llvm::ToolOutputFile> ThinLinkOS, DwoOS; - RunOptimizationPipeline(Action, OS, ThinLinkOS); + RunOptimizationPipeline(Action, OS, ThinLinkOS, BC); RunCodegenPipeline(Action, OS, DwoOS); if (ThinLinkOS) @@ -1186,11 +1196,12 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action, } static void runThinLTOBackend( - DiagnosticsEngine &Diags, ModuleSummaryIndex *CombinedIndex, Module *M, - const HeaderSearchOptions &HeaderOpts, const CodeGenOptions &CGOpts, - const clang::TargetOptions &TOpts, const LangOptions &LOpts, - std::unique_ptr<raw_pwrite_stream> OS, std::string SampleProfile, - std::string ProfileRemapping, BackendAction Action) { + DiagnosticsEngine &Diags, ModuleSummaryIndex *CombinedIndex, + llvm::Module *M, const HeaderSearchOptions &HeaderOpts, + const CodeGenOptions &CGOpts, const clang::TargetOptions &TOpts, + const LangOptions &LOpts, std::unique_ptr<raw_pwrite_stream> OS, + std::string SampleProfile, std::string ProfileRemapping, + BackendAction Action) { DenseMap<StringRef, DenseMap<GlobalValue::GUID, GlobalValueSummary *>> ModuleToDefinedGVSummaries; CombinedIndex->collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries); @@ -1259,18 +1270,18 @@ static void runThinLTOBackend( Conf.SplitDwarfOutput = CGOpts.SplitDwarfOutput; switch (Action) { case Backend_EmitNothing: - Conf.PreCodeGenModuleHook = [](size_t Task, const Module &Mod) { + Conf.PreCodeGenModuleHook = [](size_t Task, const llvm::Module &Mod) { return false; }; break; case Backend_EmitLL: - Conf.PreCodeGenModuleHook = [&](size_t Task, const Module &Mod) { + Conf.PreCodeGenModuleHook = [&](size_t Task, const llvm::Module &Mod) { M->print(*OS, nullptr, CGOpts.EmitLLVMUseLists); return false; }; break; case Backend_EmitBC: - Conf.PreCodeGenModuleHook = [&](size_t Task, const Module &Mod) { + Conf.PreCodeGenModuleHook = [&](size_t Task, const llvm::Module &Mod) { WriteBitcodeToFile(*M, *OS, CGOpts.EmitLLVMUseLists); return false; }; @@ -1294,9 +1305,10 @@ void clang::EmitBackendOutput(DiagnosticsEngine &Diags, const CodeGenOptions &CGOpts, const clang::TargetOptions &TOpts, const LangOptions &LOpts, StringRef TDesc, - Module *M, BackendAction Action, + llvm::Module *M, BackendAction Action, IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, - std::unique_ptr<raw_pwrite_stream> OS) { + std::unique_ptr<raw_pwrite_stream> OS, + BackendConsumer *BC) { llvm::TimeTraceScope TimeScope("Backend"); @@ -1339,7 +1351,7 @@ void clang::EmitBackendOutput(DiagnosticsEngine &Diags, } EmitAssemblyHelper AsmHelper(Diags, HeaderOpts, CGOpts, TOpts, LOpts, M, VFS); - AsmHelper.EmitAssembly(Action, std::move(OS)); + AsmHelper.EmitAssembly(Action, std::move(OS), BC); // Verify clang's TargetInfo DataLayout against the LLVM TargetMachine's // DataLayout. diff --git a/clang/lib/CodeGen/CMakeLists.txt b/clang/lib/CodeGen/CMakeLists.txt index 1debeb6d9cce9e0..41e31c12a16e641 100644 --- a/clang/lib/CodeGen/CMakeLists.txt +++ b/clang/lib/CodeGen/CMakeLists.txt @@ -81,6 +81,7 @@ add_clang_library(clangCodeGen ConstantInitBuilder.cpp CoverageMappingGen.cpp ItaniumCXXABI.cpp + LinkInModulesPass.cpp MacroPPCallbacks.cpp MicrosoftCXXABI.cpp ModuleBuilder.cpp diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp index a3b72381d73fc54..f4586a776c0fefd 100644 --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "clang/CodeGen/CodeGenAction.h" +#include "BackendConsumer.h" #include "CGCall.h" #include "CodeGenModule.h" #include "CoverageMappingGen.h" @@ -48,8 +49,8 @@ #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; @@ -57,419 +58,360 @@ 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) over... [truncated] `````````` </details> 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