1//===- llvm/IR/LLVMRemarkStreamer.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 conversion between IR
10// Diagnostics and serializable remarks::Remark objects.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm/IR/LLVMRemarkStreamer.h"
15#include "llvm/IR/DiagnosticInfo.h"
16#include "llvm/IR/Function.h"
17#include "llvm/IR/GlobalValue.h"
18#include "llvm/Support/FileSystem.h"
19
20using namespace llvm;
21
22/// DiagnosticKind -> remarks::Type
23static remarks::Type toRemarkType(enum DiagnosticKind Kind) {
24  switch (Kind) {
25  default:
26    return remarks::Type::Unknown;
27  case DK_OptimizationRemark:
28  case DK_MachineOptimizationRemark:
29    return remarks::Type::Passed;
30  case DK_OptimizationRemarkMissed:
31  case DK_MachineOptimizationRemarkMissed:
32    return remarks::Type::Missed;
33  case DK_OptimizationRemarkAnalysis:
34  case DK_MachineOptimizationRemarkAnalysis:
35    return remarks::Type::Analysis;
36  case DK_OptimizationRemarkAnalysisFPCommute:
37    return remarks::Type::AnalysisFPCommute;
38  case DK_OptimizationRemarkAnalysisAliasing:
39    return remarks::Type::AnalysisAliasing;
40  case DK_OptimizationFailure:
41    return remarks::Type::Failure;
42  }
43}
44
45/// DiagnosticLocation -> remarks::RemarkLocation.
46static Optional<remarks::RemarkLocation>
47toRemarkLocation(const DiagnosticLocation &DL) {
48  if (!DL.isValid())
49    return None;
50  StringRef File = DL.getRelativePath();
51  unsigned Line = DL.getLine();
52  unsigned Col = DL.getColumn();
53  return remarks::RemarkLocation{File, Line, Col};
54}
55
56/// LLVM Diagnostic -> Remark
57remarks::Remark
58LLVMRemarkStreamer::toRemark(const DiagnosticInfoOptimizationBase &Diag) const {
59  remarks::Remark R; // The result.
60  R.RemarkType = toRemarkType(static_cast<DiagnosticKind>(Diag.getKind()));
61  R.PassName = Diag.getPassName();
62  R.RemarkName = Diag.getRemarkName();
63  R.FunctionName =
64      GlobalValue::dropLLVMManglingEscape(Diag.getFunction().getName());
65  R.Loc = toRemarkLocation(Diag.getLocation());
66  R.Hotness = Diag.getHotness();
67
68  for (const DiagnosticInfoOptimizationBase::Argument &Arg : Diag.getArgs()) {
69    R.Args.emplace_back();
70    R.Args.back().Key = Arg.Key;
71    R.Args.back().Val = Arg.Val;
72    R.Args.back().Loc = toRemarkLocation(Arg.Loc);
73  }
74
75  return R;
76}
77
78void LLVMRemarkStreamer::emit(const DiagnosticInfoOptimizationBase &Diag) {
79  if (!RS.matchesFilter(Diag.getPassName()))
80      return;
81
82  // First, convert the diagnostic to a remark.
83  remarks::Remark R = toRemark(Diag);
84  // Then, emit the remark through the serializer.
85  RS.getSerializer().emit(R);
86}
87
88char LLVMRemarkSetupFileError::ID = 0;
89char LLVMRemarkSetupPatternError::ID = 0;
90char LLVMRemarkSetupFormatError::ID = 0;
91
92Expected<std::unique_ptr<ToolOutputFile>> llvm::setupLLVMOptimizationRemarks(
93    LLVMContext &Context, StringRef RemarksFilename, StringRef RemarksPasses,
94    StringRef RemarksFormat, bool RemarksWithHotness,
95    unsigned RemarksHotnessThreshold) {
96  if (RemarksWithHotness)
97    Context.setDiagnosticsHotnessRequested(true);
98
99  if (RemarksHotnessThreshold)
100    Context.setDiagnosticsHotnessThreshold(RemarksHotnessThreshold);
101
102  if (RemarksFilename.empty())
103    return nullptr;
104
105  Expected<remarks::Format> Format = remarks::parseFormat(RemarksFormat);
106  if (Error E = Format.takeError())
107    return make_error<LLVMRemarkSetupFormatError>(std::move(E));
108
109  std::error_code EC;
110  auto Flags = *Format == remarks::Format::YAML ? sys::fs::OF_Text
111                                                : sys::fs::OF_None;
112  auto RemarksFile =
113      std::make_unique<ToolOutputFile>(RemarksFilename, EC, Flags);
114  // We don't use llvm::FileError here because some diagnostics want the file
115  // name separately.
116  if (EC)
117    return make_error<LLVMRemarkSetupFileError>(errorCodeToError(EC));
118
119  Expected<std::unique_ptr<remarks::RemarkSerializer>> RemarkSerializer =
120      remarks::createRemarkSerializer(
121          *Format, remarks::SerializerMode::Separate, RemarksFile->os());
122  if (Error E = RemarkSerializer.takeError())
123    return make_error<LLVMRemarkSetupFormatError>(std::move(E));
124
125  // Create the main remark streamer.
126  Context.setMainRemarkStreamer(std::make_unique<remarks::RemarkStreamer>(
127      std::move(*RemarkSerializer), RemarksFilename));
128
129  // Create LLVM's optimization remarks streamer.
130  Context.setLLVMRemarkStreamer(
131      std::make_unique<LLVMRemarkStreamer>(*Context.getMainRemarkStreamer()));
132
133  if (!RemarksPasses.empty())
134    if (Error E = Context.getMainRemarkStreamer()->setFilter(RemarksPasses))
135      return make_error<LLVMRemarkSetupPatternError>(std::move(E));
136
137  return std::move(RemarksFile);
138}
139
140Error llvm::setupLLVMOptimizationRemarks(LLVMContext &Context, raw_ostream &OS,
141                                         StringRef RemarksPasses,
142                                         StringRef RemarksFormat,
143                                         bool RemarksWithHotness,
144                                         unsigned RemarksHotnessThreshold) {
145  if (RemarksWithHotness)
146    Context.setDiagnosticsHotnessRequested(true);
147
148  if (RemarksHotnessThreshold)
149    Context.setDiagnosticsHotnessThreshold(RemarksHotnessThreshold);
150
151  Expected<remarks::Format> Format = remarks::parseFormat(RemarksFormat);
152  if (Error E = Format.takeError())
153    return make_error<LLVMRemarkSetupFormatError>(std::move(E));
154
155  Expected<std::unique_ptr<remarks::RemarkSerializer>> RemarkSerializer =
156      remarks::createRemarkSerializer(*Format,
157                                      remarks::SerializerMode::Separate, OS);
158  if (Error E = RemarkSerializer.takeError())
159    return make_error<LLVMRemarkSetupFormatError>(std::move(E));
160
161  // Create the main remark streamer.
162  Context.setMainRemarkStreamer(
163      std::make_unique<remarks::RemarkStreamer>(std::move(*RemarkSerializer)));
164
165  // Create LLVM's optimization remarks streamer.
166  Context.setLLVMRemarkStreamer(
167      std::make_unique<LLVMRemarkStreamer>(*Context.getMainRemarkStreamer()));
168
169  if (!RemarksPasses.empty())
170    if (Error E = Context.getMainRemarkStreamer()->setFilter(RemarksPasses))
171      return make_error<LLVMRemarkSetupPatternError>(std::move(E));
172
173  return Error::success();
174}
175