blob: 135a026da49a8b82e9f51ea1c3ba338393ffd1a6 [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
Vedant Kumar775c7af2018-02-15 21:14:36 +000015#include "PassPrinters.h"
Vedant Kumar195dfd12017-12-08 21:57:28 +000016#include "llvm/ADT/BitVector.h"
17#include "llvm/ADT/StringExtras.h"
18#include "llvm/IR/BasicBlock.h"
19#include "llvm/IR/Constants.h"
20#include "llvm/IR/DIBuilder.h"
21#include "llvm/IR/DebugInfo.h"
22#include "llvm/IR/Function.h"
23#include "llvm/IR/GlobalVariable.h"
24#include "llvm/IR/InstIterator.h"
25#include "llvm/IR/Instruction.h"
26#include "llvm/IR/Instructions.h"
27#include "llvm/IR/IntrinsicInst.h"
28#include "llvm/IR/Module.h"
29#include "llvm/IR/Type.h"
30#include "llvm/Pass.h"
31#include "llvm/Support/raw_ostream.h"
32#include "llvm/Transforms/IPO.h"
33
34using namespace llvm;
35
36namespace {
37
Vedant Kumar17d8bba2018-02-15 21:28:38 +000038bool isFunctionSkipped(Function &F) {
39 return F.isDeclaration() || !F.hasExactDefinition();
40}
41
Vedant Kumar595ba1d2018-05-15 00:29:27 +000042bool applyDebugifyMetadata(Module &M,
43 iterator_range<Module::iterator> Functions,
44 StringRef Banner) {
Vedant Kumar195dfd12017-12-08 21:57:28 +000045 // Skip modules with debug info.
46 if (M.getNamedMetadata("llvm.dbg.cu")) {
Vedant Kumar595ba1d2018-05-15 00:29:27 +000047 errs() << Banner << "Skipping module with debug info\n";
Vedant Kumar195dfd12017-12-08 21:57:28 +000048 return false;
49 }
50
51 DIBuilder DIB(M);
52 LLVMContext &Ctx = M.getContext();
53
54 // Get a DIType which corresponds to Ty.
55 DenseMap<uint64_t, DIType *> TypeCache;
56 auto getCachedDIType = [&](Type *Ty) -> DIType * {
Vedant Kumar1f6f5f12018-01-06 00:37:01 +000057 uint64_t Size =
58 Ty->isSized() ? M.getDataLayout().getTypeAllocSizeInBits(Ty) : 0;
Vedant Kumar195dfd12017-12-08 21:57:28 +000059 DIType *&DTy = TypeCache[Size];
60 if (!DTy) {
61 std::string Name = "ty" + utostr(Size);
62 DTy = DIB.createBasicType(Name, Size, dwarf::DW_ATE_unsigned);
63 }
64 return DTy;
65 };
66
67 unsigned NextLine = 1;
68 unsigned NextVar = 1;
69 auto File = DIB.createFile(M.getName(), "/");
Vedant Kumar595ba1d2018-05-15 00:29:27 +000070 auto CU = DIB.createCompileUnit(dwarf::DW_LANG_C, File,
Vedant Kumar195dfd12017-12-08 21:57:28 +000071 "debugify", /*isOptimized=*/true, "", 0);
72
73 // Visit each instruction.
Vedant Kumar595ba1d2018-05-15 00:29:27 +000074 for (Function &F : Functions) {
Vedant Kumar17d8bba2018-02-15 21:28:38 +000075 if (isFunctionSkipped(F))
Vedant Kumar195dfd12017-12-08 21:57:28 +000076 continue;
77
78 auto SPType = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None));
79 bool IsLocalToUnit = F.hasPrivateLinkage() || F.hasInternalLinkage();
80 auto SP =
81 DIB.createFunction(CU, F.getName(), F.getName(), File, NextLine, SPType,
Vedant Kumar16276322018-02-13 18:15:27 +000082 IsLocalToUnit, /*isDefinition=*/true, NextLine,
Vedant Kumar195dfd12017-12-08 21:57:28 +000083 DINode::FlagZero, /*isOptimized=*/true);
84 F.setSubprogram(SP);
85 for (BasicBlock &BB : F) {
86 // Attach debug locations.
87 for (Instruction &I : BB)
88 I.setDebugLoc(DILocation::get(Ctx, NextLine++, 1, SP));
89
90 // Attach debug values.
91 for (Instruction &I : BB) {
92 // Skip void-valued instructions.
93 if (I.getType()->isVoidTy())
94 continue;
95
96 // Skip the terminator instruction and any just-inserted intrinsics.
97 if (isa<TerminatorInst>(&I) || isa<DbgValueInst>(&I))
98 break;
99
100 std::string Name = utostr(NextVar++);
101 const DILocation *Loc = I.getDebugLoc().get();
102 auto LocalVar = DIB.createAutoVariable(SP, Name, File, Loc->getLine(),
103 getCachedDIType(I.getType()),
104 /*AlwaysPreserve=*/true);
105 DIB.insertDbgValueIntrinsic(&I, LocalVar, DIB.createExpression(), Loc,
106 BB.getTerminator());
107 }
108 }
109 DIB.finalizeSubprogram(SP);
110 }
111 DIB.finalize();
112
113 // Track the number of distinct lines and variables.
114 NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.debugify");
115 auto *IntTy = Type::getInt32Ty(Ctx);
116 auto addDebugifyOperand = [&](unsigned N) {
117 NMD->addOperand(MDNode::get(
118 Ctx, ValueAsMetadata::getConstant(ConstantInt::get(IntTy, N))));
119 };
120 addDebugifyOperand(NextLine - 1); // Original number of lines.
121 addDebugifyOperand(NextVar - 1); // Original number of variables.
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000122 assert(NMD->getNumOperands() == 2 &&
123 "llvm.debugify should have exactly 2 operands!");
Vedant Kumar195dfd12017-12-08 21:57:28 +0000124 return true;
125}
126
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000127bool checkDebugifyMetadata(Module &M,
128 iterator_range<Module::iterator> Functions,
129 StringRef Banner,
130 bool Strip) {
Vedant Kumar195dfd12017-12-08 21:57:28 +0000131 // Skip modules without debugify metadata.
132 NamedMDNode *NMD = M.getNamedMetadata("llvm.debugify");
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000133 if (!NMD) {
134 errs() << Banner << "Skipping module without debugify metadata\n";
135 return false;
136 }
Vedant Kumar195dfd12017-12-08 21:57:28 +0000137
138 auto getDebugifyOperand = [&](unsigned Idx) -> unsigned {
139 return mdconst::extract<ConstantInt>(NMD->getOperand(Idx)->getOperand(0))
140 ->getZExtValue();
141 };
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000142 assert(NMD->getNumOperands() == 2 &&
143 "llvm.debugify should have exactly 2 operands!");
Vedant Kumar195dfd12017-12-08 21:57:28 +0000144 unsigned OriginalNumLines = getDebugifyOperand(0);
145 unsigned OriginalNumVars = getDebugifyOperand(1);
146 bool HasErrors = false;
147
Vedant Kumar195dfd12017-12-08 21:57:28 +0000148 BitVector MissingLines{OriginalNumLines, true};
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000149 BitVector MissingVars{OriginalNumVars, true};
150 for (Function &F : Functions) {
Vedant Kumar17d8bba2018-02-15 21:28:38 +0000151 if (isFunctionSkipped(F))
152 continue;
153
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000154 // Find missing lines.
Vedant Kumar195dfd12017-12-08 21:57:28 +0000155 for (Instruction &I : instructions(F)) {
156 if (isa<DbgValueInst>(&I))
157 continue;
158
159 auto DL = I.getDebugLoc();
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000160 if (DL && DL.getLine() != 0) {
Vedant Kumar195dfd12017-12-08 21:57:28 +0000161 MissingLines.reset(DL.getLine() - 1);
162 continue;
163 }
164
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000165 outs() << "ERROR: Instruction with empty DebugLoc in function ";
166 outs() << F.getName() << " --";
Vedant Kumar195dfd12017-12-08 21:57:28 +0000167 I.print(outs());
168 outs() << "\n";
169 HasErrors = true;
170 }
Vedant Kumar195dfd12017-12-08 21:57:28 +0000171
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000172 // Find missing variables.
Vedant Kumar195dfd12017-12-08 21:57:28 +0000173 for (Instruction &I : instructions(F)) {
174 auto *DVI = dyn_cast<DbgValueInst>(&I);
175 if (!DVI)
176 continue;
177
178 unsigned Var = ~0U;
179 (void)to_integer(DVI->getVariable()->getName(), Var, 10);
180 assert(Var <= OriginalNumVars && "Unexpected name for DILocalVariable");
181 MissingVars.reset(Var - 1);
182 }
183 }
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000184
185 // Print the results.
186 for (unsigned Idx : MissingLines.set_bits())
187 outs() << "WARNING: Missing line " << Idx + 1 << "\n";
188
Vedant Kumar195dfd12017-12-08 21:57:28 +0000189 for (unsigned Idx : MissingVars.set_bits())
190 outs() << "ERROR: Missing variable " << Idx + 1 << "\n";
191 HasErrors |= MissingVars.count() > 0;
192
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000193 outs() << Banner << (HasErrors ? "FAIL" : "PASS") << '\n';
194 if (HasErrors) {
195 outs() << "Module IR Dump\n";
196 M.print(outs(), nullptr, false);
197 }
198
199 // Strip the Debugify Metadata if required.
200 if (Strip) {
201 StripDebugInfo(M);
202 M.eraseNamedMetadata(NMD);
203 return true;
204 }
205
206 return false;
Vedant Kumar195dfd12017-12-08 21:57:28 +0000207}
208
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000209/// ModulePass for attaching synthetic debug info to everything, used with the
210/// legacy module pass manager.
211struct DebugifyModulePass : public ModulePass {
212 bool runOnModule(Module &M) override {
213 return applyDebugifyMetadata(M, M.functions(), "ModuleDebugify: ");
214 }
Vedant Kumar195dfd12017-12-08 21:57:28 +0000215
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000216 DebugifyModulePass() : ModulePass(ID) {}
Vedant Kumar195dfd12017-12-08 21:57:28 +0000217
218 void getAnalysisUsage(AnalysisUsage &AU) const override {
219 AU.setPreservesAll();
220 }
221
222 static char ID; // Pass identification.
223};
224
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000225/// FunctionPass for attaching synthetic debug info to instructions within a
226/// single function, used with the legacy module pass manager.
227struct DebugifyFunctionPass : public FunctionPass {
228 bool runOnFunction(Function &F) override {
229 Module &M = *F.getParent();
230 auto FuncIt = F.getIterator();
231 return applyDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)),
232 "FunctionDebugify: ");
Vedant Kumar195dfd12017-12-08 21:57:28 +0000233 }
234
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000235 DebugifyFunctionPass() : FunctionPass(ID) {}
Vedant Kumar195dfd12017-12-08 21:57:28 +0000236
237 void getAnalysisUsage(AnalysisUsage &AU) const override {
238 AU.setPreservesAll();
239 }
240
241 static char ID; // Pass identification.
242};
243
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000244/// ModulePass for checking debug info inserted by -debugify, used with the
245/// legacy module pass manager.
246struct CheckDebugifyModulePass : public ModulePass {
247 bool runOnModule(Module &M) override {
248 return checkDebugifyMetadata(M, M.functions(), "CheckModuleDebugify: ",
249 Strip);
250 }
251
252 CheckDebugifyModulePass(bool Strip = false) : ModulePass(ID), Strip(Strip) {}
253
254 static char ID; // Pass identification.
255
256private:
257 bool Strip;
258};
259
260/// FunctionPass for checking debug info inserted by -debugify-function, used
261/// with the legacy module pass manager.
262struct CheckDebugifyFunctionPass : public FunctionPass {
263 bool runOnFunction(Function &F) override {
264 Module &M = *F.getParent();
265 auto FuncIt = F.getIterator();
266 return checkDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)),
267 "CheckFunctionDebugify: ", Strip);
268 }
269
270 CheckDebugifyFunctionPass(bool Strip = false) : FunctionPass(ID), Strip(Strip) {}
271
272 void getAnalysisUsage(AnalysisUsage &AU) const override {
273 AU.setPreservesAll();
274 }
275
276 static char ID; // Pass identification.
277
278private:
279 bool Strip;
280};
281
Vedant Kumar195dfd12017-12-08 21:57:28 +0000282} // end anonymous namespace
283
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000284ModulePass *createDebugifyModulePass() {
285 return new DebugifyModulePass();
286}
287
288FunctionPass *createDebugifyFunctionPass() {
289 return new DebugifyFunctionPass();
290}
Vedant Kumar92f7a622018-01-23 20:43:50 +0000291
Vedant Kumar775c7af2018-02-15 21:14:36 +0000292PreservedAnalyses NewPMDebugifyPass::run(Module &M, ModuleAnalysisManager &) {
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000293 applyDebugifyMetadata(M, M.functions(), "ModuleDebugify: ");
Vedant Kumar775c7af2018-02-15 21:14:36 +0000294 return PreservedAnalyses::all();
295}
296
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000297ModulePass *createCheckDebugifyModulePass(bool Strip) {
298 return new CheckDebugifyModulePass(Strip);
299}
300
301FunctionPass *createCheckDebugifyFunctionPass(bool Strip) {
302 return new CheckDebugifyFunctionPass(Strip);
303}
Vedant Kumar92f7a622018-01-23 20:43:50 +0000304
Vedant Kumar775c7af2018-02-15 21:14:36 +0000305PreservedAnalyses NewPMCheckDebugifyPass::run(Module &M,
306 ModuleAnalysisManager &) {
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000307 checkDebugifyMetadata(M, M.functions(), "CheckModuleDebugify: ", false);
Vedant Kumar775c7af2018-02-15 21:14:36 +0000308 return PreservedAnalyses::all();
309}
310
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000311char DebugifyModulePass::ID = 0;
312static RegisterPass<DebugifyModulePass> DM("debugify",
Vedant Kumar195dfd12017-12-08 21:57:28 +0000313 "Attach debug info to everything");
314
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000315char CheckDebugifyModulePass::ID = 0;
316static RegisterPass<CheckDebugifyModulePass> CDM("check-debugify",
Vedant Kumar195dfd12017-12-08 21:57:28 +0000317 "Check debug info from -debugify");
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000318
319char DebugifyFunctionPass::ID = 0;
320static RegisterPass<DebugifyFunctionPass> DF("debugify-function",
321 "Attach debug info to a function");
322
323char CheckDebugifyFunctionPass::ID = 0;
324static RegisterPass<CheckDebugifyFunctionPass> CDF("check-debugify-function",
325 "Check debug info from -debugify-function");