From 76568372f46bc79b375283ddce48db10cdba3534 Mon Sep 17 00:00:00 2001 From: Tobias Stadler Date: Fri, 6 Jun 2025 18:20:30 +0100 Subject: [PATCH] [IRGen] Setup LLVMRemarkStreamer using existing RemarkStreamer Calling setupLLVMOptimizationRemarks overwrites the MainRemarkStreamer in the LLVM context. This prevents LLVM from serializing the remark meta information for the already emitted SIL remarks into the object file. Without the meta information bitstream remarks don't work correctly. Instead, emit SIL remarks and LLVM remarks to the same RemarkSerializer, and keep the file stream alive until after CodeGen. --- include/swift/AST/IRGenRequests.h | 16 +++++----- include/swift/SIL/SILRemarkStreamer.h | 4 +++ lib/IRGen/IRGen.cpp | 44 ++++++++++----------------- lib/IRGen/IRGenModule.cpp | 7 ++--- lib/IRGen/IRGenModule.h | 1 + 5 files changed, 33 insertions(+), 39 deletions(-) diff --git a/include/swift/AST/IRGenRequests.h b/include/swift/AST/IRGenRequests.h index a9819b27261..7285a7370f9 100644 --- a/include/swift/AST/IRGenRequests.h +++ b/include/swift/AST/IRGenRequests.h @@ -68,6 +68,7 @@ private: std::unique_ptr Context; std::unique_ptr Module; std::unique_ptr Target; + std::unique_ptr RemarkStream; GeneratedModule() : Context(nullptr), Module(nullptr), Target(nullptr) {} @@ -81,13 +82,14 @@ public: /// needed, use \c GeneratedModule::null() instead. explicit GeneratedModule(std::unique_ptr &&Context, std::unique_ptr &&Module, - std::unique_ptr &&Target) - : Context(std::move(Context)), Module(std::move(Module)), - Target(std::move(Target)) { - assert(getModule() && "Use GeneratedModule::null() instead"); - assert(getContext() && "Use GeneratedModule::null() instead"); - assert(getTargetMachine() && "Use GeneratedModule::null() instead"); - } + std::unique_ptr &&Target, + std::unique_ptr &&RemarkStream) + : Context(std::move(Context)), Module(std::move(Module)), + Target(std::move(Target)), RemarkStream(std::move(RemarkStream)) { + assert(getModule() && "Use GeneratedModule::null() instead"); + assert(getContext() && "Use GeneratedModule::null() instead"); + assert(getTargetMachine() && "Use GeneratedModule::null() instead"); + } GeneratedModule(GeneratedModule &&) = default; GeneratedModule& operator=(GeneratedModule &&) = default; diff --git a/include/swift/SIL/SILRemarkStreamer.h b/include/swift/SIL/SILRemarkStreamer.h index 9bb8cc182af..39dc9c639ce 100644 --- a/include/swift/SIL/SILRemarkStreamer.h +++ b/include/swift/SIL/SILRemarkStreamer.h @@ -72,6 +72,10 @@ public: /// \c llvm::remarks::RemarkStreamer with the given \c LLVMContext. void intoLLVMContext(llvm::LLVMContext &Ctx) &; + std::unique_ptr releaseStream() { + return std::move(remarkStream); + } + public: /// Emit a remark through the streamer. template diff --git a/lib/IRGen/IRGen.cpp b/lib/IRGen/IRGen.cpp index 79de76923f6..887b44f1aa0 100644 --- a/lib/IRGen/IRGen.cpp +++ b/lib/IRGen/IRGen.cpp @@ -703,32 +703,11 @@ bool swift::performLLVM(const IRGenOptions &Opts, assert(Opts.OutputKind == IRGenOutputKind::Module && "no output specified"); } - std::string OptRemarksRecordFile; - if (Opts.AnnotateCondFailMessage && !OutputFilename.empty()) { - OptRemarksRecordFile = std::string(OutputFilename); - OptRemarksRecordFile.append(".opt.yaml"); - } - auto &Ctxt = Module->getContext(); std::unique_ptr OldDiagnosticHandler = Ctxt.getDiagnosticHandler(); Ctxt.setDiagnosticHandler(std::make_unique(Opts)); - llvm::Expected> OptRecordFileOrErr = - setupLLVMOptimizationRemarks(Ctxt, OptRemarksRecordFile.c_str(), "annotation-remarks", "yaml", - false/*RemarksWithHotness*/, - 0/*RemarksHotnessThreshold*/); - - if (Error E = OptRecordFileOrErr.takeError()) { - diagnoseSync(Diags, DiagMutex, SourceLoc(), diag::error_opening_output, - StringRef(OptRemarksRecordFile.c_str()), - toString(std::move(E))); - return true; - } - - std::unique_ptr OptRecordFile = - std::move(*OptRecordFileOrErr); - performLLVMOptimizations(Opts, Diags, DiagMutex, Module, TargetMachine, OutputFile ? &OutputFile->getOS() : nullptr); @@ -759,10 +738,8 @@ bool swift::performLLVM(const IRGenOptions &Opts, } auto res = compileAndWriteLLVM(Module, TargetMachine, Opts, Stats, Diags, - *OutputFile, DiagMutex, - CASIDFile ? CASIDFile.get() : nullptr); - if (OptRecordFile) - OptRecordFile->keep(); + *OutputFile, DiagMutex, + CASIDFile ? CASIDFile.get() : nullptr); Ctxt.setDiagnosticHandler(std::move(OldDiagnosticHandler)); @@ -1166,7 +1143,7 @@ static void embedBitcode(llvm::Module *M, const IRGenOptions &Opts) NewUsed->setSection("llvm.metadata"); } -static void initLLVMModule(const IRGenModule &IGM, SILModule &SIL) { +static void initLLVMModule(IRGenModule &IGM, SILModule &SIL) { auto *Module = IGM.getModule(); assert(Module && "Expected llvm:Module for IR generation!"); @@ -1208,8 +1185,19 @@ static void initLLVMModule(const IRGenModule &IGM, SILModule &SIL) { "standard-library"), llvm::ConstantAsMetadata::get(Value)})); - if (auto *streamer = SIL.getSILRemarkStreamer()) { - streamer->intoLLVMContext(Module->getContext()); + if (auto *SILstreamer = SIL.getSILRemarkStreamer()) { + // Install RemarkStreamer into LLVM and keep the remarks file alive. This is + // required even if no LLVM remarks are enabled, because the AsmPrinter + // serializes meta information about the remarks into the object file. + IGM.RemarkStream = SILstreamer->releaseStream(); + SILstreamer->intoLLVMContext(Context); + auto &RS = *IGM.getLLVMContext().getMainRemarkStreamer(); + if (IGM.getOptions().AnnotateCondFailMessage) { + Context.setLLVMRemarkStreamer( + std::make_unique(RS)); + // FIXME: add a frontend flag to enable all LLVM remarks + cantFail(RS.setFilter("annotation-remarks")); + } } } diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp index a3a4ba6857b..40d92d8dc3b 100644 --- a/lib/IRGen/IRGenModule.cpp +++ b/lib/IRGen/IRGenModule.cpp @@ -1469,10 +1469,9 @@ bool IRGenModule::IsWellKnownBuiltinOrStructralType(CanType T) const { GeneratedModule IRGenModule::intoGeneratedModule() && { return GeneratedModule{ - std::move(LLVMContext), - std::unique_ptr{ClangCodeGen->ReleaseModule()}, - std::move(TargetMachine) - }; + std::move(LLVMContext), + std::unique_ptr{ClangCodeGen->ReleaseModule()}, + std::move(TargetMachine), std::move(RemarkStream)}; } bool IRGenerator::canEmitWitnessTableLazily(SILWitnessTable *wt) { diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index e0a333bce84..21ac4927179 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -674,6 +674,7 @@ public: SILModuleConventions silConv; ModuleDecl *ObjCModule = nullptr; ModuleDecl *ClangImporterModule = nullptr; + std::unique_ptr RemarkStream; llvm::StringMap OriginalModules; llvm::SmallString<128> OutputFilename;