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 a9819b2726105..7285a7370f95f 100644 --- a/include/swift/AST/IRGenRequests.h +++ b/include/swift/AST/IRGenRequests.h @@ -68,6 +68,7 @@ class GeneratedModule final { 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 @@ class GeneratedModule final { /// 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 9bb8cc182af1a..39dc9c639ce62 100644 --- a/include/swift/SIL/SILRemarkStreamer.h +++ b/include/swift/SIL/SILRemarkStreamer.h @@ -72,6 +72,10 @@ class SILRemarkStreamer { /// \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 79de76923f69a..887b44f1aa0bc 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 a3a4ba6857b68..40d92d8dc3b8c 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 e0a333bce841e..21ac492717951 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -674,6 +674,7 @@ class IRGenModule { SILModuleConventions silConv; ModuleDecl *ObjCModule = nullptr; ModuleDecl *ClangImporterModule = nullptr; + std::unique_ptr RemarkStream; llvm::StringMap OriginalModules; llvm::SmallString<128> OutputFilename;