RemarkStreamer.cpp revision 360784
1//===- llvm/IR/RemarkStreamer.cpp - Remark Streamer -*- C++ -------------*-===// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8// 9// This file contains the implementation of the remark outputting as part of 10// LLVMContext. 11// 12//===----------------------------------------------------------------------===// 13 14#include "llvm/IR/RemarkStreamer.h" 15#include "llvm/IR/DiagnosticInfo.h" 16#include "llvm/IR/Function.h" 17#include "llvm/IR/GlobalValue.h" 18#include "llvm/Remarks/BitstreamRemarkSerializer.h" 19#include "llvm/Remarks/RemarkFormat.h" 20#include "llvm/Remarks/RemarkSerializer.h" 21#include "llvm/Support/CommandLine.h" 22 23using namespace llvm; 24 25static cl::opt<cl::boolOrDefault> EnableRemarksSection( 26 "remarks-section", 27 cl::desc( 28 "Emit a section containing remark diagnostics metadata. By default, " 29 "this is enabled for the following formats: yaml-strtab, bitstream."), 30 cl::init(cl::BOU_UNSET), cl::Hidden); 31 32RemarkStreamer::RemarkStreamer( 33 std::unique_ptr<remarks::RemarkSerializer> RemarkSerializer, 34 Optional<StringRef> FilenameIn) 35 : PassFilter(), RemarkSerializer(std::move(RemarkSerializer)), 36 Filename(FilenameIn ? Optional<std::string>(FilenameIn->str()) : None) {} 37 38Error RemarkStreamer::setFilter(StringRef Filter) { 39 Regex R = Regex(Filter); 40 std::string RegexError; 41 if (!R.isValid(RegexError)) 42 return createStringError(std::make_error_code(std::errc::invalid_argument), 43 RegexError.data()); 44 PassFilter = std::move(R); 45 return Error::success(); 46} 47 48/// DiagnosticKind -> remarks::Type 49static remarks::Type toRemarkType(enum DiagnosticKind Kind) { 50 switch (Kind) { 51 default: 52 return remarks::Type::Unknown; 53 case DK_OptimizationRemark: 54 case DK_MachineOptimizationRemark: 55 return remarks::Type::Passed; 56 case DK_OptimizationRemarkMissed: 57 case DK_MachineOptimizationRemarkMissed: 58 return remarks::Type::Missed; 59 case DK_OptimizationRemarkAnalysis: 60 case DK_MachineOptimizationRemarkAnalysis: 61 return remarks::Type::Analysis; 62 case DK_OptimizationRemarkAnalysisFPCommute: 63 return remarks::Type::AnalysisFPCommute; 64 case DK_OptimizationRemarkAnalysisAliasing: 65 return remarks::Type::AnalysisAliasing; 66 case DK_OptimizationFailure: 67 return remarks::Type::Failure; 68 } 69} 70 71/// DiagnosticLocation -> remarks::RemarkLocation. 72static Optional<remarks::RemarkLocation> 73toRemarkLocation(const DiagnosticLocation &DL) { 74 if (!DL.isValid()) 75 return None; 76 StringRef File = DL.getRelativePath(); 77 unsigned Line = DL.getLine(); 78 unsigned Col = DL.getColumn(); 79 return remarks::RemarkLocation{File, Line, Col}; 80} 81 82/// LLVM Diagnostic -> Remark 83remarks::Remark 84RemarkStreamer::toRemark(const DiagnosticInfoOptimizationBase &Diag) { 85 remarks::Remark R; // The result. 86 R.RemarkType = toRemarkType(static_cast<DiagnosticKind>(Diag.getKind())); 87 R.PassName = Diag.getPassName(); 88 R.RemarkName = Diag.getRemarkName(); 89 R.FunctionName = 90 GlobalValue::dropLLVMManglingEscape(Diag.getFunction().getName()); 91 R.Loc = toRemarkLocation(Diag.getLocation()); 92 R.Hotness = Diag.getHotness(); 93 94 for (const DiagnosticInfoOptimizationBase::Argument &Arg : Diag.getArgs()) { 95 R.Args.emplace_back(); 96 R.Args.back().Key = Arg.Key; 97 R.Args.back().Val = Arg.Val; 98 R.Args.back().Loc = toRemarkLocation(Arg.Loc); 99 } 100 101 return R; 102} 103 104void RemarkStreamer::emit(const DiagnosticInfoOptimizationBase &Diag) { 105 if (Optional<Regex> &Filter = PassFilter) 106 if (!Filter->match(Diag.getPassName())) 107 return; 108 109 // First, convert the diagnostic to a remark. 110 remarks::Remark R = toRemark(Diag); 111 // Then, emit the remark through the serializer. 112 RemarkSerializer->emit(R); 113} 114 115bool RemarkStreamer::needsSection() const { 116 if (EnableRemarksSection == cl::BOU_TRUE) 117 return true; 118 119 if (EnableRemarksSection == cl::BOU_FALSE) 120 return false; 121 122 assert(EnableRemarksSection == cl::BOU_UNSET); 123 124 // We only need a section if we're in separate mode. 125 if (RemarkSerializer->Mode != remarks::SerializerMode::Separate) 126 return false; 127 128 // Only some formats need a section: 129 // * bitstream 130 // * yaml-strtab 131 switch (RemarkSerializer->SerializerFormat) { 132 case remarks::Format::YAMLStrTab: 133 case remarks::Format::Bitstream: 134 return true; 135 default: 136 return false; 137 } 138} 139 140char RemarkSetupFileError::ID = 0; 141char RemarkSetupPatternError::ID = 0; 142char RemarkSetupFormatError::ID = 0; 143 144Expected<std::unique_ptr<ToolOutputFile>> 145llvm::setupOptimizationRemarks(LLVMContext &Context, StringRef RemarksFilename, 146 StringRef RemarksPasses, StringRef RemarksFormat, 147 bool RemarksWithHotness, 148 unsigned RemarksHotnessThreshold) { 149 if (RemarksWithHotness) 150 Context.setDiagnosticsHotnessRequested(true); 151 152 if (RemarksHotnessThreshold) 153 Context.setDiagnosticsHotnessThreshold(RemarksHotnessThreshold); 154 155 if (RemarksFilename.empty()) 156 return nullptr; 157 158 Expected<remarks::Format> Format = remarks::parseFormat(RemarksFormat); 159 if (Error E = Format.takeError()) 160 return make_error<RemarkSetupFormatError>(std::move(E)); 161 162 std::error_code EC; 163 auto Flags = *Format == remarks::Format::YAML ? sys::fs::OF_Text 164 : sys::fs::OF_None; 165 auto RemarksFile = 166 std::make_unique<ToolOutputFile>(RemarksFilename, EC, Flags); 167 // We don't use llvm::FileError here because some diagnostics want the file 168 // name separately. 169 if (EC) 170 return make_error<RemarkSetupFileError>(errorCodeToError(EC)); 171 172 Expected<std::unique_ptr<remarks::RemarkSerializer>> RemarkSerializer = 173 remarks::createRemarkSerializer( 174 *Format, remarks::SerializerMode::Separate, RemarksFile->os()); 175 if (Error E = RemarkSerializer.takeError()) 176 return make_error<RemarkSetupFormatError>(std::move(E)); 177 178 Context.setRemarkStreamer(std::make_unique<RemarkStreamer>( 179 std::move(*RemarkSerializer), RemarksFilename)); 180 181 if (!RemarksPasses.empty()) 182 if (Error E = Context.getRemarkStreamer()->setFilter(RemarksPasses)) 183 return make_error<RemarkSetupPatternError>(std::move(E)); 184 185 return std::move(RemarksFile); 186} 187 188Error llvm::setupOptimizationRemarks(LLVMContext &Context, raw_ostream &OS, 189 StringRef RemarksPasses, 190 StringRef RemarksFormat, 191 bool RemarksWithHotness, 192 unsigned RemarksHotnessThreshold) { 193 if (RemarksWithHotness) 194 Context.setDiagnosticsHotnessRequested(true); 195 196 if (RemarksHotnessThreshold) 197 Context.setDiagnosticsHotnessThreshold(RemarksHotnessThreshold); 198 199 Expected<remarks::Format> Format = remarks::parseFormat(RemarksFormat); 200 if (Error E = Format.takeError()) 201 return make_error<RemarkSetupFormatError>(std::move(E)); 202 203 Expected<std::unique_ptr<remarks::RemarkSerializer>> RemarkSerializer = 204 remarks::createRemarkSerializer(*Format, 205 remarks::SerializerMode::Separate, OS); 206 if (Error E = RemarkSerializer.takeError()) 207 return make_error<RemarkSetupFormatError>(std::move(E)); 208 209 Context.setRemarkStreamer( 210 std::make_unique<RemarkStreamer>(std::move(*RemarkSerializer))); 211 212 if (!RemarksPasses.empty()) 213 if (Error E = Context.getRemarkStreamer()->setFilter(RemarksPasses)) 214 return make_error<RemarkSetupPatternError>(std::move(E)); 215 216 return Error::success(); 217} 218