//===- llvm/IR/RemarkStreamer.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 remark outputting as part of // LLVMContext. // //===----------------------------------------------------------------------===// #include "llvm/IR/RemarkStreamer.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalValue.h" #include "llvm/Remarks/BitstreamRemarkSerializer.h" #include "llvm/Remarks/RemarkFormat.h" #include "llvm/Remarks/RemarkSerializer.h" #include "llvm/Support/CommandLine.h" using namespace llvm; static cl::opt EnableRemarksSection( "remarks-section", cl::desc( "Emit a section containing remark diagnostics metadata. By default, " "this is enabled for the following formats: yaml-strtab, bitstream."), cl::init(cl::BOU_UNSET), cl::Hidden); RemarkStreamer::RemarkStreamer( std::unique_ptr RemarkSerializer, Optional FilenameIn) : PassFilter(), RemarkSerializer(std::move(RemarkSerializer)), Filename(FilenameIn ? Optional(FilenameIn->str()) : None) {} Error RemarkStreamer::setFilter(StringRef Filter) { Regex R = Regex(Filter); std::string RegexError; if (!R.isValid(RegexError)) return createStringError(std::make_error_code(std::errc::invalid_argument), RegexError.data()); PassFilter = std::move(R); return Error::success(); } /// 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 Optional toRemarkLocation(const DiagnosticLocation &DL) { if (!DL.isValid()) return None; StringRef File = DL.getRelativePath(); unsigned Line = DL.getLine(); unsigned Col = DL.getColumn(); return remarks::RemarkLocation{File, Line, Col}; } /// LLVM Diagnostic -> Remark remarks::Remark RemarkStreamer::toRemark(const DiagnosticInfoOptimizationBase &Diag) { 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 RemarkStreamer::emit(const DiagnosticInfoOptimizationBase &Diag) { if (Optional &Filter = PassFilter) if (!Filter->match(Diag.getPassName())) return; // First, convert the diagnostic to a remark. remarks::Remark R = toRemark(Diag); // Then, emit the remark through the serializer. RemarkSerializer->emit(R); } bool RemarkStreamer::needsSection() const { if (EnableRemarksSection == cl::BOU_TRUE) return true; if (EnableRemarksSection == cl::BOU_FALSE) return false; assert(EnableRemarksSection == cl::BOU_UNSET); // We only need a section if we're in separate mode. if (RemarkSerializer->Mode != remarks::SerializerMode::Separate) return false; // Only some formats need a section: // * bitstream // * yaml-strtab switch (RemarkSerializer->SerializerFormat) { case remarks::Format::YAMLStrTab: case remarks::Format::Bitstream: return true; default: return false; } } char RemarkSetupFileError::ID = 0; char RemarkSetupPatternError::ID = 0; char RemarkSetupFormatError::ID = 0; Expected> llvm::setupOptimizationRemarks(LLVMContext &Context, StringRef RemarksFilename, StringRef RemarksPasses, StringRef RemarksFormat, bool RemarksWithHotness, unsigned RemarksHotnessThreshold) { if (RemarksWithHotness) Context.setDiagnosticsHotnessRequested(true); if (RemarksHotnessThreshold) Context.setDiagnosticsHotnessThreshold(RemarksHotnessThreshold); if (RemarksFilename.empty()) return nullptr; 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_Text : 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, remarks::SerializerMode::Separate, RemarksFile->os()); if (Error E = RemarkSerializer.takeError()) return make_error(std::move(E)); Context.setRemarkStreamer(std::make_unique( std::move(*RemarkSerializer), RemarksFilename)); if (!RemarksPasses.empty()) if (Error E = Context.getRemarkStreamer()->setFilter(RemarksPasses)) return make_error(std::move(E)); return std::move(RemarksFile); } Error llvm::setupOptimizationRemarks(LLVMContext &Context, raw_ostream &OS, StringRef RemarksPasses, StringRef RemarksFormat, bool RemarksWithHotness, unsigned RemarksHotnessThreshold) { if (RemarksWithHotness) Context.setDiagnosticsHotnessRequested(true); if (RemarksHotnessThreshold) Context.setDiagnosticsHotnessThreshold(RemarksHotnessThreshold); Expected Format = remarks::parseFormat(RemarksFormat); if (Error E = Format.takeError()) return make_error(std::move(E)); Expected> RemarkSerializer = remarks::createRemarkSerializer(*Format, remarks::SerializerMode::Separate, OS); if (Error E = RemarkSerializer.takeError()) return make_error(std::move(E)); Context.setRemarkStreamer( std::make_unique(std::move(*RemarkSerializer))); if (!RemarksPasses.empty()) if (Error E = Context.getRemarkStreamer()->setFilter(RemarksPasses)) return make_error(std::move(E)); return Error::success(); }