1 | //===- llvm/IR/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 "llvm/ADT/StringExtras.h" |
16 | #include "llvm/ADT/Twine.h" |
17 | #include "llvm/ADT/iterator_range.h" |
18 | #include "llvm/Demangle/Demangle.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/Instructions.h" |
28 | #include "llvm/IR/IntrinsicInst.h" |
29 | #include "llvm/IR/LLVMContext.h" |
30 | #include "llvm/IR/Metadata.h" |
31 | #include "llvm/IR/Module.h" |
32 | #include "llvm/IR/Type.h" |
33 | #include "llvm/IR/Value.h" |
34 | #include "llvm/Support/Casting.h" |
35 | #include "llvm/Support/ErrorHandling.h" |
36 | #include "llvm/Support/InstructionCost.h" |
37 | #include "llvm/Support/Path.h" |
38 | #include "llvm/Support/ScopedPrinter.h" |
39 | #include "llvm/Support/raw_ostream.h" |
40 | #include <atomic> |
41 | #include <string> |
42 | |
43 | using namespace llvm; |
44 | |
45 | int llvm::getNextAvailablePluginDiagnosticKind() { |
46 | static std::atomic<int> PluginKindID(DK_FirstPluginKind); |
47 | return ++PluginKindID; |
48 | } |
49 | |
50 | const char *OptimizationRemarkAnalysis:: = "" ; |
51 | |
52 | void DiagnosticInfoGeneric::print(DiagnosticPrinter &DP) const { |
53 | DP << getMsgStr(); |
54 | } |
55 | |
56 | void DiagnosticInfoGenericWithLoc::print(DiagnosticPrinter &DP) const { |
57 | DP << getLocationStr() << ": " << getMsgStr(); |
58 | } |
59 | |
60 | DiagnosticInfoInlineAsm::DiagnosticInfoInlineAsm(uint64_t LocCookie, |
61 | const Twine &MsgStr, |
62 | DiagnosticSeverity Severity) |
63 | : DiagnosticInfo(DK_InlineAsm, Severity), LocCookie(LocCookie), |
64 | MsgStr(MsgStr) {} |
65 | |
66 | DiagnosticInfoInlineAsm::DiagnosticInfoInlineAsm(const Instruction &I, |
67 | const Twine &MsgStr, |
68 | DiagnosticSeverity Severity) |
69 | : DiagnosticInfo(DK_InlineAsm, Severity), MsgStr(MsgStr), Instr(&I) { |
70 | if (const MDNode *SrcLoc = I.getMetadata(Kind: "srcloc" )) { |
71 | if (SrcLoc->getNumOperands() != 0) |
72 | if (const auto *CI = |
73 | mdconst::dyn_extract<ConstantInt>(MD: SrcLoc->getOperand(I: 0))) |
74 | LocCookie = CI->getZExtValue(); |
75 | } |
76 | } |
77 | |
78 | void DiagnosticInfoInlineAsm::print(DiagnosticPrinter &DP) const { |
79 | DP << getMsgStr(); |
80 | if (getLocCookie()) |
81 | DP << " at line " << getLocCookie(); |
82 | } |
83 | |
84 | DiagnosticInfoRegAllocFailure::DiagnosticInfoRegAllocFailure( |
85 | const Twine &MsgStr, const Function &Fn, const DiagnosticLocation &DL, |
86 | DiagnosticSeverity Severity) |
87 | : DiagnosticInfoWithLocationBase(DK_RegAllocFailure, Severity, Fn, |
88 | DL.isValid() ? DL : Fn.getSubprogram()), |
89 | MsgStr(MsgStr) {} |
90 | |
91 | DiagnosticInfoRegAllocFailure::DiagnosticInfoRegAllocFailure( |
92 | const Twine &MsgStr, const Function &Fn, DiagnosticSeverity Severity) |
93 | : DiagnosticInfoWithLocationBase(DK_RegAllocFailure, Severity, Fn, |
94 | Fn.getSubprogram()), |
95 | MsgStr(MsgStr) {} |
96 | |
97 | void DiagnosticInfoRegAllocFailure::print(DiagnosticPrinter &DP) const { |
98 | DP << getLocationStr() << ": " << MsgStr << " in function '" << getFunction() |
99 | << '\''; |
100 | } |
101 | |
102 | DiagnosticInfoResourceLimit::DiagnosticInfoResourceLimit( |
103 | const Function &Fn, const char *ResourceName, uint64_t ResourceSize, |
104 | uint64_t ResourceLimit, DiagnosticSeverity Severity, DiagnosticKind Kind) |
105 | : DiagnosticInfoWithLocationBase(Kind, Severity, Fn, Fn.getSubprogram()), |
106 | Fn(Fn), ResourceName(ResourceName), ResourceSize(ResourceSize), |
107 | ResourceLimit(ResourceLimit) {} |
108 | |
109 | void DiagnosticInfoResourceLimit::print(DiagnosticPrinter &DP) const { |
110 | DP << getLocationStr() << ": " << getResourceName() << " (" |
111 | << getResourceSize() << ") exceeds limit (" << getResourceLimit() |
112 | << ") in function '" << getFunction() << '\''; |
113 | } |
114 | |
115 | void DiagnosticInfoDebugMetadataVersion::print(DiagnosticPrinter &DP) const { |
116 | DP << "ignoring debug info with an invalid version (" << getMetadataVersion() |
117 | << ") in " << getModule(); |
118 | } |
119 | |
120 | void DiagnosticInfoIgnoringInvalidDebugMetadata::print( |
121 | DiagnosticPrinter &DP) const { |
122 | DP << "ignoring invalid debug info in " << getModule().getModuleIdentifier(); |
123 | } |
124 | |
125 | void DiagnosticInfoSampleProfile::print(DiagnosticPrinter &DP) const { |
126 | if (!FileName.empty()) { |
127 | DP << getFileName(); |
128 | if (LineNum > 0) |
129 | DP << ":" << getLineNum(); |
130 | DP << ": " ; |
131 | } |
132 | DP << getMsg(); |
133 | } |
134 | |
135 | void DiagnosticInfoPGOProfile::print(DiagnosticPrinter &DP) const { |
136 | if (getFileName()) |
137 | DP << getFileName() << ": " ; |
138 | DP << getMsg(); |
139 | } |
140 | |
141 | void DiagnosticInfo::anchor() {} |
142 | void DiagnosticInfoStackSize::anchor() {} |
143 | void DiagnosticInfoWithLocationBase::anchor() {} |
144 | void DiagnosticInfoIROptimization::anchor() {} |
145 | |
146 | DiagnosticLocation::DiagnosticLocation(const DebugLoc &DL) { |
147 | if (!DL) |
148 | return; |
149 | File = DL->getFile(); |
150 | Line = DL->getLine(); |
151 | Column = DL->getColumn(); |
152 | } |
153 | |
154 | DiagnosticLocation::DiagnosticLocation(const DISubprogram *SP) { |
155 | if (!SP) |
156 | return; |
157 | |
158 | File = SP->getFile(); |
159 | Line = SP->getScopeLine(); |
160 | Column = 0; |
161 | } |
162 | |
163 | StringRef DiagnosticLocation::getRelativePath() const { |
164 | return File->getFilename(); |
165 | } |
166 | |
167 | std::string DiagnosticLocation::getAbsolutePath() const { |
168 | StringRef Name = File->getFilename(); |
169 | if (sys::path::is_absolute(path: Name)) |
170 | return std::string(Name); |
171 | |
172 | SmallString<128> Path; |
173 | sys::path::append(path&: Path, a: File->getDirectory(), b: Name); |
174 | return sys::path::remove_leading_dotslash(path: Path).str(); |
175 | } |
176 | |
177 | std::string DiagnosticInfoWithLocationBase::getAbsolutePath() const { |
178 | return Loc.getAbsolutePath(); |
179 | } |
180 | |
181 | void DiagnosticInfoWithLocationBase::getLocation(StringRef &RelativePath, |
182 | unsigned &Line, |
183 | unsigned &Column) const { |
184 | RelativePath = Loc.getRelativePath(); |
185 | Line = Loc.getLine(); |
186 | Column = Loc.getColumn(); |
187 | } |
188 | |
189 | std::string DiagnosticInfoWithLocationBase::getLocationStr() const { |
190 | StringRef Filename("<unknown>" ); |
191 | unsigned Line = 0; |
192 | unsigned Column = 0; |
193 | if (isLocationAvailable()) |
194 | getLocation(RelativePath&: Filename, Line, Column); |
195 | return (Filename + ":" + Twine(Line) + ":" + Twine(Column)).str(); |
196 | } |
197 | |
198 | DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, |
199 | const Value *V) |
200 | : Key(std::string(Key)) { |
201 | if (auto *F = dyn_cast<Function>(Val: V)) { |
202 | if (DISubprogram *SP = F->getSubprogram()) |
203 | Loc = SP; |
204 | } |
205 | else if (auto *I = dyn_cast<Instruction>(Val: V)) |
206 | Loc = I->getDebugLoc(); |
207 | |
208 | // Only include names that correspond to user variables. FIXME: We should use |
209 | // debug info if available to get the name of the user variable. |
210 | if (isa<llvm::Argument>(Val: V) || isa<GlobalValue>(Val: V)) |
211 | Val = std::string(GlobalValue::dropLLVMManglingEscape(Name: V->getName())); |
212 | else if (isa<Constant>(Val: V)) { |
213 | raw_string_ostream OS(Val); |
214 | V->printAsOperand(O&: OS, /*PrintType=*/false); |
215 | } else if (auto *II = dyn_cast<IntrinsicInst>(Val: V)) { |
216 | raw_string_ostream OS(Val); |
217 | OS << "call " << II->getCalledFunction()->getName(); |
218 | } else if (auto *I = dyn_cast<Instruction>(Val: V)) { |
219 | Val = I->getOpcodeName(); |
220 | } else if (auto *MD = dyn_cast<MetadataAsValue>(Val: V)) { |
221 | if (auto *S = dyn_cast<MDString>(Val: MD->getMetadata())) |
222 | Val = S->getString(); |
223 | } |
224 | } |
225 | |
226 | DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, const Type *T) |
227 | : Key(std::string(Key)) { |
228 | raw_string_ostream OS(Val); |
229 | OS << *T; |
230 | } |
231 | |
232 | DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, StringRef S) |
233 | : Key(std::string(Key)), Val(S.str()) {} |
234 | |
235 | DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, int N) |
236 | : Key(std::string(Key)), Val(itostr(X: N)) {} |
237 | |
238 | DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, float N) |
239 | : Key(std::string(Key)), Val(llvm::to_string(Value: N)) {} |
240 | |
241 | DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, long N) |
242 | : Key(std::string(Key)), Val(itostr(X: N)) {} |
243 | |
244 | DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, long long N) |
245 | : Key(std::string(Key)), Val(itostr(X: N)) {} |
246 | |
247 | DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, unsigned N) |
248 | : Key(std::string(Key)), Val(utostr(X: N)) {} |
249 | |
250 | DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, |
251 | unsigned long N) |
252 | : Key(std::string(Key)), Val(utostr(X: N)) {} |
253 | |
254 | DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, |
255 | unsigned long long N) |
256 | : Key(std::string(Key)), Val(utostr(X: N)) {} |
257 | |
258 | DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, |
259 | ElementCount EC) |
260 | : Key(std::string(Key)) { |
261 | raw_string_ostream OS(Val); |
262 | EC.print(OS); |
263 | } |
264 | |
265 | DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, |
266 | InstructionCost C) |
267 | : Key(std::string(Key)) { |
268 | raw_string_ostream OS(Val); |
269 | C.print(OS); |
270 | } |
271 | |
272 | DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, DebugLoc Loc) |
273 | : Key(std::string(Key)), Loc(Loc) { |
274 | if (Loc) { |
275 | Val = (Loc->getFilename() + ":" + Twine(Loc.getLine()) + ":" + |
276 | Twine(Loc.getCol())).str(); |
277 | } else { |
278 | Val = "<UNKNOWN LOCATION>" ; |
279 | } |
280 | } |
281 | |
282 | void DiagnosticInfoOptimizationBase::print(DiagnosticPrinter &DP) const { |
283 | DP << getLocationStr() << ": " << getMsg(); |
284 | if (Hotness) |
285 | DP << " (hotness: " << *Hotness << ")" ; |
286 | } |
287 | |
288 | OptimizationRemark::(const char *PassName, |
289 | StringRef , |
290 | const DiagnosticLocation &Loc, |
291 | const BasicBlock *CodeRegion) |
292 | : DiagnosticInfoIROptimization(DK_OptimizationRemark, DS_Remark, PassName, |
293 | RemarkName, *CodeRegion->getParent(), Loc, |
294 | CodeRegion) {} |
295 | |
296 | OptimizationRemark::(const char *PassName, |
297 | StringRef , |
298 | const Instruction *Inst) |
299 | : DiagnosticInfoIROptimization(DK_OptimizationRemark, DS_Remark, PassName, |
300 | RemarkName, *Inst->getParent()->getParent(), |
301 | Inst->getDebugLoc(), Inst->getParent()) {} |
302 | |
303 | static const BasicBlock *getFirstFunctionBlock(const Function *Func) { |
304 | return Func->empty() ? nullptr : &Func->front(); |
305 | } |
306 | |
307 | OptimizationRemark::(const char *PassName, |
308 | StringRef , |
309 | const Function *Func) |
310 | : DiagnosticInfoIROptimization(DK_OptimizationRemark, DS_Remark, PassName, |
311 | RemarkName, *Func, Func->getSubprogram(), |
312 | getFirstFunctionBlock(Func)) {} |
313 | |
314 | bool OptimizationRemark::() const { |
315 | const Function &Fn = getFunction(); |
316 | LLVMContext &Ctx = Fn.getContext(); |
317 | return Ctx.getDiagHandlerPtr()->isPassedOptRemarkEnabled(PassName: getPassName()); |
318 | } |
319 | |
320 | OptimizationRemarkMissed::( |
321 | const char *PassName, StringRef , const DiagnosticLocation &Loc, |
322 | const BasicBlock *CodeRegion) |
323 | : DiagnosticInfoIROptimization(DK_OptimizationRemarkMissed, DS_Remark, |
324 | PassName, RemarkName, |
325 | *CodeRegion->getParent(), Loc, CodeRegion) {} |
326 | |
327 | OptimizationRemarkMissed::(const char *PassName, |
328 | StringRef , |
329 | const Instruction *Inst) |
330 | : DiagnosticInfoIROptimization(DK_OptimizationRemarkMissed, DS_Remark, |
331 | PassName, RemarkName, |
332 | *Inst->getParent()->getParent(), |
333 | Inst->getDebugLoc(), Inst->getParent()) {} |
334 | |
335 | OptimizationRemarkMissed::(const char *PassName, |
336 | StringRef , |
337 | const Function *Func) |
338 | : DiagnosticInfoIROptimization( |
339 | DK_OptimizationRemarkMissed, DS_Remark, PassName, RemarkName, *Func, |
340 | Func->getSubprogram(), getFirstFunctionBlock(Func)) {} |
341 | |
342 | bool OptimizationRemarkMissed::() const { |
343 | const Function &Fn = getFunction(); |
344 | LLVMContext &Ctx = Fn.getContext(); |
345 | return Ctx.getDiagHandlerPtr()->isMissedOptRemarkEnabled(PassName: getPassName()); |
346 | } |
347 | |
348 | OptimizationRemarkAnalysis::( |
349 | const char *PassName, StringRef , const DiagnosticLocation &Loc, |
350 | const BasicBlock *CodeRegion) |
351 | : DiagnosticInfoIROptimization(DK_OptimizationRemarkAnalysis, DS_Remark, |
352 | PassName, RemarkName, |
353 | *CodeRegion->getParent(), Loc, CodeRegion) {} |
354 | |
355 | OptimizationRemarkAnalysis::(const char *PassName, |
356 | StringRef , |
357 | const Instruction *Inst) |
358 | : DiagnosticInfoIROptimization(DK_OptimizationRemarkAnalysis, DS_Remark, |
359 | PassName, RemarkName, |
360 | *Inst->getParent()->getParent(), |
361 | Inst->getDebugLoc(), Inst->getParent()) {} |
362 | |
363 | OptimizationRemarkAnalysis::( |
364 | enum DiagnosticKind Kind, const char *PassName, StringRef , |
365 | const DiagnosticLocation &Loc, const BasicBlock *CodeRegion) |
366 | : DiagnosticInfoIROptimization(Kind, DS_Remark, PassName, RemarkName, |
367 | *CodeRegion->getParent(), Loc, CodeRegion) {} |
368 | |
369 | OptimizationRemarkAnalysis::(const char *PassName, |
370 | StringRef , |
371 | const Function *Func) |
372 | : DiagnosticInfoIROptimization( |
373 | DK_OptimizationRemarkAnalysis, DS_Remark, PassName, RemarkName, *Func, |
374 | Func->getSubprogram(), getFirstFunctionBlock(Func)) {} |
375 | |
376 | bool OptimizationRemarkAnalysis::() const { |
377 | const Function &Fn = getFunction(); |
378 | LLVMContext &Ctx = Fn.getContext(); |
379 | return Ctx.getDiagHandlerPtr()->isAnalysisRemarkEnabled(PassName: getPassName()) || |
380 | shouldAlwaysPrint(); |
381 | } |
382 | |
383 | void DiagnosticInfoMIRParser::print(DiagnosticPrinter &DP) const { |
384 | DP << Diagnostic; |
385 | } |
386 | |
387 | void DiagnosticInfoSrcMgr::print(DiagnosticPrinter &DP) const { |
388 | DP << Diagnostic; |
389 | } |
390 | |
391 | DiagnosticInfoOptimizationFailure::DiagnosticInfoOptimizationFailure( |
392 | const char *PassName, StringRef , const DiagnosticLocation &Loc, |
393 | const BasicBlock *CodeRegion) |
394 | : DiagnosticInfoIROptimization(DK_OptimizationFailure, DS_Warning, PassName, |
395 | RemarkName, *CodeRegion->getParent(), Loc, |
396 | CodeRegion) {} |
397 | |
398 | bool DiagnosticInfoOptimizationFailure::isEnabled() const { |
399 | // Only print warnings. |
400 | return getSeverity() == DS_Warning; |
401 | } |
402 | |
403 | void DiagnosticInfoUnsupported::print(DiagnosticPrinter &DP) const { |
404 | std::string Str; |
405 | raw_string_ostream OS(Str); |
406 | |
407 | OS << getLocationStr() << ": in function " << getFunction().getName() << ' ' |
408 | << *getFunction().getFunctionType() << ": " << Msg << '\n'; |
409 | OS.flush(); |
410 | DP << Str; |
411 | } |
412 | |
413 | void DiagnosticInfoInstrumentation::print(DiagnosticPrinter &DP) const { |
414 | DP << Msg; |
415 | } |
416 | |
417 | void DiagnosticInfoISelFallback::print(DiagnosticPrinter &DP) const { |
418 | DP << "Instruction selection used fallback path for " << getFunction(); |
419 | } |
420 | |
421 | void DiagnosticInfoOptimizationBase::insert(StringRef S) { |
422 | Args.emplace_back(Args&: S); |
423 | } |
424 | |
425 | void DiagnosticInfoOptimizationBase::insert(Argument A) { |
426 | Args.push_back(Elt: std::move(A)); |
427 | } |
428 | |
429 | void DiagnosticInfoOptimizationBase::insert(setIsVerbose V) { |
430 | IsVerbose = true; |
431 | } |
432 | |
433 | void DiagnosticInfoOptimizationBase::(setExtraArgs EA) { |
434 | FirstExtraArgIndex = Args.size(); |
435 | } |
436 | |
437 | std::string DiagnosticInfoOptimizationBase::getMsg() const { |
438 | std::string Str; |
439 | raw_string_ostream OS(Str); |
440 | for (const DiagnosticInfoOptimizationBase::Argument &Arg : |
441 | make_range(x: Args.begin(), y: FirstExtraArgIndex == -1 |
442 | ? Args.end() |
443 | : Args.begin() + FirstExtraArgIndex)) |
444 | OS << Arg.Val; |
445 | return Str; |
446 | } |
447 | |
448 | DiagnosticInfoMisExpect::DiagnosticInfoMisExpect(const Instruction *Inst, |
449 | const Twine &Msg) |
450 | : DiagnosticInfoWithLocationBase(DK_MisExpect, DS_Warning, |
451 | *Inst->getParent()->getParent(), |
452 | Inst->getDebugLoc()), |
453 | Msg(Msg) {} |
454 | |
455 | void DiagnosticInfoMisExpect::print(DiagnosticPrinter &DP) const { |
456 | DP << getLocationStr() << ": " << getMsg(); |
457 | } |
458 | |
459 | void OptimizationRemarkAnalysisFPCommute::() {} |
460 | void OptimizationRemarkAnalysisAliasing::() {} |
461 | |
462 | void llvm::diagnoseDontCall(const CallInst &CI) { |
463 | const auto *F = |
464 | dyn_cast<Function>(Val: CI.getCalledOperand()->stripPointerCasts()); |
465 | |
466 | if (!F) |
467 | return; |
468 | |
469 | for (int i = 0; i != 2; ++i) { |
470 | auto AttrName = i == 0 ? "dontcall-error" : "dontcall-warn" ; |
471 | auto Sev = i == 0 ? DS_Error : DS_Warning; |
472 | |
473 | if (F->hasFnAttribute(Kind: AttrName)) { |
474 | uint64_t LocCookie = 0; |
475 | auto A = F->getFnAttribute(Kind: AttrName); |
476 | if (MDNode *MD = CI.getMetadata(Kind: "srcloc" )) |
477 | LocCookie = |
478 | mdconst::extract<ConstantInt>(MD: MD->getOperand(I: 0))->getZExtValue(); |
479 | DiagnosticInfoDontCall D(F->getName(), A.getValueAsString(), Sev, |
480 | LocCookie); |
481 | F->getContext().diagnose(DI: D); |
482 | } |
483 | } |
484 | } |
485 | |
486 | void DiagnosticInfoDontCall::print(DiagnosticPrinter &DP) const { |
487 | DP << "call to " << demangle(MangledName: getFunctionName()) << " marked \"dontcall-" ; |
488 | if (getSeverity() == DiagnosticSeverity::DS_Error) |
489 | DP << "error\"" ; |
490 | else |
491 | DP << "warn\"" ; |
492 | if (!getNote().empty()) |
493 | DP << ": " << getNote(); |
494 | } |
495 | |