//===- llvm/IR/LLVMRemarkStreamer.cpp - Remark Streamer -*- 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 // //===----------------------------------------------------------------------===// // // This file contains the implementation of the conversion between IR // Diagnostics and serializable remarks::Remark objects. // //===----------------------------------------------------------------------===// #include "llvm/IR/LLVMRemarkStreamer.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalValue.h" #include "llvm/Remarks/RemarkStreamer.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/ToolOutputFile.h" #include using namespace llvm; /// DiagnosticKind -> remarks::Type static remarks::Type toRemarkType(enum DiagnosticKind Kind) { switch (Kind) { default: return remarks::Type::Unknown; case DK_OptimizationRemark: case DK_MachineOptimizationRemark: return remarks::Type::Passed; case DK_OptimizationRemarkMissed: case DK_MachineOptimizationRemarkMissed: return remarks::Type::Missed; case DK_OptimizationRemarkAnalysis: case DK_MachineOptimizationRemarkAnalysis: return remarks::Type::Analysis; case DK_OptimizationRemarkAnalysisFPCommute: return remarks::Type::AnalysisFPCommute; case DK_OptimizationRemarkAnalysisAliasing: return remarks::Type::AnalysisAliasing; case DK_OptimizationFailure: return remarks::Type::Failure; } } /// DiagnosticLocation -> remarks::RemarkLocation. static std::optional toRemarkLocation(const DiagnosticLocation &DL) { if (!DL.isValid()) return std::nullopt; StringRef File = DL.getRelativePath(); unsigned Line = DL.getLine(); unsigned Col = DL.getColumn(); return remarks::RemarkLocation{File, Line, Col}; } /// LLVM Diagnostic -> Remark remarks::Remark LLVMRemarkStreamer::toRemark(const DiagnosticInfoOptimizationBase &Diag) const { remarks::Remark R; // The result. R.RemarkType = toRemarkType(static_cast(Diag.getKind())); R.PassName = Diag.getPassName(); R.RemarkName = Diag.getRemarkName(); R.FunctionName = GlobalValue::dropLLVMManglingEscape(Diag.getFunction().getName()); R.Loc = toRemarkLocation(Diag.getLocation()); R.Hotness = Diag.getHotness(); for (const DiagnosticInfoOptimizationBase::Argument &Arg : Diag.getArgs()) { R.Args.emplace_back(); R.Args.back().Key = Arg.Key; R.Args.back().Val = Arg.Val; R.Args.back().Loc = toRemarkLocation(Arg.Loc); } return R; } void LLVMRemarkStreamer::emit(const DiagnosticInfoOptimizationBase &Diag) { if (!RS.matchesFilter(Diag.getPassName())) return; // First, convert the diagnostic to a remark. remarks::Remark R = toRemark(Diag); // Then, emit the remark through the serializer. RS.getSerializer().emit(R); } char LLVMRemarkSetupFileError::ID = 0; char LLVMRemarkSetupPatternError::ID = 0; char LLVMRemarkSetupFormatError::ID = 0; Expected llvm::setupLLVMOptimizationRemarks( LLVMContext &Context, StringRef RemarksFilename, StringRef RemarksPasses, StringRef RemarksFormat, bool RemarksWithHotness, std::optional RemarksHotnessThreshold) { if (RemarksWithHotness || RemarksHotnessThreshold.value_or(1)) Context.setDiagnosticsHotnessRequested(true); Context.setDiagnosticsHotnessThreshold(RemarksHotnessThreshold); if (RemarksFilename.empty()) return LLVMRemarkFileHandle(); Expected Format = remarks::parseFormat(RemarksFormat); if (Error E = Format.takeError()) return make_error(std::move(E)); std::error_code EC; auto Flags = *Format == remarks::Format::YAML ? sys::fs::OF_TextWithCRLF : sys::fs::OF_None; auto RemarksFile = std::make_unique(RemarksFilename, EC, Flags); // We don't use llvm::FileError here because some diagnostics want the file // name separately. if (EC) return make_error(errorCodeToError(EC)); Expected> RemarkSerializer = remarks::createRemarkSerializer(*Format, RemarksFile->os()); if (Error E = RemarkSerializer.takeError()) return make_error(std::move(E)); auto RS = std::make_unique( std::move(*RemarkSerializer), RemarksFilename); if (!RemarksPasses.empty()) if (Error E = RS->setFilter(RemarksPasses)) { RS->releaseSerializer(); return make_error(std::move(E)); } // Install the main remark streamer. Only install this after setting the // filter, because this might fail. Context.setMainRemarkStreamer(std::move(RS)); // Create LLVM's optimization remarks streamer. Context.setLLVMRemarkStreamer( std::make_unique(*Context.getMainRemarkStreamer())); return LLVMRemarkFileHandle{std::move(RemarksFile), Context}; } void LLVMRemarkFileHandle::Finalizer::finalize() { if (!Context) return; finalizeLLVMOptimizationRemarks(*Context); Context = nullptr; } Error llvm::setupLLVMOptimizationRemarks( LLVMContext &Context, raw_ostream &OS, StringRef RemarksPasses, StringRef RemarksFormat, bool RemarksWithHotness, std::optional RemarksHotnessThreshold) { if (RemarksWithHotness || RemarksHotnessThreshold.value_or(1)) Context.setDiagnosticsHotnessRequested(true); Context.setDiagnosticsHotnessThreshold(RemarksHotnessThreshold); Expected Format = remarks::parseFormat(RemarksFormat); if (Error E = Format.takeError()) return make_error(std::move(E)); Expected> RemarkSerializer = remarks::createRemarkSerializer(*Format, OS); if (Error E = RemarkSerializer.takeError()) return make_error(std::move(E)); auto RS = std::make_unique(std::move(*RemarkSerializer)); if (!RemarksPasses.empty()) if (Error E = RS->setFilter(RemarksPasses)) { RS->releaseSerializer(); return make_error(std::move(E)); } // Install the main remark streamer. Only install this after setting the // filter, because this might fail. Context.setMainRemarkStreamer(std::move(RS)); // Create LLVM's optimization remarks streamer. Context.setLLVMRemarkStreamer( std::make_unique(*Context.getMainRemarkStreamer())); return Error::success(); } void llvm::finalizeLLVMOptimizationRemarks(LLVMContext &Context) { Context.setLLVMRemarkStreamer(nullptr); if (auto *RS = Context.getMainRemarkStreamer()) { RS->releaseSerializer(); Context.setMainRemarkStreamer(nullptr); } }