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