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