Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 1 | //===- Debugify.cpp - Attach synthetic debug info to everything -----------===// |
| 2 | // |
Chandler Carruth | 2946cd7 | 2019-01-19 08:50:56 +0000 | [diff] [blame] | 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 |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | /// |
| 9 | /// \file This pass attaches synthetic debug info to everything. It can be used |
| 10 | /// to create targeted tests for debug info preservation. |
| 11 | /// |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
Reid Kleckner | 4c1a1d3 | 2019-11-14 15:15:48 -0800 | [diff] [blame] | 14 | #include "llvm/Transforms/Utils/Debugify.h" |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 15 | #include "llvm/ADT/BitVector.h" |
| 16 | #include "llvm/ADT/StringExtras.h" |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 17 | #include "llvm/IR/DIBuilder.h" |
| 18 | #include "llvm/IR/DebugInfo.h" |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 19 | #include "llvm/IR/InstIterator.h" |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 20 | #include "llvm/IR/Instructions.h" |
| 21 | #include "llvm/IR/IntrinsicInst.h" |
Simon Pilgrim | 0128b95 | 2020-07-24 13:02:33 +0100 | [diff] [blame] | 22 | #include "llvm/IR/Module.h" |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 23 | #include "llvm/Pass.h" |
Reid Kleckner | 4c1a1d3 | 2019-11-14 15:15:48 -0800 | [diff] [blame] | 24 | #include "llvm/Support/CommandLine.h" |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 25 | |
| 26 | using namespace llvm; |
| 27 | |
| 28 | namespace { |
| 29 | |
Vedant Kumar | a9e2731 | 2018-06-06 19:05:41 +0000 | [diff] [blame] | 30 | cl::opt<bool> Quiet("debugify-quiet", |
| 31 | cl::desc("Suppress verbose debugify output")); |
| 32 | |
Daniel Sanders | 15f7bc7 | 2020-04-03 15:50:11 -0700 | [diff] [blame] | 33 | enum class Level { |
| 34 | Locations, |
| 35 | LocationsAndVariables |
| 36 | }; |
| 37 | cl::opt<Level> DebugifyLevel( |
| 38 | "debugify-level", cl::desc("Kind of debug info to add"), |
| 39 | cl::values(clEnumValN(Level::Locations, "locations", "Locations only"), |
| 40 | clEnumValN(Level::LocationsAndVariables, "location+variables", |
| 41 | "Locations and Variables")), |
| 42 | cl::init(Level::LocationsAndVariables)); |
| 43 | |
Vedant Kumar | a9e2731 | 2018-06-06 19:05:41 +0000 | [diff] [blame] | 44 | raw_ostream &dbg() { return Quiet ? nulls() : errs(); } |
| 45 | |
Vedant Kumar | b9c1a23 | 2018-06-26 22:46:41 +0000 | [diff] [blame] | 46 | uint64_t getAllocSizeInBits(Module &M, Type *Ty) { |
| 47 | return Ty->isSized() ? M.getDataLayout().getTypeAllocSizeInBits(Ty) : 0; |
| 48 | } |
| 49 | |
Vedant Kumar | 17d8bba | 2018-02-15 21:28:38 +0000 | [diff] [blame] | 50 | bool isFunctionSkipped(Function &F) { |
| 51 | return F.isDeclaration() || !F.hasExactDefinition(); |
| 52 | } |
| 53 | |
Vedant Kumar | 6d354ed | 2018-06-06 19:05:42 +0000 | [diff] [blame] | 54 | /// Find the basic block's terminating instruction. |
Vedant Kumar | 800255f | 2018-06-05 00:56:07 +0000 | [diff] [blame] | 55 | /// |
Vedant Kumar | 6d354ed | 2018-06-06 19:05:42 +0000 | [diff] [blame] | 56 | /// Special care is needed to handle musttail and deopt calls, as these behave |
| 57 | /// like (but are in fact not) terminators. |
| 58 | Instruction *findTerminatingInstruction(BasicBlock &BB) { |
Vedant Kumar | 800255f | 2018-06-05 00:56:07 +0000 | [diff] [blame] | 59 | if (auto *I = BB.getTerminatingMustTailCall()) |
| 60 | return I; |
| 61 | if (auto *I = BB.getTerminatingDeoptimizeCall()) |
| 62 | return I; |
| 63 | return BB.getTerminator(); |
| 64 | } |
Daniel Sanders | 1adeeab | 2020-04-03 16:18:45 -0700 | [diff] [blame] | 65 | } // end anonymous namespace |
Vedant Kumar | 800255f | 2018-06-05 00:56:07 +0000 | [diff] [blame] | 66 | |
Daniel Sanders | 1adeeab | 2020-04-03 16:18:45 -0700 | [diff] [blame] | 67 | bool llvm::applyDebugifyMetadata( |
| 68 | Module &M, iterator_range<Module::iterator> Functions, StringRef Banner, |
| 69 | std::function<bool(DIBuilder &DIB, Function &F)> ApplyToMF) { |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 70 | // Skip modules with debug info. |
| 71 | if (M.getNamedMetadata("llvm.dbg.cu")) { |
Vedant Kumar | a9e2731 | 2018-06-06 19:05:41 +0000 | [diff] [blame] | 72 | dbg() << Banner << "Skipping module with debug info\n"; |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 73 | return false; |
| 74 | } |
| 75 | |
| 76 | DIBuilder DIB(M); |
| 77 | LLVMContext &Ctx = M.getContext(); |
Vedant Kumar | 2a5675f | 2020-04-13 16:15:37 -0700 | [diff] [blame] | 78 | auto *Int32Ty = Type::getInt32Ty(Ctx); |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 79 | |
| 80 | // Get a DIType which corresponds to Ty. |
| 81 | DenseMap<uint64_t, DIType *> TypeCache; |
| 82 | auto getCachedDIType = [&](Type *Ty) -> DIType * { |
Vedant Kumar | b9c1a23 | 2018-06-26 22:46:41 +0000 | [diff] [blame] | 83 | uint64_t Size = getAllocSizeInBits(M, Ty); |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 84 | DIType *&DTy = TypeCache[Size]; |
| 85 | if (!DTy) { |
| 86 | std::string Name = "ty" + utostr(Size); |
| 87 | DTy = DIB.createBasicType(Name, Size, dwarf::DW_ATE_unsigned); |
| 88 | } |
| 89 | return DTy; |
| 90 | }; |
| 91 | |
| 92 | unsigned NextLine = 1; |
| 93 | unsigned NextVar = 1; |
| 94 | auto File = DIB.createFile(M.getName(), "/"); |
Vedant Kumar | ab112b8 | 2018-06-05 00:56:07 +0000 | [diff] [blame] | 95 | auto CU = DIB.createCompileUnit(dwarf::DW_LANG_C, File, "debugify", |
| 96 | /*isOptimized=*/true, "", 0); |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 97 | |
| 98 | // Visit each instruction. |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 99 | for (Function &F : Functions) { |
Vedant Kumar | 17d8bba | 2018-02-15 21:28:38 +0000 | [diff] [blame] | 100 | if (isFunctionSkipped(F)) |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 101 | continue; |
| 102 | |
Vedant Kumar | 2a5675f | 2020-04-13 16:15:37 -0700 | [diff] [blame] | 103 | bool InsertedDbgVal = false; |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 104 | auto SPType = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None)); |
Paul Robinson | cda5421 | 2018-11-19 18:29:28 +0000 | [diff] [blame] | 105 | DISubprogram::DISPFlags SPFlags = |
| 106 | DISubprogram::SPFlagDefinition | DISubprogram::SPFlagOptimized; |
| 107 | if (F.hasPrivateLinkage() || F.hasInternalLinkage()) |
| 108 | SPFlags |= DISubprogram::SPFlagLocalToUnit; |
| 109 | auto SP = DIB.createFunction(CU, F.getName(), F.getName(), File, NextLine, |
| 110 | SPType, NextLine, DINode::FlagZero, SPFlags); |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 111 | F.setSubprogram(SP); |
Vedant Kumar | 2a5675f | 2020-04-13 16:15:37 -0700 | [diff] [blame] | 112 | |
| 113 | // Helper that inserts a dbg.value before \p InsertBefore, copying the |
| 114 | // location (and possibly the type, if it's non-void) from \p TemplateInst. |
| 115 | auto insertDbgVal = [&](Instruction &TemplateInst, |
| 116 | Instruction *InsertBefore) { |
| 117 | std::string Name = utostr(NextVar++); |
| 118 | Value *V = &TemplateInst; |
| 119 | if (TemplateInst.getType()->isVoidTy()) |
| 120 | V = ConstantInt::get(Int32Ty, 0); |
| 121 | const DILocation *Loc = TemplateInst.getDebugLoc().get(); |
| 122 | auto LocalVar = DIB.createAutoVariable(SP, Name, File, Loc->getLine(), |
| 123 | getCachedDIType(V->getType()), |
| 124 | /*AlwaysPreserve=*/true); |
| 125 | DIB.insertDbgValueIntrinsic(V, LocalVar, DIB.createExpression(), Loc, |
| 126 | InsertBefore); |
| 127 | }; |
| 128 | |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 129 | for (BasicBlock &BB : F) { |
| 130 | // Attach debug locations. |
| 131 | for (Instruction &I : BB) |
| 132 | I.setDebugLoc(DILocation::get(Ctx, NextLine++, 1, SP)); |
| 133 | |
Daniel Sanders | 15f7bc7 | 2020-04-03 15:50:11 -0700 | [diff] [blame] | 134 | if (DebugifyLevel < Level::LocationsAndVariables) |
| 135 | continue; |
| 136 | |
Vedant Kumar | 77f4d4d | 2018-06-03 22:50:22 +0000 | [diff] [blame] | 137 | // Inserting debug values into EH pads can break IR invariants. |
| 138 | if (BB.isEHPad()) |
| 139 | continue; |
| 140 | |
Vedant Kumar | 6d354ed | 2018-06-06 19:05:42 +0000 | [diff] [blame] | 141 | // Find the terminating instruction, after which no debug values are |
| 142 | // attached. |
| 143 | Instruction *LastInst = findTerminatingInstruction(BB); |
| 144 | assert(LastInst && "Expected basic block with a terminator"); |
| 145 | |
| 146 | // Maintain an insertion point which can't be invalidated when updates |
| 147 | // are made. |
| 148 | BasicBlock::iterator InsertPt = BB.getFirstInsertionPt(); |
| 149 | assert(InsertPt != BB.end() && "Expected to find an insertion point"); |
| 150 | Instruction *InsertBefore = &*InsertPt; |
Vedant Kumar | 7dda221 | 2018-06-04 03:33:01 +0000 | [diff] [blame] | 151 | |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 152 | // Attach debug values. |
Vedant Kumar | 6d354ed | 2018-06-06 19:05:42 +0000 | [diff] [blame] | 153 | for (Instruction *I = &*BB.begin(); I != LastInst; I = I->getNextNode()) { |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 154 | // Skip void-valued instructions. |
Vedant Kumar | 6d354ed | 2018-06-06 19:05:42 +0000 | [diff] [blame] | 155 | if (I->getType()->isVoidTy()) |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 156 | continue; |
| 157 | |
Vedant Kumar | 6d354ed | 2018-06-06 19:05:42 +0000 | [diff] [blame] | 158 | // Phis and EH pads must be grouped at the beginning of the block. |
| 159 | // Only advance the insertion point when we finish visiting these. |
| 160 | if (!isa<PHINode>(I) && !I->isEHPad()) |
| 161 | InsertBefore = I->getNextNode(); |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 162 | |
Vedant Kumar | 2a5675f | 2020-04-13 16:15:37 -0700 | [diff] [blame] | 163 | insertDbgVal(*I, InsertBefore); |
| 164 | InsertedDbgVal = true; |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 165 | } |
| 166 | } |
Vedant Kumar | 2a5675f | 2020-04-13 16:15:37 -0700 | [diff] [blame] | 167 | // Make sure we emit at least one dbg.value, otherwise MachineDebugify may |
| 168 | // not have anything to work with as it goes about inserting DBG_VALUEs. |
| 169 | // (It's common for MIR tests to be written containing skeletal IR with |
| 170 | // empty functions -- we're still interested in debugifying the MIR within |
| 171 | // those tests, and this helps with that.) |
| 172 | if (DebugifyLevel == Level::LocationsAndVariables && !InsertedDbgVal) { |
| 173 | auto *Term = findTerminatingInstruction(F.getEntryBlock()); |
| 174 | insertDbgVal(*Term, Term); |
| 175 | } |
Daniel Sanders | 1adeeab | 2020-04-03 16:18:45 -0700 | [diff] [blame] | 176 | if (ApplyToMF) |
| 177 | ApplyToMF(DIB, F); |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 178 | DIB.finalizeSubprogram(SP); |
| 179 | } |
| 180 | DIB.finalize(); |
| 181 | |
| 182 | // Track the number of distinct lines and variables. |
| 183 | NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.debugify"); |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 184 | auto addDebugifyOperand = [&](unsigned N) { |
| 185 | NMD->addOperand(MDNode::get( |
Vedant Kumar | 2a5675f | 2020-04-13 16:15:37 -0700 | [diff] [blame] | 186 | Ctx, ValueAsMetadata::getConstant(ConstantInt::get(Int32Ty, N)))); |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 187 | }; |
| 188 | addDebugifyOperand(NextLine - 1); // Original number of lines. |
| 189 | addDebugifyOperand(NextVar - 1); // Original number of variables. |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 190 | assert(NMD->getNumOperands() == 2 && |
| 191 | "llvm.debugify should have exactly 2 operands!"); |
Vedant Kumar | 4872535e | 2018-05-24 23:00:23 +0000 | [diff] [blame] | 192 | |
| 193 | // Claim that this synthetic debug info is valid. |
| 194 | StringRef DIVersionKey = "Debug Info Version"; |
| 195 | if (!M.getModuleFlag(DIVersionKey)) |
| 196 | M.addModuleFlag(Module::Warning, DIVersionKey, DEBUG_METADATA_VERSION); |
| 197 | |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 198 | return true; |
| 199 | } |
| 200 | |
Vedant Kumar | 122a6bf | 2020-04-10 14:58:13 -0700 | [diff] [blame] | 201 | bool llvm::stripDebugifyMetadata(Module &M) { |
| 202 | bool Changed = false; |
| 203 | |
| 204 | // Remove the llvm.debugify module-level named metadata. |
| 205 | NamedMDNode *DebugifyMD = M.getNamedMetadata("llvm.debugify"); |
| 206 | if (DebugifyMD) { |
| 207 | M.eraseNamedMetadata(DebugifyMD); |
| 208 | Changed = true; |
| 209 | } |
| 210 | |
| 211 | // Strip out all debug intrinsics and supporting metadata (subprograms, types, |
| 212 | // variables, etc). |
| 213 | Changed |= StripDebugInfo(M); |
| 214 | |
| 215 | // Strip out the dead dbg.value prototype. |
| 216 | Function *DbgValF = M.getFunction("llvm.dbg.value"); |
| 217 | if (DbgValF) { |
| 218 | assert(DbgValF->isDeclaration() && DbgValF->use_empty() && |
| 219 | "Not all debug info stripped?"); |
| 220 | DbgValF->eraseFromParent(); |
| 221 | Changed = true; |
| 222 | } |
| 223 | |
| 224 | // Strip out the module-level Debug Info Version metadata. |
| 225 | // FIXME: There must be an easier way to remove an operand from a NamedMDNode. |
| 226 | NamedMDNode *NMD = M.getModuleFlagsMetadata(); |
Vedant Kumar | 2fa656c | 2020-04-17 17:53:14 -0700 | [diff] [blame] | 227 | if (!NMD) |
| 228 | return Changed; |
Vedant Kumar | 122a6bf | 2020-04-10 14:58:13 -0700 | [diff] [blame] | 229 | SmallVector<MDNode *, 4> Flags; |
| 230 | for (MDNode *Flag : NMD->operands()) |
| 231 | Flags.push_back(Flag); |
| 232 | NMD->clearOperands(); |
| 233 | for (MDNode *Flag : Flags) { |
| 234 | MDString *Key = dyn_cast_or_null<MDString>(Flag->getOperand(1)); |
| 235 | if (Key->getString() == "Debug Info Version") { |
| 236 | Changed = true; |
| 237 | continue; |
| 238 | } |
| 239 | NMD->addOperand(Flag); |
| 240 | } |
| 241 | // If we left it empty we might as well remove it. |
| 242 | if (NMD->getNumOperands() == 0) |
| 243 | NMD->eraseFromParent(); |
| 244 | |
| 245 | return Changed; |
| 246 | } |
| 247 | |
Daniel Sanders | 1adeeab | 2020-04-03 16:18:45 -0700 | [diff] [blame] | 248 | namespace { |
Vedant Kumar | b9c1a23 | 2018-06-26 22:46:41 +0000 | [diff] [blame] | 249 | /// Return true if a mis-sized diagnostic is issued for \p DVI. |
| 250 | bool diagnoseMisSizedDbgValue(Module &M, DbgValueInst *DVI) { |
| 251 | // The size of a dbg.value's value operand should match the size of the |
| 252 | // variable it corresponds to. |
| 253 | // |
| 254 | // TODO: This, along with a check for non-null value operands, should be |
| 255 | // promoted to verifier failures. |
| 256 | Value *V = DVI->getValue(); |
| 257 | if (!V) |
| 258 | return false; |
| 259 | |
| 260 | // For now, don't try to interpret anything more complicated than an empty |
| 261 | // DIExpression. Eventually we should try to handle OP_deref and fragments. |
| 262 | if (DVI->getExpression()->getNumElements()) |
| 263 | return false; |
| 264 | |
| 265 | Type *Ty = V->getType(); |
| 266 | uint64_t ValueOperandSize = getAllocSizeInBits(M, Ty); |
Vedant Kumar | d13536e | 2018-06-27 00:47:52 +0000 | [diff] [blame] | 267 | Optional<uint64_t> DbgVarSize = DVI->getFragmentSizeInBits(); |
| 268 | if (!ValueOperandSize || !DbgVarSize) |
| 269 | return false; |
| 270 | |
Vedant Kumar | ba0c876 | 2018-07-06 17:32:40 +0000 | [diff] [blame] | 271 | bool HasBadSize = false; |
| 272 | if (Ty->isIntegerTy()) { |
| 273 | auto Signedness = DVI->getVariable()->getSignedness(); |
| 274 | if (Signedness && *Signedness == DIBasicType::Signedness::Signed) |
| 275 | HasBadSize = ValueOperandSize < *DbgVarSize; |
| 276 | } else { |
| 277 | HasBadSize = ValueOperandSize != *DbgVarSize; |
| 278 | } |
| 279 | |
Vedant Kumar | b9c1a23 | 2018-06-26 22:46:41 +0000 | [diff] [blame] | 280 | if (HasBadSize) { |
| 281 | dbg() << "ERROR: dbg.value operand has size " << ValueOperandSize |
Vedant Kumar | d13536e | 2018-06-27 00:47:52 +0000 | [diff] [blame] | 282 | << ", but its variable has size " << *DbgVarSize << ": "; |
Vedant Kumar | b9c1a23 | 2018-06-26 22:46:41 +0000 | [diff] [blame] | 283 | DVI->print(dbg()); |
| 284 | dbg() << "\n"; |
| 285 | } |
| 286 | return HasBadSize; |
| 287 | } |
| 288 | |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 289 | bool checkDebugifyMetadata(Module &M, |
| 290 | iterator_range<Module::iterator> Functions, |
Vedant Kumar | ab112b8 | 2018-06-05 00:56:07 +0000 | [diff] [blame] | 291 | StringRef NameOfWrappedPass, StringRef Banner, |
Vedant Kumar | d6ff43c | 2018-07-24 00:41:29 +0000 | [diff] [blame] | 292 | bool Strip, DebugifyStatsMap *StatsMap) { |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 293 | // Skip modules without debugify metadata. |
| 294 | NamedMDNode *NMD = M.getNamedMetadata("llvm.debugify"); |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 295 | if (!NMD) { |
Djordje Todorovic | 6503082 | 2020-05-27 09:42:15 +0200 | [diff] [blame] | 296 | dbg() << Banner << ": Skipping module without debugify metadata\n"; |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 297 | return false; |
| 298 | } |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 299 | |
| 300 | auto getDebugifyOperand = [&](unsigned Idx) -> unsigned { |
| 301 | return mdconst::extract<ConstantInt>(NMD->getOperand(Idx)->getOperand(0)) |
| 302 | ->getZExtValue(); |
| 303 | }; |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 304 | assert(NMD->getNumOperands() == 2 && |
| 305 | "llvm.debugify should have exactly 2 operands!"); |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 306 | unsigned OriginalNumLines = getDebugifyOperand(0); |
| 307 | unsigned OriginalNumVars = getDebugifyOperand(1); |
| 308 | bool HasErrors = false; |
| 309 | |
Vedant Kumar | d6ff43c | 2018-07-24 00:41:29 +0000 | [diff] [blame] | 310 | // Track debug info loss statistics if able. |
| 311 | DebugifyStatistics *Stats = nullptr; |
| 312 | if (StatsMap && !NameOfWrappedPass.empty()) |
| 313 | Stats = &StatsMap->operator[](NameOfWrappedPass); |
| 314 | |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 315 | BitVector MissingLines{OriginalNumLines, true}; |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 316 | BitVector MissingVars{OriginalNumVars, true}; |
| 317 | for (Function &F : Functions) { |
Vedant Kumar | 17d8bba | 2018-02-15 21:28:38 +0000 | [diff] [blame] | 318 | if (isFunctionSkipped(F)) |
| 319 | continue; |
| 320 | |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 321 | // Find missing lines. |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 322 | for (Instruction &I : instructions(F)) { |
Pierre-vh | f64e457 | 2020-02-27 12:32:51 +0000 | [diff] [blame] | 323 | if (isa<DbgValueInst>(&I) || isa<PHINode>(&I)) |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 324 | continue; |
| 325 | |
| 326 | auto DL = I.getDebugLoc(); |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 327 | if (DL && DL.getLine() != 0) { |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 328 | MissingLines.reset(DL.getLine() - 1); |
| 329 | continue; |
| 330 | } |
| 331 | |
Vedant Kumar | 197e73f | 2018-06-28 18:21:11 +0000 | [diff] [blame] | 332 | if (!DL) { |
Vedant Kumar | c1cad15 | 2020-06-18 14:17:07 -0700 | [diff] [blame] | 333 | dbg() << "WARNING: Instruction with empty DebugLoc in function "; |
Vedant Kumar | 197e73f | 2018-06-28 18:21:11 +0000 | [diff] [blame] | 334 | dbg() << F.getName() << " --"; |
| 335 | I.print(dbg()); |
| 336 | dbg() << "\n"; |
Vedant Kumar | 197e73f | 2018-06-28 18:21:11 +0000 | [diff] [blame] | 337 | } |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 338 | } |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 339 | |
Vedant Kumar | b9c1a23 | 2018-06-26 22:46:41 +0000 | [diff] [blame] | 340 | // Find missing variables and mis-sized debug values. |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 341 | for (Instruction &I : instructions(F)) { |
| 342 | auto *DVI = dyn_cast<DbgValueInst>(&I); |
| 343 | if (!DVI) |
| 344 | continue; |
| 345 | |
| 346 | unsigned Var = ~0U; |
| 347 | (void)to_integer(DVI->getVariable()->getName(), Var, 10); |
| 348 | assert(Var <= OriginalNumVars && "Unexpected name for DILocalVariable"); |
Vedant Kumar | b9c1a23 | 2018-06-26 22:46:41 +0000 | [diff] [blame] | 349 | bool HasBadSize = diagnoseMisSizedDbgValue(M, DVI); |
| 350 | if (!HasBadSize) |
| 351 | MissingVars.reset(Var - 1); |
| 352 | HasErrors |= HasBadSize; |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 353 | } |
| 354 | } |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 355 | |
| 356 | // Print the results. |
| 357 | for (unsigned Idx : MissingLines.set_bits()) |
Vedant Kumar | a9e2731 | 2018-06-06 19:05:41 +0000 | [diff] [blame] | 358 | dbg() << "WARNING: Missing line " << Idx + 1 << "\n"; |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 359 | |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 360 | for (unsigned Idx : MissingVars.set_bits()) |
Vedant Kumar | 2e6c5f9 | 2018-06-26 18:54:10 +0000 | [diff] [blame] | 361 | dbg() << "WARNING: Missing variable " << Idx + 1 << "\n"; |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 362 | |
Vedant Kumar | d6ff43c | 2018-07-24 00:41:29 +0000 | [diff] [blame] | 363 | // Update DI loss statistics. |
| 364 | if (Stats) { |
| 365 | Stats->NumDbgLocsExpected += OriginalNumLines; |
| 366 | Stats->NumDbgLocsMissing += MissingLines.count(); |
| 367 | Stats->NumDbgValuesExpected += OriginalNumVars; |
| 368 | Stats->NumDbgValuesMissing += MissingVars.count(); |
| 369 | } |
| 370 | |
Vedant Kumar | a9e2731 | 2018-06-06 19:05:41 +0000 | [diff] [blame] | 371 | dbg() << Banner; |
Vedant Kumar | b70e356 | 2018-05-24 23:00:22 +0000 | [diff] [blame] | 372 | if (!NameOfWrappedPass.empty()) |
Vedant Kumar | a9e2731 | 2018-06-06 19:05:41 +0000 | [diff] [blame] | 373 | dbg() << " [" << NameOfWrappedPass << "]"; |
| 374 | dbg() << ": " << (HasErrors ? "FAIL" : "PASS") << '\n'; |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 375 | |
Vedant Kumar | 122a6bf | 2020-04-10 14:58:13 -0700 | [diff] [blame] | 376 | // Strip debugify metadata if required. |
| 377 | if (Strip) |
| 378 | return stripDebugifyMetadata(M); |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 379 | |
| 380 | return false; |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 381 | } |
| 382 | |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 383 | /// ModulePass for attaching synthetic debug info to everything, used with the |
| 384 | /// legacy module pass manager. |
| 385 | struct DebugifyModulePass : public ModulePass { |
| 386 | bool runOnModule(Module &M) override { |
Daniel Sanders | 1adeeab | 2020-04-03 16:18:45 -0700 | [diff] [blame] | 387 | return applyDebugifyMetadata(M, M.functions(), |
| 388 | "ModuleDebugify: ", /*ApplyToMF*/ nullptr); |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 389 | } |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 390 | |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 391 | DebugifyModulePass() : ModulePass(ID) {} |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 392 | |
| 393 | void getAnalysisUsage(AnalysisUsage &AU) const override { |
| 394 | AU.setPreservesAll(); |
| 395 | } |
| 396 | |
| 397 | static char ID; // Pass identification. |
| 398 | }; |
| 399 | |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 400 | /// FunctionPass for attaching synthetic debug info to instructions within a |
| 401 | /// single function, used with the legacy module pass manager. |
| 402 | struct DebugifyFunctionPass : public FunctionPass { |
| 403 | bool runOnFunction(Function &F) override { |
| 404 | Module &M = *F.getParent(); |
| 405 | auto FuncIt = F.getIterator(); |
| 406 | return applyDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)), |
Daniel Sanders | 1adeeab | 2020-04-03 16:18:45 -0700 | [diff] [blame] | 407 | "FunctionDebugify: ", /*ApplyToMF*/ nullptr); |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 408 | } |
| 409 | |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 410 | DebugifyFunctionPass() : FunctionPass(ID) {} |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 411 | |
| 412 | void getAnalysisUsage(AnalysisUsage &AU) const override { |
| 413 | AU.setPreservesAll(); |
| 414 | } |
| 415 | |
| 416 | static char ID; // Pass identification. |
| 417 | }; |
| 418 | |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 419 | /// ModulePass for checking debug info inserted by -debugify, used with the |
| 420 | /// legacy module pass manager. |
| 421 | struct CheckDebugifyModulePass : public ModulePass { |
| 422 | bool runOnModule(Module &M) override { |
Anastasis Grammenos | b4344c6 | 2018-05-15 23:38:05 +0000 | [diff] [blame] | 423 | return checkDebugifyMetadata(M, M.functions(), NameOfWrappedPass, |
Vedant Kumar | d6ff43c | 2018-07-24 00:41:29 +0000 | [diff] [blame] | 424 | "CheckModuleDebugify", Strip, StatsMap); |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 425 | } |
| 426 | |
Vedant Kumar | d6ff43c | 2018-07-24 00:41:29 +0000 | [diff] [blame] | 427 | CheckDebugifyModulePass(bool Strip = false, StringRef NameOfWrappedPass = "", |
| 428 | DebugifyStatsMap *StatsMap = nullptr) |
| 429 | : ModulePass(ID), Strip(Strip), NameOfWrappedPass(NameOfWrappedPass), |
| 430 | StatsMap(StatsMap) {} |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 431 | |
Vedant Kumar | fb7c768 | 2018-06-04 21:43:28 +0000 | [diff] [blame] | 432 | void getAnalysisUsage(AnalysisUsage &AU) const override { |
| 433 | AU.setPreservesAll(); |
| 434 | } |
| 435 | |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 436 | static char ID; // Pass identification. |
| 437 | |
| 438 | private: |
| 439 | bool Strip; |
Anastasis Grammenos | b4344c6 | 2018-05-15 23:38:05 +0000 | [diff] [blame] | 440 | StringRef NameOfWrappedPass; |
Vedant Kumar | d6ff43c | 2018-07-24 00:41:29 +0000 | [diff] [blame] | 441 | DebugifyStatsMap *StatsMap; |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 442 | }; |
| 443 | |
| 444 | /// FunctionPass for checking debug info inserted by -debugify-function, used |
| 445 | /// with the legacy module pass manager. |
| 446 | struct CheckDebugifyFunctionPass : public FunctionPass { |
| 447 | bool runOnFunction(Function &F) override { |
| 448 | Module &M = *F.getParent(); |
| 449 | auto FuncIt = F.getIterator(); |
| 450 | return checkDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)), |
Vedant Kumar | 4872535e | 2018-05-24 23:00:23 +0000 | [diff] [blame] | 451 | NameOfWrappedPass, "CheckFunctionDebugify", |
Vedant Kumar | d6ff43c | 2018-07-24 00:41:29 +0000 | [diff] [blame] | 452 | Strip, StatsMap); |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 453 | } |
| 454 | |
Vedant Kumar | 4872535e | 2018-05-24 23:00:23 +0000 | [diff] [blame] | 455 | CheckDebugifyFunctionPass(bool Strip = false, |
Vedant Kumar | d6ff43c | 2018-07-24 00:41:29 +0000 | [diff] [blame] | 456 | StringRef NameOfWrappedPass = "", |
| 457 | DebugifyStatsMap *StatsMap = nullptr) |
| 458 | : FunctionPass(ID), Strip(Strip), NameOfWrappedPass(NameOfWrappedPass), |
| 459 | StatsMap(StatsMap) {} |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 460 | |
| 461 | void getAnalysisUsage(AnalysisUsage &AU) const override { |
| 462 | AU.setPreservesAll(); |
| 463 | } |
| 464 | |
| 465 | static char ID; // Pass identification. |
| 466 | |
| 467 | private: |
| 468 | bool Strip; |
Anastasis Grammenos | b4344c6 | 2018-05-15 23:38:05 +0000 | [diff] [blame] | 469 | StringRef NameOfWrappedPass; |
Vedant Kumar | d6ff43c | 2018-07-24 00:41:29 +0000 | [diff] [blame] | 470 | DebugifyStatsMap *StatsMap; |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 471 | }; |
| 472 | |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 473 | } // end anonymous namespace |
| 474 | |
Vedant Kumar | ab112b8 | 2018-06-05 00:56:07 +0000 | [diff] [blame] | 475 | ModulePass *createDebugifyModulePass() { return new DebugifyModulePass(); } |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 476 | |
| 477 | FunctionPass *createDebugifyFunctionPass() { |
| 478 | return new DebugifyFunctionPass(); |
| 479 | } |
Vedant Kumar | 92f7a62 | 2018-01-23 20:43:50 +0000 | [diff] [blame] | 480 | |
Vedant Kumar | 775c7af | 2018-02-15 21:14:36 +0000 | [diff] [blame] | 481 | PreservedAnalyses NewPMDebugifyPass::run(Module &M, ModuleAnalysisManager &) { |
Daniel Sanders | 1adeeab | 2020-04-03 16:18:45 -0700 | [diff] [blame] | 482 | applyDebugifyMetadata(M, M.functions(), |
| 483 | "ModuleDebugify: ", /*ApplyToMF*/ nullptr); |
Vedant Kumar | 775c7af | 2018-02-15 21:14:36 +0000 | [diff] [blame] | 484 | return PreservedAnalyses::all(); |
| 485 | } |
| 486 | |
Vedant Kumar | 36b89d4 | 2018-06-04 00:11:47 +0000 | [diff] [blame] | 487 | ModulePass *createCheckDebugifyModulePass(bool Strip, |
Vedant Kumar | d6ff43c | 2018-07-24 00:41:29 +0000 | [diff] [blame] | 488 | StringRef NameOfWrappedPass, |
| 489 | DebugifyStatsMap *StatsMap) { |
| 490 | return new CheckDebugifyModulePass(Strip, NameOfWrappedPass, StatsMap); |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 491 | } |
| 492 | |
Vedant Kumar | 36b89d4 | 2018-06-04 00:11:47 +0000 | [diff] [blame] | 493 | FunctionPass *createCheckDebugifyFunctionPass(bool Strip, |
Vedant Kumar | d6ff43c | 2018-07-24 00:41:29 +0000 | [diff] [blame] | 494 | StringRef NameOfWrappedPass, |
| 495 | DebugifyStatsMap *StatsMap) { |
| 496 | return new CheckDebugifyFunctionPass(Strip, NameOfWrappedPass, StatsMap); |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 497 | } |
Vedant Kumar | 92f7a62 | 2018-01-23 20:43:50 +0000 | [diff] [blame] | 498 | |
Vedant Kumar | 775c7af | 2018-02-15 21:14:36 +0000 | [diff] [blame] | 499 | PreservedAnalyses NewPMCheckDebugifyPass::run(Module &M, |
| 500 | ModuleAnalysisManager &) { |
Vedant Kumar | d6ff43c | 2018-07-24 00:41:29 +0000 | [diff] [blame] | 501 | checkDebugifyMetadata(M, M.functions(), "", "CheckModuleDebugify", false, |
| 502 | nullptr); |
Vedant Kumar | 775c7af | 2018-02-15 21:14:36 +0000 | [diff] [blame] | 503 | return PreservedAnalyses::all(); |
| 504 | } |
| 505 | |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 506 | char DebugifyModulePass::ID = 0; |
| 507 | static RegisterPass<DebugifyModulePass> DM("debugify", |
Vedant Kumar | 36b89d4 | 2018-06-04 00:11:47 +0000 | [diff] [blame] | 508 | "Attach debug info to everything"); |
Vedant Kumar | 195dfd1 | 2017-12-08 21:57:28 +0000 | [diff] [blame] | 509 | |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 510 | char CheckDebugifyModulePass::ID = 0; |
Vedant Kumar | 36b89d4 | 2018-06-04 00:11:47 +0000 | [diff] [blame] | 511 | static RegisterPass<CheckDebugifyModulePass> |
| 512 | CDM("check-debugify", "Check debug info from -debugify"); |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 513 | |
| 514 | char DebugifyFunctionPass::ID = 0; |
| 515 | static RegisterPass<DebugifyFunctionPass> DF("debugify-function", |
Vedant Kumar | 36b89d4 | 2018-06-04 00:11:47 +0000 | [diff] [blame] | 516 | "Attach debug info to a function"); |
Vedant Kumar | 595ba1d | 2018-05-15 00:29:27 +0000 | [diff] [blame] | 517 | |
| 518 | char CheckDebugifyFunctionPass::ID = 0; |
Vedant Kumar | 36b89d4 | 2018-06-04 00:11:47 +0000 | [diff] [blame] | 519 | static RegisterPass<CheckDebugifyFunctionPass> |
| 520 | CDF("check-debugify-function", "Check debug info from -debugify-function"); |