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