blob: 40ee545c098d3cf14cd2f4c18e2f8a3fa33e77e2 [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 * {
50 uint64_t Size = M.getDataLayout().getTypeAllocSizeInBits(Ty);
51 DIType *&DTy = TypeCache[Size];
52 if (!DTy) {
53 std::string Name = "ty" + utostr(Size);
54 DTy = DIB.createBasicType(Name, Size, dwarf::DW_ATE_unsigned);
55 }
56 return DTy;
57 };
58
59 unsigned NextLine = 1;
60 unsigned NextVar = 1;
61 auto File = DIB.createFile(M.getName(), "/");
62 auto CU =
63 DIB.createCompileUnit(dwarf::DW_LANG_C, DIB.createFile(M.getName(), "/"),
64 "debugify", /*isOptimized=*/true, "", 0);
65
66 // Visit each instruction.
67 for (Function &F : M) {
68 if (F.isDeclaration())
69 continue;
70
71 auto SPType = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None));
72 bool IsLocalToUnit = F.hasPrivateLinkage() || F.hasInternalLinkage();
73 auto SP =
74 DIB.createFunction(CU, F.getName(), F.getName(), File, NextLine, SPType,
75 IsLocalToUnit, F.hasExactDefinition(), NextLine,
76 DINode::FlagZero, /*isOptimized=*/true);
77 F.setSubprogram(SP);
78 for (BasicBlock &BB : F) {
79 // Attach debug locations.
80 for (Instruction &I : BB)
81 I.setDebugLoc(DILocation::get(Ctx, NextLine++, 1, SP));
82
83 // Attach debug values.
84 for (Instruction &I : BB) {
85 // Skip void-valued instructions.
86 if (I.getType()->isVoidTy())
87 continue;
88
89 // Skip the terminator instruction and any just-inserted intrinsics.
90 if (isa<TerminatorInst>(&I) || isa<DbgValueInst>(&I))
91 break;
92
93 std::string Name = utostr(NextVar++);
94 const DILocation *Loc = I.getDebugLoc().get();
95 auto LocalVar = DIB.createAutoVariable(SP, Name, File, Loc->getLine(),
96 getCachedDIType(I.getType()),
97 /*AlwaysPreserve=*/true);
98 DIB.insertDbgValueIntrinsic(&I, LocalVar, DIB.createExpression(), Loc,
99 BB.getTerminator());
100 }
101 }
102 DIB.finalizeSubprogram(SP);
103 }
104 DIB.finalize();
105
106 // Track the number of distinct lines and variables.
107 NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.debugify");
108 auto *IntTy = Type::getInt32Ty(Ctx);
109 auto addDebugifyOperand = [&](unsigned N) {
110 NMD->addOperand(MDNode::get(
111 Ctx, ValueAsMetadata::getConstant(ConstantInt::get(IntTy, N))));
112 };
113 addDebugifyOperand(NextLine - 1); // Original number of lines.
114 addDebugifyOperand(NextVar - 1); // Original number of variables.
115 return true;
116}
117
118void checkDebugifyMetadata(Module &M) {
119 // Skip modules without debugify metadata.
120 NamedMDNode *NMD = M.getNamedMetadata("llvm.debugify");
121 if (!NMD)
122 return;
123
124 auto getDebugifyOperand = [&](unsigned Idx) -> unsigned {
125 return mdconst::extract<ConstantInt>(NMD->getOperand(Idx)->getOperand(0))
126 ->getZExtValue();
127 };
128 unsigned OriginalNumLines = getDebugifyOperand(0);
129 unsigned OriginalNumVars = getDebugifyOperand(1);
130 bool HasErrors = false;
131
132 // Find missing lines.
133 BitVector MissingLines{OriginalNumLines, true};
134 for (Function &F : M) {
135 for (Instruction &I : instructions(F)) {
136 if (isa<DbgValueInst>(&I))
137 continue;
138
139 auto DL = I.getDebugLoc();
140 if (DL) {
141 MissingLines.reset(DL.getLine() - 1);
142 continue;
143 }
144
145 outs() << "ERROR: Instruction with empty DebugLoc -- ";
146 I.print(outs());
147 outs() << "\n";
148 HasErrors = true;
149 }
150 }
151 for (unsigned Idx : MissingLines.set_bits())
152 outs() << "WARNING: Missing line " << Idx + 1 << "\n";
153
154 // Find missing variables.
155 BitVector MissingVars{OriginalNumVars, true};
156 for (Function &F : M) {
157 for (Instruction &I : instructions(F)) {
158 auto *DVI = dyn_cast<DbgValueInst>(&I);
159 if (!DVI)
160 continue;
161
162 unsigned Var = ~0U;
163 (void)to_integer(DVI->getVariable()->getName(), Var, 10);
164 assert(Var <= OriginalNumVars && "Unexpected name for DILocalVariable");
165 MissingVars.reset(Var - 1);
166 }
167 }
168 for (unsigned Idx : MissingVars.set_bits())
169 outs() << "ERROR: Missing variable " << Idx + 1 << "\n";
170 HasErrors |= MissingVars.count() > 0;
171
172 outs() << "CheckDebugify: " << (HasErrors ? "FAIL" : "PASS") << "\n";
173}
174
175/// Attach synthetic debug info to everything.
176struct DebugifyPass : public ModulePass {
177 bool runOnModule(Module &M) override { return applyDebugifyMetadata(M); }
178
179 DebugifyPass() : ModulePass(ID) {}
180
181 void getAnalysisUsage(AnalysisUsage &AU) const override {
182 AU.setPreservesAll();
183 }
184
185 static char ID; // Pass identification.
186};
187
188/// Check debug info inserted by -debugify for completeness.
189struct CheckDebugifyPass : public ModulePass {
190 bool runOnModule(Module &M) override {
191 checkDebugifyMetadata(M);
192 return false;
193 }
194
195 CheckDebugifyPass() : ModulePass(ID) {}
196
197 void getAnalysisUsage(AnalysisUsage &AU) const override {
198 AU.setPreservesAll();
199 }
200
201 static char ID; // Pass identification.
202};
203
204} // end anonymous namespace
205
206char DebugifyPass::ID = 0;
207static RegisterPass<DebugifyPass> X("debugify",
208 "Attach debug info to everything");
209
210char CheckDebugifyPass::ID = 0;
211static RegisterPass<CheckDebugifyPass> Y("check-debugify",
212 "Check debug info from -debugify");