blob: 89e572474bd95e834c4891eae978ad7c788ec258 [file] [log] [blame]
Vedant Kumar195dfd12017-12-08 21:57:28 +00001//===- Debugify.cpp - Attach synthetic debug info to everything -----------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9///
10/// \file This pass attaches synthetic debug info to everything. It can be used
11/// to create targeted tests for debug info preservation.
12///
13//===----------------------------------------------------------------------===//
14
15#include "llvm/ADT/BitVector.h"
16#include "llvm/ADT/StringExtras.h"
17#include "llvm/IR/BasicBlock.h"
18#include "llvm/IR/Constants.h"
19#include "llvm/IR/DIBuilder.h"
20#include "llvm/IR/DebugInfo.h"
21#include "llvm/IR/Function.h"
22#include "llvm/IR/GlobalVariable.h"
23#include "llvm/IR/InstIterator.h"
24#include "llvm/IR/Instruction.h"
25#include "llvm/IR/Instructions.h"
26#include "llvm/IR/IntrinsicInst.h"
27#include "llvm/IR/Module.h"
28#include "llvm/IR/Type.h"
29#include "llvm/Pass.h"
30#include "llvm/Support/raw_ostream.h"
31#include "llvm/Transforms/IPO.h"
32
33using namespace llvm;
34
35namespace {
36
37bool applyDebugifyMetadata(Module &M) {
38 // Skip modules with debug info.
39 if (M.getNamedMetadata("llvm.dbg.cu")) {
40 errs() << "Debugify: Skipping module with debug info\n";
41 return false;
42 }
43
44 DIBuilder DIB(M);
45 LLVMContext &Ctx = M.getContext();
46
47 // Get a DIType which corresponds to Ty.
48 DenseMap<uint64_t, DIType *> TypeCache;
49 auto getCachedDIType = [&](Type *Ty) -> DIType * {
Vedant Kumar1f6f5f12018-01-06 00:37:01 +000050 uint64_t Size =
51 Ty->isSized() ? M.getDataLayout().getTypeAllocSizeInBits(Ty) : 0;
Vedant Kumar195dfd12017-12-08 21:57:28 +000052 DIType *&DTy = TypeCache[Size];
53 if (!DTy) {
54 std::string Name = "ty" + utostr(Size);
55 DTy = DIB.createBasicType(Name, Size, dwarf::DW_ATE_unsigned);
56 }
57 return DTy;
58 };
59
60 unsigned NextLine = 1;
61 unsigned NextVar = 1;
62 auto File = DIB.createFile(M.getName(), "/");
63 auto CU =
64 DIB.createCompileUnit(dwarf::DW_LANG_C, DIB.createFile(M.getName(), "/"),
65 "debugify", /*isOptimized=*/true, "", 0);
66
67 // Visit each instruction.
68 for (Function &F : M) {
69 if (F.isDeclaration())
70 continue;
71
72 auto SPType = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None));
73 bool IsLocalToUnit = F.hasPrivateLinkage() || F.hasInternalLinkage();
74 auto SP =
75 DIB.createFunction(CU, F.getName(), F.getName(), File, NextLine, SPType,
76 IsLocalToUnit, F.hasExactDefinition(), NextLine,
77 DINode::FlagZero, /*isOptimized=*/true);
78 F.setSubprogram(SP);
79 for (BasicBlock &BB : F) {
80 // Attach debug locations.
81 for (Instruction &I : BB)
82 I.setDebugLoc(DILocation::get(Ctx, NextLine++, 1, SP));
83
84 // Attach debug values.
85 for (Instruction &I : BB) {
86 // Skip void-valued instructions.
87 if (I.getType()->isVoidTy())
88 continue;
89
90 // Skip the terminator instruction and any just-inserted intrinsics.
91 if (isa<TerminatorInst>(&I) || isa<DbgValueInst>(&I))
92 break;
93
94 std::string Name = utostr(NextVar++);
95 const DILocation *Loc = I.getDebugLoc().get();
96 auto LocalVar = DIB.createAutoVariable(SP, Name, File, Loc->getLine(),
97 getCachedDIType(I.getType()),
98 /*AlwaysPreserve=*/true);
99 DIB.insertDbgValueIntrinsic(&I, LocalVar, DIB.createExpression(), Loc,
100 BB.getTerminator());
101 }
102 }
103 DIB.finalizeSubprogram(SP);
104 }
105 DIB.finalize();
106
107 // Track the number of distinct lines and variables.
108 NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.debugify");
109 auto *IntTy = Type::getInt32Ty(Ctx);
110 auto addDebugifyOperand = [&](unsigned N) {
111 NMD->addOperand(MDNode::get(
112 Ctx, ValueAsMetadata::getConstant(ConstantInt::get(IntTy, N))));
113 };
114 addDebugifyOperand(NextLine - 1); // Original number of lines.
115 addDebugifyOperand(NextVar - 1); // Original number of variables.
116 return true;
117}
118
119void checkDebugifyMetadata(Module &M) {
120 // Skip modules without debugify metadata.
121 NamedMDNode *NMD = M.getNamedMetadata("llvm.debugify");
122 if (!NMD)
123 return;
124
125 auto getDebugifyOperand = [&](unsigned Idx) -> unsigned {
126 return mdconst::extract<ConstantInt>(NMD->getOperand(Idx)->getOperand(0))
127 ->getZExtValue();
128 };
129 unsigned OriginalNumLines = getDebugifyOperand(0);
130 unsigned OriginalNumVars = getDebugifyOperand(1);
131 bool HasErrors = false;
132
133 // Find missing lines.
134 BitVector MissingLines{OriginalNumLines, true};
135 for (Function &F : M) {
136 for (Instruction &I : instructions(F)) {
137 if (isa<DbgValueInst>(&I))
138 continue;
139
140 auto DL = I.getDebugLoc();
141 if (DL) {
142 MissingLines.reset(DL.getLine() - 1);
143 continue;
144 }
145
146 outs() << "ERROR: Instruction with empty DebugLoc -- ";
147 I.print(outs());
148 outs() << "\n";
149 HasErrors = true;
150 }
151 }
152 for (unsigned Idx : MissingLines.set_bits())
153 outs() << "WARNING: Missing line " << Idx + 1 << "\n";
154
155 // Find missing variables.
156 BitVector MissingVars{OriginalNumVars, true};
157 for (Function &F : M) {
158 for (Instruction &I : instructions(F)) {
159 auto *DVI = dyn_cast<DbgValueInst>(&I);
160 if (!DVI)
161 continue;
162
163 unsigned Var = ~0U;
164 (void)to_integer(DVI->getVariable()->getName(), Var, 10);
165 assert(Var <= OriginalNumVars && "Unexpected name for DILocalVariable");
166 MissingVars.reset(Var - 1);
167 }
168 }
169 for (unsigned Idx : MissingVars.set_bits())
170 outs() << "ERROR: Missing variable " << Idx + 1 << "\n";
171 HasErrors |= MissingVars.count() > 0;
172
173 outs() << "CheckDebugify: " << (HasErrors ? "FAIL" : "PASS") << "\n";
174}
175
176/// Attach synthetic debug info to everything.
177struct DebugifyPass : public ModulePass {
178 bool runOnModule(Module &M) override { return applyDebugifyMetadata(M); }
179
180 DebugifyPass() : ModulePass(ID) {}
181
182 void getAnalysisUsage(AnalysisUsage &AU) const override {
183 AU.setPreservesAll();
184 }
185
186 static char ID; // Pass identification.
187};
188
189/// Check debug info inserted by -debugify for completeness.
190struct CheckDebugifyPass : public ModulePass {
191 bool runOnModule(Module &M) override {
192 checkDebugifyMetadata(M);
193 return false;
194 }
195
196 CheckDebugifyPass() : ModulePass(ID) {}
197
198 void getAnalysisUsage(AnalysisUsage &AU) const override {
199 AU.setPreservesAll();
200 }
201
202 static char ID; // Pass identification.
203};
204
205} // end anonymous namespace
206
207char DebugifyPass::ID = 0;
208static RegisterPass<DebugifyPass> X("debugify",
209 "Attach debug info to everything");
210
211char CheckDebugifyPass::ID = 0;
212static RegisterPass<CheckDebugifyPass> Y("check-debugify",
213 "Check debug info from -debugify");