11a2b3536SDjordje Todorovic //===- Debugify.cpp - Check debug info preservation in optimizations ------===// 225ee8613SDaniel Sanders // 325ee8613SDaniel Sanders // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 425ee8613SDaniel Sanders // See https://llvm.org/LICENSE.txt for license information. 525ee8613SDaniel Sanders // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 625ee8613SDaniel Sanders // 725ee8613SDaniel Sanders //===----------------------------------------------------------------------===// 825ee8613SDaniel Sanders /// 91a2b3536SDjordje Todorovic /// \file In the `synthetic` mode, the `-debugify` attaches synthetic debug info 101a2b3536SDjordje Todorovic /// to everything. It can be used to create targeted tests for debug info 111a2b3536SDjordje Todorovic /// preservation. In addition, when using the `original` mode, it can check 121a2b3536SDjordje Todorovic /// original debug info preservation. The `synthetic` mode is default one. 1325ee8613SDaniel Sanders /// 1425ee8613SDaniel Sanders //===----------------------------------------------------------------------===// 1525ee8613SDaniel Sanders 164c1a1d3cSReid Kleckner #include "llvm/Transforms/Utils/Debugify.h" 1725ee8613SDaniel Sanders #include "llvm/ADT/BitVector.h" 1825ee8613SDaniel Sanders #include "llvm/ADT/StringExtras.h" 1925ee8613SDaniel Sanders #include "llvm/IR/DIBuilder.h" 2025ee8613SDaniel Sanders #include "llvm/IR/DebugInfo.h" 2125ee8613SDaniel Sanders #include "llvm/IR/InstIterator.h" 2225ee8613SDaniel Sanders #include "llvm/IR/Instructions.h" 2325ee8613SDaniel Sanders #include "llvm/IR/IntrinsicInst.h" 240128b950SSimon Pilgrim #include "llvm/IR/Module.h" 257de6dcd2SArthur Eubanks #include "llvm/IR/PassInstrumentation.h" 2625ee8613SDaniel Sanders #include "llvm/Pass.h" 274c1a1d3cSReid Kleckner #include "llvm/Support/CommandLine.h" 28ba7a92c0SNico Weber #include "llvm/Support/FileSystem.h" 299f41c03fSDjordje Todorovic #include "llvm/Support/JSON.h" 3025ee8613SDaniel Sanders 311a2b3536SDjordje Todorovic #define DEBUG_TYPE "debugify" 321a2b3536SDjordje Todorovic 3325ee8613SDaniel Sanders using namespace llvm; 3425ee8613SDaniel Sanders 3525ee8613SDaniel Sanders namespace { 3625ee8613SDaniel Sanders 3725ee8613SDaniel Sanders cl::opt<bool> Quiet("debugify-quiet", 3825ee8613SDaniel Sanders cl::desc("Suppress verbose debugify output")); 3925ee8613SDaniel Sanders 4015f7bc78SDaniel Sanders enum class Level { 4115f7bc78SDaniel Sanders Locations, 4215f7bc78SDaniel Sanders LocationsAndVariables 4315f7bc78SDaniel Sanders }; 441a2b3536SDjordje Todorovic 451a2b3536SDjordje Todorovic // Used for the synthetic mode only. 4615f7bc78SDaniel Sanders cl::opt<Level> DebugifyLevel( 4715f7bc78SDaniel Sanders "debugify-level", cl::desc("Kind of debug info to add"), 4815f7bc78SDaniel Sanders cl::values(clEnumValN(Level::Locations, "locations", "Locations only"), 4915f7bc78SDaniel Sanders clEnumValN(Level::LocationsAndVariables, "location+variables", 5015f7bc78SDaniel Sanders "Locations and Variables")), 5115f7bc78SDaniel Sanders cl::init(Level::LocationsAndVariables)); 5215f7bc78SDaniel Sanders 5325ee8613SDaniel Sanders raw_ostream &dbg() { return Quiet ? nulls() : errs(); } 5425ee8613SDaniel Sanders 5525ee8613SDaniel Sanders uint64_t getAllocSizeInBits(Module &M, Type *Ty) { 5625ee8613SDaniel Sanders return Ty->isSized() ? M.getDataLayout().getTypeAllocSizeInBits(Ty) : 0; 5725ee8613SDaniel Sanders } 5825ee8613SDaniel Sanders 5925ee8613SDaniel Sanders bool isFunctionSkipped(Function &F) { 6025ee8613SDaniel Sanders return F.isDeclaration() || !F.hasExactDefinition(); 6125ee8613SDaniel Sanders } 6225ee8613SDaniel Sanders 6325ee8613SDaniel Sanders /// Find the basic block's terminating instruction. 6425ee8613SDaniel Sanders /// 6525ee8613SDaniel Sanders /// Special care is needed to handle musttail and deopt calls, as these behave 6625ee8613SDaniel Sanders /// like (but are in fact not) terminators. 6725ee8613SDaniel Sanders Instruction *findTerminatingInstruction(BasicBlock &BB) { 6825ee8613SDaniel Sanders if (auto *I = BB.getTerminatingMustTailCall()) 6925ee8613SDaniel Sanders return I; 7025ee8613SDaniel Sanders if (auto *I = BB.getTerminatingDeoptimizeCall()) 7125ee8613SDaniel Sanders return I; 7225ee8613SDaniel Sanders return BB.getTerminator(); 7325ee8613SDaniel Sanders } 741adeeabbSDaniel Sanders } // end anonymous namespace 7525ee8613SDaniel Sanders 761adeeabbSDaniel Sanders bool llvm::applyDebugifyMetadata( 771adeeabbSDaniel Sanders Module &M, iterator_range<Module::iterator> Functions, StringRef Banner, 781adeeabbSDaniel Sanders std::function<bool(DIBuilder &DIB, Function &F)> ApplyToMF) { 7925ee8613SDaniel Sanders // Skip modules with debug info. 8025ee8613SDaniel Sanders if (M.getNamedMetadata("llvm.dbg.cu")) { 8125ee8613SDaniel Sanders dbg() << Banner << "Skipping module with debug info\n"; 8225ee8613SDaniel Sanders return false; 8325ee8613SDaniel Sanders } 8425ee8613SDaniel Sanders 8525ee8613SDaniel Sanders DIBuilder DIB(M); 8625ee8613SDaniel Sanders LLVMContext &Ctx = M.getContext(); 87a852ee19SNico Weber auto *Int32Ty = Type::getInt32Ty(Ctx); 8825ee8613SDaniel Sanders 8925ee8613SDaniel Sanders // Get a DIType which corresponds to Ty. 9025ee8613SDaniel Sanders DenseMap<uint64_t, DIType *> TypeCache; 9125ee8613SDaniel Sanders auto getCachedDIType = [&](Type *Ty) -> DIType * { 9225ee8613SDaniel Sanders uint64_t Size = getAllocSizeInBits(M, Ty); 9325ee8613SDaniel Sanders DIType *&DTy = TypeCache[Size]; 9425ee8613SDaniel Sanders if (!DTy) { 9525ee8613SDaniel Sanders std::string Name = "ty" + utostr(Size); 9625ee8613SDaniel Sanders DTy = DIB.createBasicType(Name, Size, dwarf::DW_ATE_unsigned); 9725ee8613SDaniel Sanders } 9825ee8613SDaniel Sanders return DTy; 9925ee8613SDaniel Sanders }; 10025ee8613SDaniel Sanders 10125ee8613SDaniel Sanders unsigned NextLine = 1; 10225ee8613SDaniel Sanders unsigned NextVar = 1; 10325ee8613SDaniel Sanders auto File = DIB.createFile(M.getName(), "/"); 10425ee8613SDaniel Sanders auto CU = DIB.createCompileUnit(dwarf::DW_LANG_C, File, "debugify", 10525ee8613SDaniel Sanders /*isOptimized=*/true, "", 0); 10625ee8613SDaniel Sanders 10725ee8613SDaniel Sanders // Visit each instruction. 10825ee8613SDaniel Sanders for (Function &F : Functions) { 10925ee8613SDaniel Sanders if (isFunctionSkipped(F)) 11025ee8613SDaniel Sanders continue; 11125ee8613SDaniel Sanders 112a852ee19SNico Weber bool InsertedDbgVal = false; 11325ee8613SDaniel Sanders auto SPType = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None)); 11425ee8613SDaniel Sanders DISubprogram::DISPFlags SPFlags = 11525ee8613SDaniel Sanders DISubprogram::SPFlagDefinition | DISubprogram::SPFlagOptimized; 11625ee8613SDaniel Sanders if (F.hasPrivateLinkage() || F.hasInternalLinkage()) 11725ee8613SDaniel Sanders SPFlags |= DISubprogram::SPFlagLocalToUnit; 11825ee8613SDaniel Sanders auto SP = DIB.createFunction(CU, F.getName(), F.getName(), File, NextLine, 11925ee8613SDaniel Sanders SPType, NextLine, DINode::FlagZero, SPFlags); 12025ee8613SDaniel Sanders F.setSubprogram(SP); 121a852ee19SNico Weber 122a852ee19SNico Weber // Helper that inserts a dbg.value before \p InsertBefore, copying the 123a852ee19SNico Weber // location (and possibly the type, if it's non-void) from \p TemplateInst. 124a852ee19SNico Weber auto insertDbgVal = [&](Instruction &TemplateInst, 125a852ee19SNico Weber Instruction *InsertBefore) { 126a852ee19SNico Weber std::string Name = utostr(NextVar++); 127a852ee19SNico Weber Value *V = &TemplateInst; 128a852ee19SNico Weber if (TemplateInst.getType()->isVoidTy()) 129a852ee19SNico Weber V = ConstantInt::get(Int32Ty, 0); 130a852ee19SNico Weber const DILocation *Loc = TemplateInst.getDebugLoc().get(); 131a852ee19SNico Weber auto LocalVar = DIB.createAutoVariable(SP, Name, File, Loc->getLine(), 132a852ee19SNico Weber getCachedDIType(V->getType()), 133a852ee19SNico Weber /*AlwaysPreserve=*/true); 134a852ee19SNico Weber DIB.insertDbgValueIntrinsic(V, LocalVar, DIB.createExpression(), Loc, 135a852ee19SNico Weber InsertBefore); 136a852ee19SNico Weber }; 137a852ee19SNico Weber 13825ee8613SDaniel Sanders for (BasicBlock &BB : F) { 13925ee8613SDaniel Sanders // Attach debug locations. 14025ee8613SDaniel Sanders for (Instruction &I : BB) 14125ee8613SDaniel Sanders I.setDebugLoc(DILocation::get(Ctx, NextLine++, 1, SP)); 14225ee8613SDaniel Sanders 14315f7bc78SDaniel Sanders if (DebugifyLevel < Level::LocationsAndVariables) 14415f7bc78SDaniel Sanders continue; 14515f7bc78SDaniel Sanders 14625ee8613SDaniel Sanders // Inserting debug values into EH pads can break IR invariants. 14725ee8613SDaniel Sanders if (BB.isEHPad()) 14825ee8613SDaniel Sanders continue; 14925ee8613SDaniel Sanders 15025ee8613SDaniel Sanders // Find the terminating instruction, after which no debug values are 15125ee8613SDaniel Sanders // attached. 15225ee8613SDaniel Sanders Instruction *LastInst = findTerminatingInstruction(BB); 15325ee8613SDaniel Sanders assert(LastInst && "Expected basic block with a terminator"); 15425ee8613SDaniel Sanders 15525ee8613SDaniel Sanders // Maintain an insertion point which can't be invalidated when updates 15625ee8613SDaniel Sanders // are made. 15725ee8613SDaniel Sanders BasicBlock::iterator InsertPt = BB.getFirstInsertionPt(); 15825ee8613SDaniel Sanders assert(InsertPt != BB.end() && "Expected to find an insertion point"); 15925ee8613SDaniel Sanders Instruction *InsertBefore = &*InsertPt; 16025ee8613SDaniel Sanders 16125ee8613SDaniel Sanders // Attach debug values. 16225ee8613SDaniel Sanders for (Instruction *I = &*BB.begin(); I != LastInst; I = I->getNextNode()) { 16325ee8613SDaniel Sanders // Skip void-valued instructions. 16425ee8613SDaniel Sanders if (I->getType()->isVoidTy()) 16525ee8613SDaniel Sanders continue; 16625ee8613SDaniel Sanders 16725ee8613SDaniel Sanders // Phis and EH pads must be grouped at the beginning of the block. 16825ee8613SDaniel Sanders // Only advance the insertion point when we finish visiting these. 16925ee8613SDaniel Sanders if (!isa<PHINode>(I) && !I->isEHPad()) 17025ee8613SDaniel Sanders InsertBefore = I->getNextNode(); 17125ee8613SDaniel Sanders 172a852ee19SNico Weber insertDbgVal(*I, InsertBefore); 173a852ee19SNico Weber InsertedDbgVal = true; 17425ee8613SDaniel Sanders } 17525ee8613SDaniel Sanders } 176a852ee19SNico Weber // Make sure we emit at least one dbg.value, otherwise MachineDebugify may 177a852ee19SNico Weber // not have anything to work with as it goes about inserting DBG_VALUEs. 178a852ee19SNico Weber // (It's common for MIR tests to be written containing skeletal IR with 179a852ee19SNico Weber // empty functions -- we're still interested in debugifying the MIR within 180a852ee19SNico Weber // those tests, and this helps with that.) 181a852ee19SNico Weber if (DebugifyLevel == Level::LocationsAndVariables && !InsertedDbgVal) { 182a852ee19SNico Weber auto *Term = findTerminatingInstruction(F.getEntryBlock()); 183a852ee19SNico Weber insertDbgVal(*Term, Term); 184a852ee19SNico Weber } 1851adeeabbSDaniel Sanders if (ApplyToMF) 1861adeeabbSDaniel Sanders ApplyToMF(DIB, F); 18725ee8613SDaniel Sanders DIB.finalizeSubprogram(SP); 18825ee8613SDaniel Sanders } 18925ee8613SDaniel Sanders DIB.finalize(); 19025ee8613SDaniel Sanders 19125ee8613SDaniel Sanders // Track the number of distinct lines and variables. 19225ee8613SDaniel Sanders NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.debugify"); 19325ee8613SDaniel Sanders auto addDebugifyOperand = [&](unsigned N) { 19425ee8613SDaniel Sanders NMD->addOperand(MDNode::get( 195a852ee19SNico Weber Ctx, ValueAsMetadata::getConstant(ConstantInt::get(Int32Ty, N)))); 19625ee8613SDaniel Sanders }; 19725ee8613SDaniel Sanders addDebugifyOperand(NextLine - 1); // Original number of lines. 19825ee8613SDaniel Sanders addDebugifyOperand(NextVar - 1); // Original number of variables. 19925ee8613SDaniel Sanders assert(NMD->getNumOperands() == 2 && 20025ee8613SDaniel Sanders "llvm.debugify should have exactly 2 operands!"); 20125ee8613SDaniel Sanders 20225ee8613SDaniel Sanders // Claim that this synthetic debug info is valid. 20325ee8613SDaniel Sanders StringRef DIVersionKey = "Debug Info Version"; 20425ee8613SDaniel Sanders if (!M.getModuleFlag(DIVersionKey)) 20525ee8613SDaniel Sanders M.addModuleFlag(Module::Warning, DIVersionKey, DEBUG_METADATA_VERSION); 20625ee8613SDaniel Sanders 20725ee8613SDaniel Sanders return true; 20825ee8613SDaniel Sanders } 20925ee8613SDaniel Sanders 2101a2b3536SDjordje Todorovic static bool 2111a2b3536SDjordje Todorovic applyDebugify(Function &F, 2121a2b3536SDjordje Todorovic enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo, 2131a2b3536SDjordje Todorovic DebugInfoPerPassMap *DIPreservationMap = nullptr, 2141a2b3536SDjordje Todorovic StringRef NameOfWrappedPass = "") { 21598b93385SFangrui Song Module &M = *F.getParent(); 21698b93385SFangrui Song auto FuncIt = F.getIterator(); 2171a2b3536SDjordje Todorovic if (Mode == DebugifyMode::SyntheticDebugInfo) 21898b93385SFangrui Song return applyDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)), 2191a2b3536SDjordje Todorovic "FunctionDebugify: ", /*ApplyToMF*/ nullptr); 2201a2b3536SDjordje Todorovic assert(DIPreservationMap); 2211a2b3536SDjordje Todorovic return collectDebugInfoMetadata(M, M.functions(), *DIPreservationMap, 2221a2b3536SDjordje Todorovic "FunctionDebugify (original debuginfo)", 2231a2b3536SDjordje Todorovic NameOfWrappedPass); 22498b93385SFangrui Song } 22598b93385SFangrui Song 2261a2b3536SDjordje Todorovic static bool 2271a2b3536SDjordje Todorovic applyDebugify(Module &M, 2281a2b3536SDjordje Todorovic enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo, 2291a2b3536SDjordje Todorovic DebugInfoPerPassMap *DIPreservationMap = nullptr, 2301a2b3536SDjordje Todorovic StringRef NameOfWrappedPass = "") { 2311a2b3536SDjordje Todorovic if (Mode == DebugifyMode::SyntheticDebugInfo) 23298b93385SFangrui Song return applyDebugifyMetadata(M, M.functions(), 2331a2b3536SDjordje Todorovic "ModuleDebugify: ", /*ApplyToMF*/ nullptr); 2341a2b3536SDjordje Todorovic return collectDebugInfoMetadata(M, M.functions(), *DIPreservationMap, 2351a2b3536SDjordje Todorovic "ModuleDebugify (original debuginfo)", 2361a2b3536SDjordje Todorovic NameOfWrappedPass); 23798b93385SFangrui Song } 23898b93385SFangrui Song 239122a6bfbSVedant Kumar bool llvm::stripDebugifyMetadata(Module &M) { 240122a6bfbSVedant Kumar bool Changed = false; 241122a6bfbSVedant Kumar 242122a6bfbSVedant Kumar // Remove the llvm.debugify module-level named metadata. 243122a6bfbSVedant Kumar NamedMDNode *DebugifyMD = M.getNamedMetadata("llvm.debugify"); 244122a6bfbSVedant Kumar if (DebugifyMD) { 245122a6bfbSVedant Kumar M.eraseNamedMetadata(DebugifyMD); 246122a6bfbSVedant Kumar Changed = true; 247122a6bfbSVedant Kumar } 248122a6bfbSVedant Kumar 249122a6bfbSVedant Kumar // Strip out all debug intrinsics and supporting metadata (subprograms, types, 250122a6bfbSVedant Kumar // variables, etc). 251122a6bfbSVedant Kumar Changed |= StripDebugInfo(M); 252122a6bfbSVedant Kumar 253122a6bfbSVedant Kumar // Strip out the dead dbg.value prototype. 254122a6bfbSVedant Kumar Function *DbgValF = M.getFunction("llvm.dbg.value"); 255122a6bfbSVedant Kumar if (DbgValF) { 256122a6bfbSVedant Kumar assert(DbgValF->isDeclaration() && DbgValF->use_empty() && 257122a6bfbSVedant Kumar "Not all debug info stripped?"); 258122a6bfbSVedant Kumar DbgValF->eraseFromParent(); 259122a6bfbSVedant Kumar Changed = true; 260122a6bfbSVedant Kumar } 261122a6bfbSVedant Kumar 262122a6bfbSVedant Kumar // Strip out the module-level Debug Info Version metadata. 263122a6bfbSVedant Kumar // FIXME: There must be an easier way to remove an operand from a NamedMDNode. 264122a6bfbSVedant Kumar NamedMDNode *NMD = M.getModuleFlagsMetadata(); 2652fa656cdSVedant Kumar if (!NMD) 2662fa656cdSVedant Kumar return Changed; 26719aacdb7SKazu Hirata SmallVector<MDNode *, 4> Flags(NMD->operands()); 268122a6bfbSVedant Kumar NMD->clearOperands(); 269122a6bfbSVedant Kumar for (MDNode *Flag : Flags) { 270122a6bfbSVedant Kumar MDString *Key = dyn_cast_or_null<MDString>(Flag->getOperand(1)); 271122a6bfbSVedant Kumar if (Key->getString() == "Debug Info Version") { 272122a6bfbSVedant Kumar Changed = true; 273122a6bfbSVedant Kumar continue; 274122a6bfbSVedant Kumar } 275122a6bfbSVedant Kumar NMD->addOperand(Flag); 276122a6bfbSVedant Kumar } 277122a6bfbSVedant Kumar // If we left it empty we might as well remove it. 278122a6bfbSVedant Kumar if (NMD->getNumOperands() == 0) 279122a6bfbSVedant Kumar NMD->eraseFromParent(); 280122a6bfbSVedant Kumar 281122a6bfbSVedant Kumar return Changed; 282122a6bfbSVedant Kumar } 283122a6bfbSVedant Kumar 2841a2b3536SDjordje Todorovic bool llvm::collectDebugInfoMetadata(Module &M, 2851a2b3536SDjordje Todorovic iterator_range<Module::iterator> Functions, 2861a2b3536SDjordje Todorovic DebugInfoPerPassMap &DIPreservationMap, 2871a2b3536SDjordje Todorovic StringRef Banner, 2881a2b3536SDjordje Todorovic StringRef NameOfWrappedPass) { 2891a2b3536SDjordje Todorovic LLVM_DEBUG(dbgs() << Banner << ": (before) " << NameOfWrappedPass << '\n'); 2901a2b3536SDjordje Todorovic 2911a2b3536SDjordje Todorovic // Clear the map with the debug info before every single pass. 2921a2b3536SDjordje Todorovic DIPreservationMap.clear(); 2931a2b3536SDjordje Todorovic 2941a2b3536SDjordje Todorovic if (!M.getNamedMetadata("llvm.dbg.cu")) { 2951a2b3536SDjordje Todorovic dbg() << Banner << ": Skipping module without debug info\n"; 2961a2b3536SDjordje Todorovic return false; 2971a2b3536SDjordje Todorovic } 2981a2b3536SDjordje Todorovic 2991a2b3536SDjordje Todorovic // Visit each instruction. 3001a2b3536SDjordje Todorovic for (Function &F : Functions) { 3011a2b3536SDjordje Todorovic if (isFunctionSkipped(F)) 3021a2b3536SDjordje Todorovic continue; 3031a2b3536SDjordje Todorovic 3041a2b3536SDjordje Todorovic // Collect the DISubprogram. 3051a2b3536SDjordje Todorovic auto *SP = F.getSubprogram(); 3061a2b3536SDjordje Todorovic DIPreservationMap[NameOfWrappedPass].DIFunctions.insert({F.getName(), SP}); 307b9076d11SDjordje Todorovic if (SP) { 3081a2b3536SDjordje Todorovic LLVM_DEBUG(dbgs() << " Collecting subprogram: " << *SP << '\n'); 309b9076d11SDjordje Todorovic for (const DINode *DN : SP->getRetainedNodes()) { 310b9076d11SDjordje Todorovic if (const auto *DV = dyn_cast<DILocalVariable>(DN)) { 311b9076d11SDjordje Todorovic DIPreservationMap[NameOfWrappedPass].DIVariables[DV] = 0; 312b9076d11SDjordje Todorovic } 313b9076d11SDjordje Todorovic } 314b9076d11SDjordje Todorovic } 3151a2b3536SDjordje Todorovic 3161a2b3536SDjordje Todorovic for (BasicBlock &BB : F) { 317b9076d11SDjordje Todorovic // Collect debug locations (!dbg) and debug variable intrinsics. 3181a2b3536SDjordje Todorovic for (Instruction &I : BB) { 3191a2b3536SDjordje Todorovic // Skip PHIs. 3201a2b3536SDjordje Todorovic if (isa<PHINode>(I)) 3211a2b3536SDjordje Todorovic continue; 3221a2b3536SDjordje Todorovic 323b9076d11SDjordje Todorovic // Collect dbg.values and dbg.declares. 324b9076d11SDjordje Todorovic if (auto *DVI = dyn_cast<DbgVariableIntrinsic>(&I)) { 325b9076d11SDjordje Todorovic if (!SP) 326b9076d11SDjordje Todorovic continue; 327b9076d11SDjordje Todorovic // Skip inlined variables. 328b9076d11SDjordje Todorovic if (I.getDebugLoc().getInlinedAt()) 329b9076d11SDjordje Todorovic continue; 330b9076d11SDjordje Todorovic // Skip undef values. 331b9076d11SDjordje Todorovic if (DVI->isUndef()) 332b9076d11SDjordje Todorovic continue; 333b9076d11SDjordje Todorovic 334b9076d11SDjordje Todorovic auto *Var = DVI->getVariable(); 335b9076d11SDjordje Todorovic DIPreservationMap[NameOfWrappedPass].DIVariables[Var]++; 336b9076d11SDjordje Todorovic continue; 337b9076d11SDjordje Todorovic } 338b9076d11SDjordje Todorovic 339b9076d11SDjordje Todorovic // Skip debug instructions other than dbg.value and dbg.declare. 3401a2b3536SDjordje Todorovic if (isa<DbgInfoIntrinsic>(&I)) 3411a2b3536SDjordje Todorovic continue; 3421a2b3536SDjordje Todorovic 3431a2b3536SDjordje Todorovic LLVM_DEBUG(dbgs() << " Collecting info for inst: " << I << '\n'); 3441a2b3536SDjordje Todorovic DIPreservationMap[NameOfWrappedPass].InstToDelete.insert({&I, &I}); 3451a2b3536SDjordje Todorovic 3461a2b3536SDjordje Todorovic const DILocation *Loc = I.getDebugLoc().get(); 3471a2b3536SDjordje Todorovic bool HasLoc = Loc != nullptr; 3481a2b3536SDjordje Todorovic DIPreservationMap[NameOfWrappedPass].DILocations.insert({&I, HasLoc}); 3491a2b3536SDjordje Todorovic } 3501a2b3536SDjordje Todorovic } 3511a2b3536SDjordje Todorovic } 3521a2b3536SDjordje Todorovic 3531a2b3536SDjordje Todorovic return true; 3541a2b3536SDjordje Todorovic } 3551a2b3536SDjordje Todorovic 3561a2b3536SDjordje Todorovic // This checks the preservation of original debug info attached to functions. 3571a2b3536SDjordje Todorovic static bool checkFunctions(const DebugFnMap &DIFunctionsBefore, 3581a2b3536SDjordje Todorovic const DebugFnMap &DIFunctionsAfter, 3591a2b3536SDjordje Todorovic StringRef NameOfWrappedPass, 3609f41c03fSDjordje Todorovic StringRef FileNameFromCU, bool ShouldWriteIntoJSON, 3619f41c03fSDjordje Todorovic llvm::json::Array &Bugs) { 3621a2b3536SDjordje Todorovic bool Preserved = true; 3631a2b3536SDjordje Todorovic for (const auto &F : DIFunctionsAfter) { 3641a2b3536SDjordje Todorovic if (F.second) 3651a2b3536SDjordje Todorovic continue; 3661a2b3536SDjordje Todorovic auto SPIt = DIFunctionsBefore.find(F.first); 3671a2b3536SDjordje Todorovic if (SPIt == DIFunctionsBefore.end()) { 3689f41c03fSDjordje Todorovic if (ShouldWriteIntoJSON) 3699f41c03fSDjordje Todorovic Bugs.push_back(llvm::json::Object({{"metadata", "DISubprogram"}, 3709f41c03fSDjordje Todorovic {"name", F.first}, 3719f41c03fSDjordje Todorovic {"action", "not-generate"}})); 3729f41c03fSDjordje Todorovic else 3731a2b3536SDjordje Todorovic dbg() << "ERROR: " << NameOfWrappedPass 3741a2b3536SDjordje Todorovic << " did not generate DISubprogram for " << F.first << " from " 3751a2b3536SDjordje Todorovic << FileNameFromCU << '\n'; 3761a2b3536SDjordje Todorovic Preserved = false; 3771a2b3536SDjordje Todorovic } else { 3781a2b3536SDjordje Todorovic auto SP = SPIt->second; 3791a2b3536SDjordje Todorovic if (!SP) 3801a2b3536SDjordje Todorovic continue; 3811a2b3536SDjordje Todorovic // If the function had the SP attached before the pass, consider it as 3821a2b3536SDjordje Todorovic // a debug info bug. 3839f41c03fSDjordje Todorovic if (ShouldWriteIntoJSON) 3849f41c03fSDjordje Todorovic Bugs.push_back(llvm::json::Object({{"metadata", "DISubprogram"}, 3859f41c03fSDjordje Todorovic {"name", F.first}, 3869f41c03fSDjordje Todorovic {"action", "drop"}})); 3879f41c03fSDjordje Todorovic else 3881a2b3536SDjordje Todorovic dbg() << "ERROR: " << NameOfWrappedPass << " dropped DISubprogram of " 3891a2b3536SDjordje Todorovic << F.first << " from " << FileNameFromCU << '\n'; 3901a2b3536SDjordje Todorovic Preserved = false; 3911a2b3536SDjordje Todorovic } 3921a2b3536SDjordje Todorovic } 3931a2b3536SDjordje Todorovic 3941a2b3536SDjordje Todorovic return Preserved; 3951a2b3536SDjordje Todorovic } 3961a2b3536SDjordje Todorovic 3971a2b3536SDjordje Todorovic // This checks the preservation of the original debug info attached to 3981a2b3536SDjordje Todorovic // instructions. 3991a2b3536SDjordje Todorovic static bool checkInstructions(const DebugInstMap &DILocsBefore, 4001a2b3536SDjordje Todorovic const DebugInstMap &DILocsAfter, 4011a2b3536SDjordje Todorovic const WeakInstValueMap &InstToDelete, 4021a2b3536SDjordje Todorovic StringRef NameOfWrappedPass, 4039f41c03fSDjordje Todorovic StringRef FileNameFromCU, 4049f41c03fSDjordje Todorovic bool ShouldWriteIntoJSON, 4059f41c03fSDjordje Todorovic llvm::json::Array &Bugs) { 4061a2b3536SDjordje Todorovic bool Preserved = true; 4071a2b3536SDjordje Todorovic for (const auto &L : DILocsAfter) { 4081a2b3536SDjordje Todorovic if (L.second) 4091a2b3536SDjordje Todorovic continue; 4101a2b3536SDjordje Todorovic auto Instr = L.first; 4111a2b3536SDjordje Todorovic 4121a2b3536SDjordje Todorovic // In order to avoid pointer reuse/recycling, skip the values that might 4131a2b3536SDjordje Todorovic // have been deleted during a pass. 4141a2b3536SDjordje Todorovic auto WeakInstrPtr = InstToDelete.find(Instr); 4151a2b3536SDjordje Todorovic if (WeakInstrPtr != InstToDelete.end() && !WeakInstrPtr->second) 4161a2b3536SDjordje Todorovic continue; 4171a2b3536SDjordje Todorovic 4181a2b3536SDjordje Todorovic auto FnName = Instr->getFunction()->getName(); 4191a2b3536SDjordje Todorovic auto BB = Instr->getParent(); 4201a2b3536SDjordje Todorovic auto BBName = BB->hasName() ? BB->getName() : "no-name"; 4219f41c03fSDjordje Todorovic auto InstName = Instruction::getOpcodeName(Instr->getOpcode()); 4221a2b3536SDjordje Todorovic 4231a2b3536SDjordje Todorovic auto InstrIt = DILocsBefore.find(Instr); 4241a2b3536SDjordje Todorovic if (InstrIt == DILocsBefore.end()) { 4259f41c03fSDjordje Todorovic if (ShouldWriteIntoJSON) 4269f41c03fSDjordje Todorovic Bugs.push_back(llvm::json::Object({{"metadata", "DILocation"}, 4279f41c03fSDjordje Todorovic {"fn-name", FnName.str()}, 4289f41c03fSDjordje Todorovic {"bb-name", BBName.str()}, 4299f41c03fSDjordje Todorovic {"instr", InstName}, 4309f41c03fSDjordje Todorovic {"action", "not-generate"}})); 4319f41c03fSDjordje Todorovic else 4321a2b3536SDjordje Todorovic dbg() << "WARNING: " << NameOfWrappedPass 4331a2b3536SDjordje Todorovic << " did not generate DILocation for " << *Instr 4341a2b3536SDjordje Todorovic << " (BB: " << BBName << ", Fn: " << FnName 4351a2b3536SDjordje Todorovic << ", File: " << FileNameFromCU << ")\n"; 4361a2b3536SDjordje Todorovic Preserved = false; 4371a2b3536SDjordje Todorovic } else { 4381a2b3536SDjordje Todorovic if (!InstrIt->second) 4391a2b3536SDjordje Todorovic continue; 4401a2b3536SDjordje Todorovic // If the instr had the !dbg attached before the pass, consider it as 4411a2b3536SDjordje Todorovic // a debug info issue. 4429f41c03fSDjordje Todorovic if (ShouldWriteIntoJSON) 4439f41c03fSDjordje Todorovic Bugs.push_back(llvm::json::Object({{"metadata", "DILocation"}, 4449f41c03fSDjordje Todorovic {"fn-name", FnName.str()}, 4459f41c03fSDjordje Todorovic {"bb-name", BBName.str()}, 4469f41c03fSDjordje Todorovic {"instr", InstName}, 4479f41c03fSDjordje Todorovic {"action", "drop"}})); 4489f41c03fSDjordje Todorovic else 4491a2b3536SDjordje Todorovic dbg() << "WARNING: " << NameOfWrappedPass << " dropped DILocation of " 4501a2b3536SDjordje Todorovic << *Instr << " (BB: " << BBName << ", Fn: " << FnName 4511a2b3536SDjordje Todorovic << ", File: " << FileNameFromCU << ")\n"; 4521a2b3536SDjordje Todorovic Preserved = false; 4531a2b3536SDjordje Todorovic } 4541a2b3536SDjordje Todorovic } 4551a2b3536SDjordje Todorovic 4561a2b3536SDjordje Todorovic return Preserved; 4571a2b3536SDjordje Todorovic } 4581a2b3536SDjordje Todorovic 459b9076d11SDjordje Todorovic // This checks the preservation of original debug variable intrinsics. 460*f8dfc352SDjordje Todorovic static bool checkVars(const DebugVarMap &DIVarsBefore, 461*f8dfc352SDjordje Todorovic const DebugVarMap &DIVarsAfter, 462b9076d11SDjordje Todorovic StringRef NameOfWrappedPass, StringRef FileNameFromCU, 463b9076d11SDjordje Todorovic bool ShouldWriteIntoJSON, llvm::json::Array &Bugs) { 464b9076d11SDjordje Todorovic bool Preserved = true; 465*f8dfc352SDjordje Todorovic for (const auto &V : DIVarsBefore) { 466*f8dfc352SDjordje Todorovic auto VarIt = DIVarsAfter.find(V.first); 467*f8dfc352SDjordje Todorovic if (VarIt == DIVarsAfter.end()) 468b9076d11SDjordje Todorovic continue; 469b9076d11SDjordje Todorovic 470b9076d11SDjordje Todorovic unsigned NumOfDbgValsAfter = VarIt->second; 471b9076d11SDjordje Todorovic 472b9076d11SDjordje Todorovic if (V.second > NumOfDbgValsAfter) { 473b9076d11SDjordje Todorovic if (ShouldWriteIntoJSON) 474b9076d11SDjordje Todorovic Bugs.push_back(llvm::json::Object( 475b9076d11SDjordje Todorovic {{"metadata", "dbg-var-intrinsic"}, 476b9076d11SDjordje Todorovic {"name", V.first->getName()}, 477b9076d11SDjordje Todorovic {"fn-name", V.first->getScope()->getSubprogram()->getName()}, 478b9076d11SDjordje Todorovic {"action", "drop"}})); 479b9076d11SDjordje Todorovic else 480b9076d11SDjordje Todorovic dbg() << "WARNING: " << NameOfWrappedPass 481b9076d11SDjordje Todorovic << " drops dbg.value()/dbg.declare() for " << V.first->getName() 482b9076d11SDjordje Todorovic << " from " 483b9076d11SDjordje Todorovic << "function " << V.first->getScope()->getSubprogram()->getName() 484b9076d11SDjordje Todorovic << " (file " << FileNameFromCU << ")\n"; 485b9076d11SDjordje Todorovic Preserved = false; 486b9076d11SDjordje Todorovic } 487b9076d11SDjordje Todorovic } 488b9076d11SDjordje Todorovic 489b9076d11SDjordje Todorovic return Preserved; 490b9076d11SDjordje Todorovic } 491b9076d11SDjordje Todorovic 4929f41c03fSDjordje Todorovic // Write the json data into the specifed file. 4939f41c03fSDjordje Todorovic static void writeJSON(StringRef OrigDIVerifyBugsReportFilePath, 4949f41c03fSDjordje Todorovic StringRef FileNameFromCU, StringRef NameOfWrappedPass, 4959f41c03fSDjordje Todorovic llvm::json::Array &Bugs) { 4969f41c03fSDjordje Todorovic std::error_code EC; 4979f41c03fSDjordje Todorovic raw_fd_ostream OS_FILE{OrigDIVerifyBugsReportFilePath, EC, 49882b3e28eSAbhina Sreeskantharajan sys::fs::OF_Append | sys::fs::OF_TextWithCRLF}; 4999f41c03fSDjordje Todorovic if (EC) { 5009f41c03fSDjordje Todorovic errs() << "Could not open file: " << EC.message() << ", " 5019f41c03fSDjordje Todorovic << OrigDIVerifyBugsReportFilePath << '\n'; 5029f41c03fSDjordje Todorovic return; 5039f41c03fSDjordje Todorovic } 5049f41c03fSDjordje Todorovic 5059f41c03fSDjordje Todorovic OS_FILE << "{\"file\":\"" << FileNameFromCU << "\", "; 5069f41c03fSDjordje Todorovic 5079f41c03fSDjordje Todorovic StringRef PassName = NameOfWrappedPass != "" ? NameOfWrappedPass : "no-name"; 5089f41c03fSDjordje Todorovic OS_FILE << "\"pass\":\"" << PassName << "\", "; 5099f41c03fSDjordje Todorovic 5109f41c03fSDjordje Todorovic llvm::json::Value BugsToPrint{std::move(Bugs)}; 5119f41c03fSDjordje Todorovic OS_FILE << "\"bugs\": " << BugsToPrint; 5129f41c03fSDjordje Todorovic 5139f41c03fSDjordje Todorovic OS_FILE << "}\n"; 5149f41c03fSDjordje Todorovic } 5159f41c03fSDjordje Todorovic 5161a2b3536SDjordje Todorovic bool llvm::checkDebugInfoMetadata(Module &M, 5171a2b3536SDjordje Todorovic iterator_range<Module::iterator> Functions, 5181a2b3536SDjordje Todorovic DebugInfoPerPassMap &DIPreservationMap, 5199f41c03fSDjordje Todorovic StringRef Banner, StringRef NameOfWrappedPass, 5209f41c03fSDjordje Todorovic StringRef OrigDIVerifyBugsReportFilePath) { 5211a2b3536SDjordje Todorovic LLVM_DEBUG(dbgs() << Banner << ": (after) " << NameOfWrappedPass << '\n'); 5221a2b3536SDjordje Todorovic 5231a2b3536SDjordje Todorovic if (!M.getNamedMetadata("llvm.dbg.cu")) { 5241a2b3536SDjordje Todorovic dbg() << Banner << ": Skipping module without debug info\n"; 5251a2b3536SDjordje Todorovic return false; 5261a2b3536SDjordje Todorovic } 5271a2b3536SDjordje Todorovic 5281a2b3536SDjordje Todorovic // Map the debug info holding DIs after a pass. 5291a2b3536SDjordje Todorovic DebugInfoPerPassMap DIPreservationAfter; 5301a2b3536SDjordje Todorovic 5311a2b3536SDjordje Todorovic // Visit each instruction. 5321a2b3536SDjordje Todorovic for (Function &F : Functions) { 5331a2b3536SDjordje Todorovic if (isFunctionSkipped(F)) 5341a2b3536SDjordje Todorovic continue; 5351a2b3536SDjordje Todorovic 5361a2b3536SDjordje Todorovic // TODO: Collect metadata other than DISubprograms. 5371a2b3536SDjordje Todorovic // Collect the DISubprogram. 5381a2b3536SDjordje Todorovic auto *SP = F.getSubprogram(); 5399f41c03fSDjordje Todorovic DIPreservationAfter[NameOfWrappedPass].DIFunctions.insert( 5409f41c03fSDjordje Todorovic {F.getName(), SP}); 541b9076d11SDjordje Todorovic 542b9076d11SDjordje Todorovic if (SP) { 5431a2b3536SDjordje Todorovic LLVM_DEBUG(dbgs() << " Collecting subprogram: " << *SP << '\n'); 544b9076d11SDjordje Todorovic for (const DINode *DN : SP->getRetainedNodes()) { 545b9076d11SDjordje Todorovic if (const auto *DV = dyn_cast<DILocalVariable>(DN)) { 546b9076d11SDjordje Todorovic DIPreservationAfter[NameOfWrappedPass].DIVariables[DV] = 0; 547b9076d11SDjordje Todorovic } 548b9076d11SDjordje Todorovic } 549b9076d11SDjordje Todorovic } 5501a2b3536SDjordje Todorovic 5511a2b3536SDjordje Todorovic for (BasicBlock &BB : F) { 552b9076d11SDjordje Todorovic // Collect debug locations (!dbg) and debug variable intrinsics. 5531a2b3536SDjordje Todorovic for (Instruction &I : BB) { 5541a2b3536SDjordje Todorovic // Skip PHIs. 5551a2b3536SDjordje Todorovic if (isa<PHINode>(I)) 5561a2b3536SDjordje Todorovic continue; 5571a2b3536SDjordje Todorovic 558b9076d11SDjordje Todorovic // Collect dbg.values and dbg.declares. 559b9076d11SDjordje Todorovic if (auto *DVI = dyn_cast<DbgVariableIntrinsic>(&I)) { 560b9076d11SDjordje Todorovic if (!SP) 561b9076d11SDjordje Todorovic continue; 562b9076d11SDjordje Todorovic // Skip inlined variables. 563b9076d11SDjordje Todorovic if (I.getDebugLoc().getInlinedAt()) 564b9076d11SDjordje Todorovic continue; 565b9076d11SDjordje Todorovic // Skip undef values. 566b9076d11SDjordje Todorovic if (DVI->isUndef()) 567b9076d11SDjordje Todorovic continue; 568b9076d11SDjordje Todorovic 569b9076d11SDjordje Todorovic auto *Var = DVI->getVariable(); 570b9076d11SDjordje Todorovic DIPreservationAfter[NameOfWrappedPass].DIVariables[Var]++; 571b9076d11SDjordje Todorovic continue; 572b9076d11SDjordje Todorovic } 573b9076d11SDjordje Todorovic 574b9076d11SDjordje Todorovic // Skip debug instructions other than dbg.value and dbg.declare. 5751a2b3536SDjordje Todorovic if (isa<DbgInfoIntrinsic>(&I)) 5761a2b3536SDjordje Todorovic continue; 5771a2b3536SDjordje Todorovic 5781a2b3536SDjordje Todorovic LLVM_DEBUG(dbgs() << " Collecting info for inst: " << I << '\n'); 5791a2b3536SDjordje Todorovic 5801a2b3536SDjordje Todorovic const DILocation *Loc = I.getDebugLoc().get(); 5811a2b3536SDjordje Todorovic bool HasLoc = Loc != nullptr; 5821a2b3536SDjordje Todorovic 5831a2b3536SDjordje Todorovic DIPreservationAfter[NameOfWrappedPass].DILocations.insert({&I, HasLoc}); 5841a2b3536SDjordje Todorovic } 5851a2b3536SDjordje Todorovic } 5861a2b3536SDjordje Todorovic } 5871a2b3536SDjordje Todorovic 5881a2b3536SDjordje Todorovic // TODO: The name of the module could be read better? 5891a2b3536SDjordje Todorovic StringRef FileNameFromCU = 5901a2b3536SDjordje Todorovic (cast<DICompileUnit>(M.getNamedMetadata("llvm.dbg.cu")->getOperand(0))) 5911a2b3536SDjordje Todorovic ->getFilename(); 5921a2b3536SDjordje Todorovic 5931a2b3536SDjordje Todorovic auto DIFunctionsBefore = DIPreservationMap[NameOfWrappedPass].DIFunctions; 5941a2b3536SDjordje Todorovic auto DIFunctionsAfter = DIPreservationAfter[NameOfWrappedPass].DIFunctions; 5951a2b3536SDjordje Todorovic 5961a2b3536SDjordje Todorovic auto DILocsBefore = DIPreservationMap[NameOfWrappedPass].DILocations; 5971a2b3536SDjordje Todorovic auto DILocsAfter = DIPreservationAfter[NameOfWrappedPass].DILocations; 5981a2b3536SDjordje Todorovic 5991a2b3536SDjordje Todorovic auto InstToDelete = DIPreservationAfter[NameOfWrappedPass].InstToDelete; 6001a2b3536SDjordje Todorovic 601b9076d11SDjordje Todorovic auto DIVarsBefore = DIPreservationMap[NameOfWrappedPass].DIVariables; 602b9076d11SDjordje Todorovic auto DIVarsAfter = DIPreservationAfter[NameOfWrappedPass].DIVariables; 603b9076d11SDjordje Todorovic 6049f41c03fSDjordje Todorovic bool ShouldWriteIntoJSON = !OrigDIVerifyBugsReportFilePath.empty(); 6059f41c03fSDjordje Todorovic llvm::json::Array Bugs; 6069f41c03fSDjordje Todorovic 6079f41c03fSDjordje Todorovic bool ResultForFunc = 6089f41c03fSDjordje Todorovic checkFunctions(DIFunctionsBefore, DIFunctionsAfter, NameOfWrappedPass, 6099f41c03fSDjordje Todorovic FileNameFromCU, ShouldWriteIntoJSON, Bugs); 6109f41c03fSDjordje Todorovic bool ResultForInsts = checkInstructions( 6119f41c03fSDjordje Todorovic DILocsBefore, DILocsAfter, InstToDelete, NameOfWrappedPass, 6129f41c03fSDjordje Todorovic FileNameFromCU, ShouldWriteIntoJSON, Bugs); 613b9076d11SDjordje Todorovic 614b9076d11SDjordje Todorovic bool ResultForVars = checkVars(DIVarsBefore, DIVarsAfter, NameOfWrappedPass, 615b9076d11SDjordje Todorovic FileNameFromCU, ShouldWriteIntoJSON, Bugs); 616b9076d11SDjordje Todorovic 617b9076d11SDjordje Todorovic bool Result = ResultForFunc && ResultForInsts && ResultForVars; 6181a2b3536SDjordje Todorovic 6191a2b3536SDjordje Todorovic StringRef ResultBanner = NameOfWrappedPass != "" ? NameOfWrappedPass : Banner; 6209f41c03fSDjordje Todorovic if (ShouldWriteIntoJSON && !Bugs.empty()) 6219f41c03fSDjordje Todorovic writeJSON(OrigDIVerifyBugsReportFilePath, FileNameFromCU, NameOfWrappedPass, 6229f41c03fSDjordje Todorovic Bugs); 6239f41c03fSDjordje Todorovic 6241a2b3536SDjordje Todorovic if (Result) 6251a2b3536SDjordje Todorovic dbg() << ResultBanner << ": PASS\n"; 6261a2b3536SDjordje Todorovic else 6271a2b3536SDjordje Todorovic dbg() << ResultBanner << ": FAIL\n"; 6281a2b3536SDjordje Todorovic 6291a2b3536SDjordje Todorovic LLVM_DEBUG(dbgs() << "\n\n"); 6301a2b3536SDjordje Todorovic return Result; 6311a2b3536SDjordje Todorovic } 6321a2b3536SDjordje Todorovic 6331adeeabbSDaniel Sanders namespace { 63425ee8613SDaniel Sanders /// Return true if a mis-sized diagnostic is issued for \p DVI. 63525ee8613SDaniel Sanders bool diagnoseMisSizedDbgValue(Module &M, DbgValueInst *DVI) { 63625ee8613SDaniel Sanders // The size of a dbg.value's value operand should match the size of the 63725ee8613SDaniel Sanders // variable it corresponds to. 63825ee8613SDaniel Sanders // 63925ee8613SDaniel Sanders // TODO: This, along with a check for non-null value operands, should be 64025ee8613SDaniel Sanders // promoted to verifier failures. 64125ee8613SDaniel Sanders 64225ee8613SDaniel Sanders // For now, don't try to interpret anything more complicated than an empty 64325ee8613SDaniel Sanders // DIExpression. Eventually we should try to handle OP_deref and fragments. 64425ee8613SDaniel Sanders if (DVI->getExpression()->getNumElements()) 64525ee8613SDaniel Sanders return false; 64625ee8613SDaniel Sanders 6473bfddc25SStephen Tozer Value *V = DVI->getVariableLocationOp(0); 6483bfddc25SStephen Tozer if (!V) 6493bfddc25SStephen Tozer return false; 6503bfddc25SStephen Tozer 65125ee8613SDaniel Sanders Type *Ty = V->getType(); 65225ee8613SDaniel Sanders uint64_t ValueOperandSize = getAllocSizeInBits(M, Ty); 65325ee8613SDaniel Sanders Optional<uint64_t> DbgVarSize = DVI->getFragmentSizeInBits(); 65425ee8613SDaniel Sanders if (!ValueOperandSize || !DbgVarSize) 65525ee8613SDaniel Sanders return false; 65625ee8613SDaniel Sanders 65725ee8613SDaniel Sanders bool HasBadSize = false; 65825ee8613SDaniel Sanders if (Ty->isIntegerTy()) { 65925ee8613SDaniel Sanders auto Signedness = DVI->getVariable()->getSignedness(); 66025ee8613SDaniel Sanders if (Signedness && *Signedness == DIBasicType::Signedness::Signed) 66125ee8613SDaniel Sanders HasBadSize = ValueOperandSize < *DbgVarSize; 66225ee8613SDaniel Sanders } else { 66325ee8613SDaniel Sanders HasBadSize = ValueOperandSize != *DbgVarSize; 66425ee8613SDaniel Sanders } 66525ee8613SDaniel Sanders 66625ee8613SDaniel Sanders if (HasBadSize) { 66725ee8613SDaniel Sanders dbg() << "ERROR: dbg.value operand has size " << ValueOperandSize 66825ee8613SDaniel Sanders << ", but its variable has size " << *DbgVarSize << ": "; 66925ee8613SDaniel Sanders DVI->print(dbg()); 67025ee8613SDaniel Sanders dbg() << "\n"; 67125ee8613SDaniel Sanders } 67225ee8613SDaniel Sanders return HasBadSize; 67325ee8613SDaniel Sanders } 67425ee8613SDaniel Sanders 67525ee8613SDaniel Sanders bool checkDebugifyMetadata(Module &M, 67625ee8613SDaniel Sanders iterator_range<Module::iterator> Functions, 67725ee8613SDaniel Sanders StringRef NameOfWrappedPass, StringRef Banner, 67825ee8613SDaniel Sanders bool Strip, DebugifyStatsMap *StatsMap) { 67925ee8613SDaniel Sanders // Skip modules without debugify metadata. 68025ee8613SDaniel Sanders NamedMDNode *NMD = M.getNamedMetadata("llvm.debugify"); 68125ee8613SDaniel Sanders if (!NMD) { 68265030821SDjordje Todorovic dbg() << Banner << ": Skipping module without debugify metadata\n"; 68325ee8613SDaniel Sanders return false; 68425ee8613SDaniel Sanders } 68525ee8613SDaniel Sanders 68625ee8613SDaniel Sanders auto getDebugifyOperand = [&](unsigned Idx) -> unsigned { 68725ee8613SDaniel Sanders return mdconst::extract<ConstantInt>(NMD->getOperand(Idx)->getOperand(0)) 68825ee8613SDaniel Sanders ->getZExtValue(); 68925ee8613SDaniel Sanders }; 69025ee8613SDaniel Sanders assert(NMD->getNumOperands() == 2 && 69125ee8613SDaniel Sanders "llvm.debugify should have exactly 2 operands!"); 69225ee8613SDaniel Sanders unsigned OriginalNumLines = getDebugifyOperand(0); 69325ee8613SDaniel Sanders unsigned OriginalNumVars = getDebugifyOperand(1); 69425ee8613SDaniel Sanders bool HasErrors = false; 69525ee8613SDaniel Sanders 69625ee8613SDaniel Sanders // Track debug info loss statistics if able. 69725ee8613SDaniel Sanders DebugifyStatistics *Stats = nullptr; 69825ee8613SDaniel Sanders if (StatsMap && !NameOfWrappedPass.empty()) 69925ee8613SDaniel Sanders Stats = &StatsMap->operator[](NameOfWrappedPass); 70025ee8613SDaniel Sanders 70125ee8613SDaniel Sanders BitVector MissingLines{OriginalNumLines, true}; 70225ee8613SDaniel Sanders BitVector MissingVars{OriginalNumVars, true}; 70325ee8613SDaniel Sanders for (Function &F : Functions) { 70425ee8613SDaniel Sanders if (isFunctionSkipped(F)) 70525ee8613SDaniel Sanders continue; 70625ee8613SDaniel Sanders 70725ee8613SDaniel Sanders // Find missing lines. 70825ee8613SDaniel Sanders for (Instruction &I : instructions(F)) { 70901c90bbdSDjordje Todorovic if (isa<DbgValueInst>(&I)) 71025ee8613SDaniel Sanders continue; 71125ee8613SDaniel Sanders 71225ee8613SDaniel Sanders auto DL = I.getDebugLoc(); 71325ee8613SDaniel Sanders if (DL && DL.getLine() != 0) { 71425ee8613SDaniel Sanders MissingLines.reset(DL.getLine() - 1); 71525ee8613SDaniel Sanders continue; 71625ee8613SDaniel Sanders } 71725ee8613SDaniel Sanders 71801c90bbdSDjordje Todorovic if (!isa<PHINode>(&I) && !DL) { 719c1cad151SVedant Kumar dbg() << "WARNING: Instruction with empty DebugLoc in function "; 72025ee8613SDaniel Sanders dbg() << F.getName() << " --"; 72125ee8613SDaniel Sanders I.print(dbg()); 72225ee8613SDaniel Sanders dbg() << "\n"; 72325ee8613SDaniel Sanders } 72425ee8613SDaniel Sanders } 72525ee8613SDaniel Sanders 72625ee8613SDaniel Sanders // Find missing variables and mis-sized debug values. 72725ee8613SDaniel Sanders for (Instruction &I : instructions(F)) { 72825ee8613SDaniel Sanders auto *DVI = dyn_cast<DbgValueInst>(&I); 72925ee8613SDaniel Sanders if (!DVI) 73025ee8613SDaniel Sanders continue; 73125ee8613SDaniel Sanders 73225ee8613SDaniel Sanders unsigned Var = ~0U; 73325ee8613SDaniel Sanders (void)to_integer(DVI->getVariable()->getName(), Var, 10); 73425ee8613SDaniel Sanders assert(Var <= OriginalNumVars && "Unexpected name for DILocalVariable"); 73525ee8613SDaniel Sanders bool HasBadSize = diagnoseMisSizedDbgValue(M, DVI); 73625ee8613SDaniel Sanders if (!HasBadSize) 73725ee8613SDaniel Sanders MissingVars.reset(Var - 1); 73825ee8613SDaniel Sanders HasErrors |= HasBadSize; 73925ee8613SDaniel Sanders } 74025ee8613SDaniel Sanders } 74125ee8613SDaniel Sanders 74225ee8613SDaniel Sanders // Print the results. 74325ee8613SDaniel Sanders for (unsigned Idx : MissingLines.set_bits()) 74425ee8613SDaniel Sanders dbg() << "WARNING: Missing line " << Idx + 1 << "\n"; 74525ee8613SDaniel Sanders 74625ee8613SDaniel Sanders for (unsigned Idx : MissingVars.set_bits()) 74725ee8613SDaniel Sanders dbg() << "WARNING: Missing variable " << Idx + 1 << "\n"; 74825ee8613SDaniel Sanders 74925ee8613SDaniel Sanders // Update DI loss statistics. 75025ee8613SDaniel Sanders if (Stats) { 75125ee8613SDaniel Sanders Stats->NumDbgLocsExpected += OriginalNumLines; 75225ee8613SDaniel Sanders Stats->NumDbgLocsMissing += MissingLines.count(); 75325ee8613SDaniel Sanders Stats->NumDbgValuesExpected += OriginalNumVars; 75425ee8613SDaniel Sanders Stats->NumDbgValuesMissing += MissingVars.count(); 75525ee8613SDaniel Sanders } 75625ee8613SDaniel Sanders 75725ee8613SDaniel Sanders dbg() << Banner; 75825ee8613SDaniel Sanders if (!NameOfWrappedPass.empty()) 75925ee8613SDaniel Sanders dbg() << " [" << NameOfWrappedPass << "]"; 76025ee8613SDaniel Sanders dbg() << ": " << (HasErrors ? "FAIL" : "PASS") << '\n'; 76125ee8613SDaniel Sanders 762122a6bfbSVedant Kumar // Strip debugify metadata if required. 763122a6bfbSVedant Kumar if (Strip) 764122a6bfbSVedant Kumar return stripDebugifyMetadata(M); 76525ee8613SDaniel Sanders 76625ee8613SDaniel Sanders return false; 76725ee8613SDaniel Sanders } 76825ee8613SDaniel Sanders 76925ee8613SDaniel Sanders /// ModulePass for attaching synthetic debug info to everything, used with the 77025ee8613SDaniel Sanders /// legacy module pass manager. 77125ee8613SDaniel Sanders struct DebugifyModulePass : public ModulePass { 7728ee7c7e0SDjordje Todorovic bool runOnModule(Module &M) override { 7731a2b3536SDjordje Todorovic return applyDebugify(M, Mode, DIPreservationMap, NameOfWrappedPass); 7748ee7c7e0SDjordje Todorovic } 7758ee7c7e0SDjordje Todorovic 7761a2b3536SDjordje Todorovic DebugifyModulePass(enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo, 7771a2b3536SDjordje Todorovic StringRef NameOfWrappedPass = "", 7781a2b3536SDjordje Todorovic DebugInfoPerPassMap *DIPreservationMap = nullptr) 7791a2b3536SDjordje Todorovic : ModulePass(ID), NameOfWrappedPass(NameOfWrappedPass), 7801a2b3536SDjordje Todorovic DIPreservationMap(DIPreservationMap), Mode(Mode) {} 7818ee7c7e0SDjordje Todorovic 7828ee7c7e0SDjordje Todorovic void getAnalysisUsage(AnalysisUsage &AU) const override { 7838ee7c7e0SDjordje Todorovic AU.setPreservesAll(); 7848ee7c7e0SDjordje Todorovic } 7858ee7c7e0SDjordje Todorovic 7868ee7c7e0SDjordje Todorovic static char ID; // Pass identification. 7878ee7c7e0SDjordje Todorovic 7888ee7c7e0SDjordje Todorovic private: 7891a2b3536SDjordje Todorovic StringRef NameOfWrappedPass; 7901a2b3536SDjordje Todorovic DebugInfoPerPassMap *DIPreservationMap; 7911a2b3536SDjordje Todorovic enum DebugifyMode Mode; 7921a2b3536SDjordje Todorovic }; 7931a2b3536SDjordje Todorovic 7941a2b3536SDjordje Todorovic /// FunctionPass for attaching synthetic debug info to instructions within a 7951a2b3536SDjordje Todorovic /// single function, used with the legacy module pass manager. 7961a2b3536SDjordje Todorovic struct DebugifyFunctionPass : public FunctionPass { 7971a2b3536SDjordje Todorovic bool runOnFunction(Function &F) override { 7981a2b3536SDjordje Todorovic return applyDebugify(F, Mode, DIPreservationMap, NameOfWrappedPass); 7991a2b3536SDjordje Todorovic } 8001a2b3536SDjordje Todorovic 8011a2b3536SDjordje Todorovic DebugifyFunctionPass( 8021a2b3536SDjordje Todorovic enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo, 8031a2b3536SDjordje Todorovic StringRef NameOfWrappedPass = "", 8041a2b3536SDjordje Todorovic DebugInfoPerPassMap *DIPreservationMap = nullptr) 8051a2b3536SDjordje Todorovic : FunctionPass(ID), NameOfWrappedPass(NameOfWrappedPass), 8061a2b3536SDjordje Todorovic DIPreservationMap(DIPreservationMap), Mode(Mode) {} 8071a2b3536SDjordje Todorovic 8081a2b3536SDjordje Todorovic void getAnalysisUsage(AnalysisUsage &AU) const override { 8091a2b3536SDjordje Todorovic AU.setPreservesAll(); 8101a2b3536SDjordje Todorovic } 8111a2b3536SDjordje Todorovic 8121a2b3536SDjordje Todorovic static char ID; // Pass identification. 8131a2b3536SDjordje Todorovic 8141a2b3536SDjordje Todorovic private: 8151a2b3536SDjordje Todorovic StringRef NameOfWrappedPass; 8161a2b3536SDjordje Todorovic DebugInfoPerPassMap *DIPreservationMap; 8171a2b3536SDjordje Todorovic enum DebugifyMode Mode; 8181a2b3536SDjordje Todorovic }; 8191a2b3536SDjordje Todorovic 8201a2b3536SDjordje Todorovic /// ModulePass for checking debug info inserted by -debugify, used with the 8211a2b3536SDjordje Todorovic /// legacy module pass manager. 8221a2b3536SDjordje Todorovic struct CheckDebugifyModulePass : public ModulePass { 8231a2b3536SDjordje Todorovic bool runOnModule(Module &M) override { 8241a2b3536SDjordje Todorovic if (Mode == DebugifyMode::SyntheticDebugInfo) 8251a2b3536SDjordje Todorovic return checkDebugifyMetadata(M, M.functions(), NameOfWrappedPass, 8261a2b3536SDjordje Todorovic "CheckModuleDebugify", Strip, StatsMap); 8271a2b3536SDjordje Todorovic return checkDebugInfoMetadata( 8281a2b3536SDjordje Todorovic M, M.functions(), *DIPreservationMap, 8299f41c03fSDjordje Todorovic "CheckModuleDebugify (original debuginfo)", NameOfWrappedPass, 8309f41c03fSDjordje Todorovic OrigDIVerifyBugsReportFilePath); 8311a2b3536SDjordje Todorovic } 8321a2b3536SDjordje Todorovic 8331a2b3536SDjordje Todorovic CheckDebugifyModulePass( 8341a2b3536SDjordje Todorovic bool Strip = false, StringRef NameOfWrappedPass = "", 8351a2b3536SDjordje Todorovic DebugifyStatsMap *StatsMap = nullptr, 8361a2b3536SDjordje Todorovic enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo, 8379f41c03fSDjordje Todorovic DebugInfoPerPassMap *DIPreservationMap = nullptr, 8389f41c03fSDjordje Todorovic StringRef OrigDIVerifyBugsReportFilePath = "") 8391a2b3536SDjordje Todorovic : ModulePass(ID), NameOfWrappedPass(NameOfWrappedPass), 8409f41c03fSDjordje Todorovic OrigDIVerifyBugsReportFilePath(OrigDIVerifyBugsReportFilePath), 8411a2b3536SDjordje Todorovic StatsMap(StatsMap), DIPreservationMap(DIPreservationMap), Mode(Mode), 8421a2b3536SDjordje Todorovic Strip(Strip) {} 8431a2b3536SDjordje Todorovic 8441a2b3536SDjordje Todorovic void getAnalysisUsage(AnalysisUsage &AU) const override { 8451a2b3536SDjordje Todorovic AU.setPreservesAll(); 8461a2b3536SDjordje Todorovic } 8471a2b3536SDjordje Todorovic 8481a2b3536SDjordje Todorovic static char ID; // Pass identification. 8491a2b3536SDjordje Todorovic 8501a2b3536SDjordje Todorovic private: 85125ee8613SDaniel Sanders StringRef NameOfWrappedPass; 8529f41c03fSDjordje Todorovic StringRef OrigDIVerifyBugsReportFilePath; 85325ee8613SDaniel Sanders DebugifyStatsMap *StatsMap; 8541a2b3536SDjordje Todorovic DebugInfoPerPassMap *DIPreservationMap; 8551a2b3536SDjordje Todorovic enum DebugifyMode Mode; 8561a2b3536SDjordje Todorovic bool Strip; 85725ee8613SDaniel Sanders }; 85825ee8613SDaniel Sanders 85925ee8613SDaniel Sanders /// FunctionPass for checking debug info inserted by -debugify-function, used 86025ee8613SDaniel Sanders /// with the legacy module pass manager. 86125ee8613SDaniel Sanders struct CheckDebugifyFunctionPass : public FunctionPass { 86225ee8613SDaniel Sanders bool runOnFunction(Function &F) override { 86325ee8613SDaniel Sanders Module &M = *F.getParent(); 86425ee8613SDaniel Sanders auto FuncIt = F.getIterator(); 8651a2b3536SDjordje Todorovic if (Mode == DebugifyMode::SyntheticDebugInfo) 86625ee8613SDaniel Sanders return checkDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)), 86725ee8613SDaniel Sanders NameOfWrappedPass, "CheckFunctionDebugify", 86825ee8613SDaniel Sanders Strip, StatsMap); 8691a2b3536SDjordje Todorovic return checkDebugInfoMetadata( 8701a2b3536SDjordje Todorovic M, make_range(FuncIt, std::next(FuncIt)), *DIPreservationMap, 8719f41c03fSDjordje Todorovic "CheckFunctionDebugify (original debuginfo)", NameOfWrappedPass, 8729f41c03fSDjordje Todorovic OrigDIVerifyBugsReportFilePath); 87325ee8613SDaniel Sanders } 87425ee8613SDaniel Sanders 8751a2b3536SDjordje Todorovic CheckDebugifyFunctionPass( 8761a2b3536SDjordje Todorovic bool Strip = false, StringRef NameOfWrappedPass = "", 8771a2b3536SDjordje Todorovic DebugifyStatsMap *StatsMap = nullptr, 8781a2b3536SDjordje Todorovic enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo, 8799f41c03fSDjordje Todorovic DebugInfoPerPassMap *DIPreservationMap = nullptr, 8809f41c03fSDjordje Todorovic StringRef OrigDIVerifyBugsReportFilePath = "") 8811a2b3536SDjordje Todorovic : FunctionPass(ID), NameOfWrappedPass(NameOfWrappedPass), 8829f41c03fSDjordje Todorovic OrigDIVerifyBugsReportFilePath(OrigDIVerifyBugsReportFilePath), 8831a2b3536SDjordje Todorovic StatsMap(StatsMap), DIPreservationMap(DIPreservationMap), Mode(Mode), 8841a2b3536SDjordje Todorovic Strip(Strip) {} 88525ee8613SDaniel Sanders 88625ee8613SDaniel Sanders void getAnalysisUsage(AnalysisUsage &AU) const override { 88725ee8613SDaniel Sanders AU.setPreservesAll(); 88825ee8613SDaniel Sanders } 88925ee8613SDaniel Sanders 89025ee8613SDaniel Sanders static char ID; // Pass identification. 89125ee8613SDaniel Sanders 89225ee8613SDaniel Sanders private: 89325ee8613SDaniel Sanders StringRef NameOfWrappedPass; 8949f41c03fSDjordje Todorovic StringRef OrigDIVerifyBugsReportFilePath; 89525ee8613SDaniel Sanders DebugifyStatsMap *StatsMap; 8961a2b3536SDjordje Todorovic DebugInfoPerPassMap *DIPreservationMap; 8971a2b3536SDjordje Todorovic enum DebugifyMode Mode; 8981a2b3536SDjordje Todorovic bool Strip; 89925ee8613SDaniel Sanders }; 90025ee8613SDaniel Sanders 90125ee8613SDaniel Sanders } // end anonymous namespace 90225ee8613SDaniel Sanders 90339856d5dSFangrui Song void llvm::exportDebugifyStats(StringRef Path, const DebugifyStatsMap &Map) { 90439856d5dSFangrui Song std::error_code EC; 90539856d5dSFangrui Song raw_fd_ostream OS{Path, EC}; 90639856d5dSFangrui Song if (EC) { 90739856d5dSFangrui Song errs() << "Could not open file: " << EC.message() << ", " << Path << '\n'; 90839856d5dSFangrui Song return; 90939856d5dSFangrui Song } 91025ee8613SDaniel Sanders 91139856d5dSFangrui Song OS << "Pass Name" << ',' << "# of missing debug values" << ',' 91239856d5dSFangrui Song << "# of missing locations" << ',' << "Missing/Expected value ratio" << ',' 91339856d5dSFangrui Song << "Missing/Expected location ratio" << '\n'; 91439856d5dSFangrui Song for (const auto &Entry : Map) { 91539856d5dSFangrui Song StringRef Pass = Entry.first; 91639856d5dSFangrui Song DebugifyStatistics Stats = Entry.second; 91739856d5dSFangrui Song 91839856d5dSFangrui Song OS << Pass << ',' << Stats.NumDbgValuesMissing << ',' 91939856d5dSFangrui Song << Stats.NumDbgLocsMissing << ',' << Stats.getMissingValueRatio() << ',' 92039856d5dSFangrui Song << Stats.getEmptyLocationRatio() << '\n'; 92139856d5dSFangrui Song } 92239856d5dSFangrui Song } 92339856d5dSFangrui Song 9241a2b3536SDjordje Todorovic ModulePass *createDebugifyModulePass(enum DebugifyMode Mode, 9251a2b3536SDjordje Todorovic llvm::StringRef NameOfWrappedPass, 9261a2b3536SDjordje Todorovic DebugInfoPerPassMap *DIPreservationMap) { 9271a2b3536SDjordje Todorovic if (Mode == DebugifyMode::SyntheticDebugInfo) 92839856d5dSFangrui Song return new DebugifyModulePass(); 9291a2b3536SDjordje Todorovic assert(Mode == DebugifyMode::OriginalDebugInfo && "Must be original mode"); 9301a2b3536SDjordje Todorovic return new DebugifyModulePass(Mode, NameOfWrappedPass, DIPreservationMap); 93139856d5dSFangrui Song } 93239856d5dSFangrui Song 9331a2b3536SDjordje Todorovic FunctionPass * 9341a2b3536SDjordje Todorovic createDebugifyFunctionPass(enum DebugifyMode Mode, 9351a2b3536SDjordje Todorovic llvm::StringRef NameOfWrappedPass, 9361a2b3536SDjordje Todorovic DebugInfoPerPassMap *DIPreservationMap) { 9371a2b3536SDjordje Todorovic if (Mode == DebugifyMode::SyntheticDebugInfo) 93825ee8613SDaniel Sanders return new DebugifyFunctionPass(); 9391a2b3536SDjordje Todorovic assert(Mode == DebugifyMode::OriginalDebugInfo && "Must be original mode"); 9401a2b3536SDjordje Todorovic return new DebugifyFunctionPass(Mode, NameOfWrappedPass, DIPreservationMap); 94125ee8613SDaniel Sanders } 94225ee8613SDaniel Sanders 94325ee8613SDaniel Sanders PreservedAnalyses NewPMDebugifyPass::run(Module &M, ModuleAnalysisManager &) { 9441adeeabbSDaniel Sanders applyDebugifyMetadata(M, M.functions(), 9451adeeabbSDaniel Sanders "ModuleDebugify: ", /*ApplyToMF*/ nullptr); 94625ee8613SDaniel Sanders return PreservedAnalyses::all(); 94725ee8613SDaniel Sanders } 94825ee8613SDaniel Sanders 9491a2b3536SDjordje Todorovic ModulePass *createCheckDebugifyModulePass( 9501a2b3536SDjordje Todorovic bool Strip, StringRef NameOfWrappedPass, DebugifyStatsMap *StatsMap, 9519f41c03fSDjordje Todorovic enum DebugifyMode Mode, DebugInfoPerPassMap *DIPreservationMap, 9529f41c03fSDjordje Todorovic StringRef OrigDIVerifyBugsReportFilePath) { 9531a2b3536SDjordje Todorovic if (Mode == DebugifyMode::SyntheticDebugInfo) 95425ee8613SDaniel Sanders return new CheckDebugifyModulePass(Strip, NameOfWrappedPass, StatsMap); 9551a2b3536SDjordje Todorovic assert(Mode == DebugifyMode::OriginalDebugInfo && "Must be original mode"); 9561a2b3536SDjordje Todorovic return new CheckDebugifyModulePass(false, NameOfWrappedPass, nullptr, Mode, 9579f41c03fSDjordje Todorovic DIPreservationMap, 9589f41c03fSDjordje Todorovic OrigDIVerifyBugsReportFilePath); 95925ee8613SDaniel Sanders } 96025ee8613SDaniel Sanders 9611a2b3536SDjordje Todorovic FunctionPass *createCheckDebugifyFunctionPass( 9621a2b3536SDjordje Todorovic bool Strip, StringRef NameOfWrappedPass, DebugifyStatsMap *StatsMap, 9639f41c03fSDjordje Todorovic enum DebugifyMode Mode, DebugInfoPerPassMap *DIPreservationMap, 9649f41c03fSDjordje Todorovic StringRef OrigDIVerifyBugsReportFilePath) { 9651a2b3536SDjordje Todorovic if (Mode == DebugifyMode::SyntheticDebugInfo) 96625ee8613SDaniel Sanders return new CheckDebugifyFunctionPass(Strip, NameOfWrappedPass, StatsMap); 9671a2b3536SDjordje Todorovic assert(Mode == DebugifyMode::OriginalDebugInfo && "Must be original mode"); 9681a2b3536SDjordje Todorovic return new CheckDebugifyFunctionPass(false, NameOfWrappedPass, nullptr, Mode, 9699f41c03fSDjordje Todorovic DIPreservationMap, 9709f41c03fSDjordje Todorovic OrigDIVerifyBugsReportFilePath); 97125ee8613SDaniel Sanders } 97225ee8613SDaniel Sanders 97325ee8613SDaniel Sanders PreservedAnalyses NewPMCheckDebugifyPass::run(Module &M, 97425ee8613SDaniel Sanders ModuleAnalysisManager &) { 97525ee8613SDaniel Sanders checkDebugifyMetadata(M, M.functions(), "", "CheckModuleDebugify", false, 97625ee8613SDaniel Sanders nullptr); 97725ee8613SDaniel Sanders return PreservedAnalyses::all(); 97825ee8613SDaniel Sanders } 97925ee8613SDaniel Sanders 9807de6dcd2SArthur Eubanks static bool isIgnoredPass(StringRef PassID) { 9817de6dcd2SArthur Eubanks return isSpecialPass(PassID, {"PassManager", "PassAdaptor", 9827de6dcd2SArthur Eubanks "AnalysisManagerProxy", "PrintFunctionPass", 9837de6dcd2SArthur Eubanks "PrintModulePass", "BitcodeWriterPass", 9847de6dcd2SArthur Eubanks "ThinLTOBitcodeWriterPass", "VerifierPass"}); 9857de6dcd2SArthur Eubanks } 9867de6dcd2SArthur Eubanks 98798b93385SFangrui Song void DebugifyEachInstrumentation::registerCallbacks( 98898b93385SFangrui Song PassInstrumentationCallbacks &PIC) { 98998b93385SFangrui Song PIC.registerBeforeNonSkippedPassCallback([](StringRef P, Any IR) { 9907de6dcd2SArthur Eubanks if (isIgnoredPass(P)) 9917de6dcd2SArthur Eubanks return; 99298b93385SFangrui Song if (any_isa<const Function *>(IR)) 99398b93385SFangrui Song applyDebugify(*const_cast<Function *>(any_cast<const Function *>(IR))); 99498b93385SFangrui Song else if (any_isa<const Module *>(IR)) 99598b93385SFangrui Song applyDebugify(*const_cast<Module *>(any_cast<const Module *>(IR))); 99698b93385SFangrui Song }); 99798b93385SFangrui Song PIC.registerAfterPassCallback([this](StringRef P, Any IR, 99898b93385SFangrui Song const PreservedAnalyses &PassPA) { 9997de6dcd2SArthur Eubanks if (isIgnoredPass(P)) 10007de6dcd2SArthur Eubanks return; 100198b93385SFangrui Song if (any_isa<const Function *>(IR)) { 100298b93385SFangrui Song auto &F = *const_cast<Function *>(any_cast<const Function *>(IR)); 100398b93385SFangrui Song Module &M = *F.getParent(); 100498b93385SFangrui Song auto It = F.getIterator(); 100598b93385SFangrui Song checkDebugifyMetadata(M, make_range(It, std::next(It)), P, 100698b93385SFangrui Song "CheckFunctionDebugify", /*Strip=*/true, &StatsMap); 100798b93385SFangrui Song } else if (any_isa<const Module *>(IR)) { 100898b93385SFangrui Song auto &M = *const_cast<Module *>(any_cast<const Module *>(IR)); 100998b93385SFangrui Song checkDebugifyMetadata(M, M.functions(), P, "CheckModuleDebugify", 101098b93385SFangrui Song /*Strip=*/true, &StatsMap); 101198b93385SFangrui Song } 101298b93385SFangrui Song }); 101398b93385SFangrui Song } 101498b93385SFangrui Song 101525ee8613SDaniel Sanders char DebugifyModulePass::ID = 0; 101625ee8613SDaniel Sanders static RegisterPass<DebugifyModulePass> DM("debugify", 101725ee8613SDaniel Sanders "Attach debug info to everything"); 101825ee8613SDaniel Sanders 101925ee8613SDaniel Sanders char CheckDebugifyModulePass::ID = 0; 102025ee8613SDaniel Sanders static RegisterPass<CheckDebugifyModulePass> 102125ee8613SDaniel Sanders CDM("check-debugify", "Check debug info from -debugify"); 102225ee8613SDaniel Sanders 102325ee8613SDaniel Sanders char DebugifyFunctionPass::ID = 0; 102425ee8613SDaniel Sanders static RegisterPass<DebugifyFunctionPass> DF("debugify-function", 102525ee8613SDaniel Sanders "Attach debug info to a function"); 102625ee8613SDaniel Sanders 102725ee8613SDaniel Sanders char CheckDebugifyFunctionPass::ID = 0; 102825ee8613SDaniel Sanders static RegisterPass<CheckDebugifyFunctionPass> 102925ee8613SDaniel Sanders CDF("check-debugify-function", "Check debug info from -debugify-function"); 1030