]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/llvm/lib/IR/RemarkStreamer.cpp
MFC r355940:
[FreeBSD/FreeBSD.git] / contrib / llvm-project / llvm / lib / IR / RemarkStreamer.cpp
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/RemarkFormat.h"
19
20 using namespace llvm;
21
22 RemarkStreamer::RemarkStreamer(StringRef Filename,
23                                std::unique_ptr<remarks::Serializer> Serializer)
24     : Filename(Filename), PassFilter(), Serializer(std::move(Serializer)) {
25   assert(!Filename.empty() && "This needs to be a real filename.");
26 }
27
28 Error RemarkStreamer::setFilter(StringRef Filter) {
29   Regex R = Regex(Filter);
30   std::string RegexError;
31   if (!R.isValid(RegexError))
32     return createStringError(std::make_error_code(std::errc::invalid_argument),
33                              RegexError.data());
34   PassFilter = std::move(R);
35   return Error::success();
36 }
37
38 /// DiagnosticKind -> remarks::Type
39 static remarks::Type toRemarkType(enum DiagnosticKind Kind) {
40   switch (Kind) {
41   default:
42     return remarks::Type::Unknown;
43   case DK_OptimizationRemark:
44   case DK_MachineOptimizationRemark:
45     return remarks::Type::Passed;
46   case DK_OptimizationRemarkMissed:
47   case DK_MachineOptimizationRemarkMissed:
48     return remarks::Type::Missed;
49   case DK_OptimizationRemarkAnalysis:
50   case DK_MachineOptimizationRemarkAnalysis:
51     return remarks::Type::Analysis;
52   case DK_OptimizationRemarkAnalysisFPCommute:
53     return remarks::Type::AnalysisFPCommute;
54   case DK_OptimizationRemarkAnalysisAliasing:
55     return remarks::Type::AnalysisAliasing;
56   case DK_OptimizationFailure:
57     return remarks::Type::Failure;
58   }
59 }
60
61 /// DiagnosticLocation -> remarks::RemarkLocation.
62 static Optional<remarks::RemarkLocation>
63 toRemarkLocation(const DiagnosticLocation &DL) {
64   if (!DL.isValid())
65     return None;
66   StringRef File = DL.getRelativePath();
67   unsigned Line = DL.getLine();
68   unsigned Col = DL.getColumn();
69   return remarks::RemarkLocation{File, Line, Col};
70 }
71
72 /// LLVM Diagnostic -> Remark
73 remarks::Remark
74 RemarkStreamer::toRemark(const DiagnosticInfoOptimizationBase &Diag) {
75   remarks::Remark R; // The result.
76   R.RemarkType = toRemarkType(static_cast<DiagnosticKind>(Diag.getKind()));
77   R.PassName = Diag.getPassName();
78   R.RemarkName = Diag.getRemarkName();
79   R.FunctionName =
80       GlobalValue::dropLLVMManglingEscape(Diag.getFunction().getName());
81   R.Loc = toRemarkLocation(Diag.getLocation());
82   R.Hotness = Diag.getHotness();
83
84   for (const DiagnosticInfoOptimizationBase::Argument &Arg : Diag.getArgs()) {
85     R.Args.emplace_back();
86     R.Args.back().Key = Arg.Key;
87     R.Args.back().Val = Arg.Val;
88     R.Args.back().Loc = toRemarkLocation(Arg.Loc);
89   }
90
91   return R;
92 }
93
94 void RemarkStreamer::emit(const DiagnosticInfoOptimizationBase &Diag) {
95   if (Optional<Regex> &Filter = PassFilter)
96     if (!Filter->match(Diag.getPassName()))
97       return;
98
99   // First, convert the diagnostic to a remark.
100   remarks::Remark R = toRemark(Diag);
101   // Then, emit the remark through the serializer.
102   Serializer->emit(R);
103 }
104
105 char RemarkSetupFileError::ID = 0;
106 char RemarkSetupPatternError::ID = 0;
107 char RemarkSetupFormatError::ID = 0;
108
109 static std::unique_ptr<remarks::Serializer>
110 formatToSerializer(remarks::Format RemarksFormat, raw_ostream &OS) {
111   switch (RemarksFormat) {
112   default:
113     llvm_unreachable("Unknown remark serializer format.");
114     return nullptr;
115   case remarks::Format::YAML:
116     return llvm::make_unique<remarks::YAMLSerializer>(OS);
117   };
118 }
119
120 Expected<std::unique_ptr<ToolOutputFile>>
121 llvm::setupOptimizationRemarks(LLVMContext &Context, StringRef RemarksFilename,
122                                StringRef RemarksPasses, StringRef RemarksFormat,
123                                bool RemarksWithHotness,
124                                unsigned RemarksHotnessThreshold) {
125   if (RemarksWithHotness)
126     Context.setDiagnosticsHotnessRequested(true);
127
128   if (RemarksHotnessThreshold)
129     Context.setDiagnosticsHotnessThreshold(RemarksHotnessThreshold);
130
131   if (RemarksFilename.empty())
132     return nullptr;
133
134   std::error_code EC;
135   auto RemarksFile =
136       llvm::make_unique<ToolOutputFile>(RemarksFilename, EC, sys::fs::F_None);
137   // We don't use llvm::FileError here because some diagnostics want the file
138   // name separately.
139   if (EC)
140     return make_error<RemarkSetupFileError>(errorCodeToError(EC));
141
142   Expected<remarks::Format> Format = remarks::parseFormat(RemarksFormat);
143   if (Error E = Format.takeError())
144     return make_error<RemarkSetupFormatError>(std::move(E));
145
146   Context.setRemarkStreamer(llvm::make_unique<RemarkStreamer>(
147       RemarksFilename, formatToSerializer(*Format, RemarksFile->os())));
148
149   if (!RemarksPasses.empty())
150     if (Error E = Context.getRemarkStreamer()->setFilter(RemarksPasses))
151       return make_error<RemarkSetupPatternError>(std::move(E));
152
153   return std::move(RemarksFile);
154 }