1//===- llvm/Support/DiagnosticInfo.cpp - Diagnostic Definitions -*- 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 defines the different classes involved in low level diagnostics.
10//
11// Diagnostics reporting is still done as part of the LLVMContext.
12//===----------------------------------------------------------------------===//
13
14#include "llvm/IR/DiagnosticInfo.h"
15#include "LLVMContextImpl.h"
16#include "llvm/ADT/StringExtras.h"
17#include "llvm/ADT/Twine.h"
18#include "llvm/ADT/iterator_range.h"
19#include "llvm/IR/BasicBlock.h"
20#include "llvm/IR/Constants.h"
21#include "llvm/IR/DebugInfoMetadata.h"
22#include "llvm/IR/DerivedTypes.h"
23#include "llvm/IR/DiagnosticPrinter.h"
24#include "llvm/IR/Function.h"
25#include "llvm/IR/GlobalValue.h"
26#include "llvm/IR/Instruction.h"
27#include "llvm/IR/LLVMContext.h"
28#include "llvm/IR/Metadata.h"
29#include "llvm/IR/Module.h"
30#include "llvm/IR/Type.h"
31#include "llvm/IR/Value.h"
32#include "llvm/Support/Casting.h"
33#include "llvm/Support/CommandLine.h"
34#include "llvm/Support/ErrorHandling.h"
35#include "llvm/Support/Path.h"
36#include "llvm/Support/Regex.h"
37#include "llvm/Support/ScopedPrinter.h"
38#include "llvm/Support/raw_ostream.h"
39#include <atomic>
40#include <cassert>
41#include <memory>
42#include <string>
43
44using namespace llvm;
45
46int llvm::getNextAvailablePluginDiagnosticKind() {
47  static std::atomic<int> PluginKindID(DK_FirstPluginKind);
48  return ++PluginKindID;
49}
50
51const char *OptimizationRemarkAnalysis::AlwaysPrint = "";
52
53DiagnosticInfoInlineAsm::DiagnosticInfoInlineAsm(const Instruction &I,
54                                                 const Twine &MsgStr,
55                                                 DiagnosticSeverity Severity)
56    : DiagnosticInfo(DK_InlineAsm, Severity), MsgStr(MsgStr), Instr(&I) {
57  if (const MDNode *SrcLoc = I.getMetadata("srcloc")) {
58    if (SrcLoc->getNumOperands() != 0)
59      if (const auto *CI =
60              mdconst::dyn_extract<ConstantInt>(SrcLoc->getOperand(0)))
61        LocCookie = CI->getZExtValue();
62  }
63}
64
65void DiagnosticInfoInlineAsm::print(DiagnosticPrinter &DP) const {
66  DP << getMsgStr();
67  if (getLocCookie())
68    DP << " at line " << getLocCookie();
69}
70
71void DiagnosticInfoResourceLimit::print(DiagnosticPrinter &DP) const {
72  DP << getResourceName() << " limit";
73
74  if (getResourceLimit() != 0)
75    DP << " of " << getResourceLimit();
76
77  DP << " exceeded (" <<  getResourceSize() << ") in " << getFunction();
78}
79
80void DiagnosticInfoDebugMetadataVersion::print(DiagnosticPrinter &DP) const {
81  DP << "ignoring debug info with an invalid version (" << getMetadataVersion()
82     << ") in " << getModule();
83}
84
85void DiagnosticInfoIgnoringInvalidDebugMetadata::print(
86    DiagnosticPrinter &DP) const {
87  DP << "ignoring invalid debug info in " << getModule().getModuleIdentifier();
88}
89
90void DiagnosticInfoSampleProfile::print(DiagnosticPrinter &DP) const {
91  if (!FileName.empty()) {
92    DP << getFileName();
93    if (LineNum > 0)
94      DP << ":" << getLineNum();
95    DP << ": ";
96  }
97  DP << getMsg();
98}
99
100void DiagnosticInfoPGOProfile::print(DiagnosticPrinter &DP) const {
101  if (getFileName())
102    DP << getFileName() << ": ";
103  DP << getMsg();
104}
105
106void DiagnosticInfo::anchor() {}
107void DiagnosticInfoStackSize::anchor() {}
108void DiagnosticInfoWithLocationBase::anchor() {}
109void DiagnosticInfoIROptimization::anchor() {}
110
111DiagnosticLocation::DiagnosticLocation(const DebugLoc &DL) {
112  if (!DL)
113    return;
114  File = DL->getFile();
115  Line = DL->getLine();
116  Column = DL->getColumn();
117}
118
119DiagnosticLocation::DiagnosticLocation(const DISubprogram *SP) {
120  if (!SP)
121    return;
122
123  File = SP->getFile();
124  Line = SP->getScopeLine();
125  Column = 0;
126}
127
128StringRef DiagnosticLocation::getRelativePath() const {
129  return File->getFilename();
130}
131
132std::string DiagnosticLocation::getAbsolutePath() const {
133  StringRef Name = File->getFilename();
134  if (sys::path::is_absolute(Name))
135    return Name;
136
137  SmallString<128> Path;
138  sys::path::append(Path, File->getDirectory(), Name);
139  return sys::path::remove_leading_dotslash(Path).str();
140}
141
142std::string DiagnosticInfoWithLocationBase::getAbsolutePath() const {
143  return Loc.getAbsolutePath();
144}
145
146void DiagnosticInfoWithLocationBase::getLocation(StringRef &RelativePath,
147                                                 unsigned &Line,
148                                                 unsigned &Column) const {
149  RelativePath = Loc.getRelativePath();
150  Line = Loc.getLine();
151  Column = Loc.getColumn();
152}
153
154const std::string DiagnosticInfoWithLocationBase::getLocationStr() const {
155  StringRef Filename("<unknown>");
156  unsigned Line = 0;
157  unsigned Column = 0;
158  if (isLocationAvailable())
159    getLocation(Filename, Line, Column);
160  return (Filename + ":" + Twine(Line) + ":" + Twine(Column)).str();
161}
162
163DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, const Value *V)
164    : Key(Key) {
165  if (auto *F = dyn_cast<Function>(V)) {
166    if (DISubprogram *SP = F->getSubprogram())
167      Loc = SP;
168  }
169  else if (auto *I = dyn_cast<Instruction>(V))
170    Loc = I->getDebugLoc();
171
172  // Only include names that correspond to user variables.  FIXME: We should use
173  // debug info if available to get the name of the user variable.
174  if (isa<llvm::Argument>(V) || isa<GlobalValue>(V))
175    Val = GlobalValue::dropLLVMManglingEscape(V->getName());
176  else if (isa<Constant>(V)) {
177    raw_string_ostream OS(Val);
178    V->printAsOperand(OS, /*PrintType=*/false);
179  } else if (auto *I = dyn_cast<Instruction>(V))
180    Val = I->getOpcodeName();
181}
182
183DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, const Type *T)
184    : Key(Key) {
185  raw_string_ostream OS(Val);
186  OS << *T;
187}
188
189DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, StringRef S)
190    : Key(Key), Val(S.str()) {}
191
192DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, int N)
193    : Key(Key), Val(itostr(N)) {}
194
195DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, float N)
196    : Key(Key), Val(llvm::to_string(N)) {}
197
198DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, long N)
199    : Key(Key), Val(itostr(N)) {}
200
201DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, long long N)
202    : Key(Key), Val(itostr(N)) {}
203
204DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, unsigned N)
205    : Key(Key), Val(utostr(N)) {}
206
207DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key,
208                                                   unsigned long N)
209    : Key(Key), Val(utostr(N)) {}
210
211DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key,
212                                                   unsigned long long N)
213    : Key(Key), Val(utostr(N)) {}
214
215DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, DebugLoc Loc)
216    : Key(Key), Loc(Loc) {
217  if (Loc) {
218    Val = (Loc->getFilename() + ":" + Twine(Loc.getLine()) + ":" +
219           Twine(Loc.getCol())).str();
220  } else {
221    Val = "<UNKNOWN LOCATION>";
222  }
223}
224
225void DiagnosticInfoOptimizationBase::print(DiagnosticPrinter &DP) const {
226  DP << getLocationStr() << ": " << getMsg();
227  if (Hotness)
228    DP << " (hotness: " << *Hotness << ")";
229}
230
231OptimizationRemark::OptimizationRemark(const char *PassName,
232                                       StringRef RemarkName,
233                                       const DiagnosticLocation &Loc,
234                                       const Value *CodeRegion)
235    : DiagnosticInfoIROptimization(
236          DK_OptimizationRemark, DS_Remark, PassName, RemarkName,
237          *cast<BasicBlock>(CodeRegion)->getParent(), Loc, CodeRegion) {}
238
239OptimizationRemark::OptimizationRemark(const char *PassName,
240                                       StringRef RemarkName,
241                                       const Instruction *Inst)
242    : DiagnosticInfoIROptimization(DK_OptimizationRemark, DS_Remark, PassName,
243                                   RemarkName, *Inst->getParent()->getParent(),
244                                   Inst->getDebugLoc(), Inst->getParent()) {}
245
246// Helper to allow for an assert before attempting to return an invalid
247// reference.
248static const BasicBlock &getFirstFunctionBlock(const Function *Func) {
249  assert(!Func->empty() && "Function does not have a body");
250  return Func->front();
251}
252
253OptimizationRemark::OptimizationRemark(const char *PassName,
254                                       StringRef RemarkName,
255                                       const Function *Func)
256    : DiagnosticInfoIROptimization(DK_OptimizationRemark, DS_Remark, PassName,
257                                   RemarkName, *Func, Func->getSubprogram(),
258                                   &getFirstFunctionBlock(Func)) {}
259
260bool OptimizationRemark::isEnabled() const {
261  const Function &Fn = getFunction();
262  LLVMContext &Ctx = Fn.getContext();
263  return Ctx.getDiagHandlerPtr()->isPassedOptRemarkEnabled(getPassName());
264}
265
266OptimizationRemarkMissed::OptimizationRemarkMissed(
267    const char *PassName, StringRef RemarkName, const DiagnosticLocation &Loc,
268    const Value *CodeRegion)
269    : DiagnosticInfoIROptimization(
270          DK_OptimizationRemarkMissed, DS_Remark, PassName, RemarkName,
271          *cast<BasicBlock>(CodeRegion)->getParent(), Loc, CodeRegion) {}
272
273OptimizationRemarkMissed::OptimizationRemarkMissed(const char *PassName,
274                                                   StringRef RemarkName,
275                                                   const Instruction *Inst)
276    : DiagnosticInfoIROptimization(DK_OptimizationRemarkMissed, DS_Remark,
277                                   PassName, RemarkName,
278                                   *Inst->getParent()->getParent(),
279                                   Inst->getDebugLoc(), Inst->getParent()) {}
280
281bool OptimizationRemarkMissed::isEnabled() const {
282  const Function &Fn = getFunction();
283  LLVMContext &Ctx = Fn.getContext();
284  return Ctx.getDiagHandlerPtr()->isMissedOptRemarkEnabled(getPassName());
285}
286
287OptimizationRemarkAnalysis::OptimizationRemarkAnalysis(
288    const char *PassName, StringRef RemarkName, const DiagnosticLocation &Loc,
289    const Value *CodeRegion)
290    : DiagnosticInfoIROptimization(
291          DK_OptimizationRemarkAnalysis, DS_Remark, PassName, RemarkName,
292          *cast<BasicBlock>(CodeRegion)->getParent(), Loc, CodeRegion) {}
293
294OptimizationRemarkAnalysis::OptimizationRemarkAnalysis(const char *PassName,
295                                                       StringRef RemarkName,
296                                                       const Instruction *Inst)
297    : DiagnosticInfoIROptimization(DK_OptimizationRemarkAnalysis, DS_Remark,
298                                   PassName, RemarkName,
299                                   *Inst->getParent()->getParent(),
300                                   Inst->getDebugLoc(), Inst->getParent()) {}
301
302OptimizationRemarkAnalysis::OptimizationRemarkAnalysis(
303    enum DiagnosticKind Kind, const char *PassName, StringRef RemarkName,
304    const DiagnosticLocation &Loc, const Value *CodeRegion)
305    : DiagnosticInfoIROptimization(Kind, DS_Remark, PassName, RemarkName,
306                                   *cast<BasicBlock>(CodeRegion)->getParent(),
307                                   Loc, CodeRegion) {}
308
309bool OptimizationRemarkAnalysis::isEnabled() const {
310  const Function &Fn = getFunction();
311  LLVMContext &Ctx = Fn.getContext();
312  return Ctx.getDiagHandlerPtr()->isAnalysisRemarkEnabled(getPassName()) ||
313         shouldAlwaysPrint();
314}
315
316void DiagnosticInfoMIRParser::print(DiagnosticPrinter &DP) const {
317  DP << Diagnostic;
318}
319
320DiagnosticInfoOptimizationFailure::DiagnosticInfoOptimizationFailure(
321    const char *PassName, StringRef RemarkName, const DiagnosticLocation &Loc,
322    const Value *CodeRegion)
323    : DiagnosticInfoIROptimization(
324          DK_OptimizationFailure, DS_Warning, PassName, RemarkName,
325          *cast<BasicBlock>(CodeRegion)->getParent(), Loc, CodeRegion) {}
326
327bool DiagnosticInfoOptimizationFailure::isEnabled() const {
328  // Only print warnings.
329  return getSeverity() == DS_Warning;
330}
331
332void DiagnosticInfoUnsupported::print(DiagnosticPrinter &DP) const {
333  std::string Str;
334  raw_string_ostream OS(Str);
335
336  OS << getLocationStr() << ": in function " << getFunction().getName() << ' '
337     << *getFunction().getFunctionType() << ": " << Msg << '\n';
338  OS.flush();
339  DP << Str;
340}
341
342void DiagnosticInfoISelFallback::print(DiagnosticPrinter &DP) const {
343  DP << "Instruction selection used fallback path for " << getFunction();
344}
345
346void DiagnosticInfoOptimizationBase::insert(StringRef S) {
347  Args.emplace_back(S);
348}
349
350void DiagnosticInfoOptimizationBase::insert(Argument A) {
351  Args.push_back(std::move(A));
352}
353
354void DiagnosticInfoOptimizationBase::insert(setIsVerbose V) {
355  IsVerbose = true;
356}
357
358void DiagnosticInfoOptimizationBase::insert(setExtraArgs EA) {
359  FirstExtraArgIndex = Args.size();
360}
361
362std::string DiagnosticInfoOptimizationBase::getMsg() const {
363  std::string Str;
364  raw_string_ostream OS(Str);
365  for (const DiagnosticInfoOptimizationBase::Argument &Arg :
366       make_range(Args.begin(), FirstExtraArgIndex == -1
367                                    ? Args.end()
368                                    : Args.begin() + FirstExtraArgIndex))
369    OS << Arg.Val;
370  return OS.str();
371}
372
373DiagnosticInfoMisExpect::DiagnosticInfoMisExpect(const Instruction *Inst,
374                                                 Twine &Msg)
375    : DiagnosticInfoWithLocationBase(DK_MisExpect, DS_Warning,
376                                     *Inst->getParent()->getParent(),
377                                     Inst->getDebugLoc()),
378      Msg(Msg) {}
379
380void DiagnosticInfoMisExpect::print(DiagnosticPrinter &DP) const {
381  DP << getLocationStr() << ": " << getMsg();
382}
383
384void OptimizationRemarkAnalysisFPCommute::anchor() {}
385void OptimizationRemarkAnalysisAliasing::anchor() {}
386