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