blob: 6d12b7e3637343fb2bfaa61489ed8400c1c17de4 [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,
Anastasis Grammenosb4344c62018-05-15 23:38:05 +0000129 StringRef NameOfWrappedPass,
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000130 StringRef Banner,
131 bool Strip) {
Vedant Kumar195dfd12017-12-08 21:57:28 +0000132 // Skip modules without debugify metadata.
133 NamedMDNode *NMD = M.getNamedMetadata("llvm.debugify");
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000134 if (!NMD) {
135 errs() << Banner << "Skipping module without debugify metadata\n";
136 return false;
137 }
Vedant Kumar195dfd12017-12-08 21:57:28 +0000138
139 auto getDebugifyOperand = [&](unsigned Idx) -> unsigned {
140 return mdconst::extract<ConstantInt>(NMD->getOperand(Idx)->getOperand(0))
141 ->getZExtValue();
142 };
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000143 assert(NMD->getNumOperands() == 2 &&
144 "llvm.debugify should have exactly 2 operands!");
Vedant Kumar195dfd12017-12-08 21:57:28 +0000145 unsigned OriginalNumLines = getDebugifyOperand(0);
146 unsigned OriginalNumVars = getDebugifyOperand(1);
147 bool HasErrors = false;
148
Vedant Kumar195dfd12017-12-08 21:57:28 +0000149 BitVector MissingLines{OriginalNumLines, true};
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000150 BitVector MissingVars{OriginalNumVars, true};
151 for (Function &F : Functions) {
Vedant Kumar17d8bba2018-02-15 21:28:38 +0000152 if (isFunctionSkipped(F))
153 continue;
154
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000155 // Find missing lines.
Vedant Kumar195dfd12017-12-08 21:57:28 +0000156 for (Instruction &I : instructions(F)) {
157 if (isa<DbgValueInst>(&I))
158 continue;
159
160 auto DL = I.getDebugLoc();
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000161 if (DL && DL.getLine() != 0) {
Vedant Kumar195dfd12017-12-08 21:57:28 +0000162 MissingLines.reset(DL.getLine() - 1);
163 continue;
164 }
165
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000166 outs() << "ERROR: Instruction with empty DebugLoc in function ";
167 outs() << F.getName() << " --";
Vedant Kumar195dfd12017-12-08 21:57:28 +0000168 I.print(outs());
169 outs() << "\n";
170 HasErrors = true;
171 }
Vedant Kumar195dfd12017-12-08 21:57:28 +0000172
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000173 // Find missing variables.
Vedant Kumar195dfd12017-12-08 21:57:28 +0000174 for (Instruction &I : instructions(F)) {
175 auto *DVI = dyn_cast<DbgValueInst>(&I);
176 if (!DVI)
177 continue;
178
179 unsigned Var = ~0U;
180 (void)to_integer(DVI->getVariable()->getName(), Var, 10);
181 assert(Var <= OriginalNumVars && "Unexpected name for DILocalVariable");
182 MissingVars.reset(Var - 1);
183 }
184 }
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000185
186 // Print the results.
187 for (unsigned Idx : MissingLines.set_bits())
188 outs() << "WARNING: Missing line " << Idx + 1 << "\n";
189
Vedant Kumar195dfd12017-12-08 21:57:28 +0000190 for (unsigned Idx : MissingVars.set_bits())
191 outs() << "ERROR: Missing variable " << Idx + 1 << "\n";
192 HasErrors |= MissingVars.count() > 0;
193
Anastasis Grammenosb4344c62018-05-15 23:38:05 +0000194 outs() << Banner << " [" << NameOfWrappedPass << "]: "
195 << (HasErrors ? "FAIL" : "PASS") << '\n';
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000196 if (HasErrors) {
197 outs() << "Module IR Dump\n";
198 M.print(outs(), nullptr, false);
199 }
200
201 // Strip the Debugify Metadata if required.
202 if (Strip) {
203 StripDebugInfo(M);
204 M.eraseNamedMetadata(NMD);
205 return true;
206 }
207
208 return false;
Vedant Kumar195dfd12017-12-08 21:57:28 +0000209}
210
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000211/// ModulePass for attaching synthetic debug info to everything, used with the
212/// legacy module pass manager.
213struct DebugifyModulePass : public ModulePass {
214 bool runOnModule(Module &M) override {
215 return applyDebugifyMetadata(M, M.functions(), "ModuleDebugify: ");
216 }
Vedant Kumar195dfd12017-12-08 21:57:28 +0000217
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000218 DebugifyModulePass() : ModulePass(ID) {}
Vedant Kumar195dfd12017-12-08 21:57:28 +0000219
220 void getAnalysisUsage(AnalysisUsage &AU) const override {
221 AU.setPreservesAll();
222 }
223
224 static char ID; // Pass identification.
225};
226
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000227/// FunctionPass for attaching synthetic debug info to instructions within a
228/// single function, used with the legacy module pass manager.
229struct DebugifyFunctionPass : public FunctionPass {
230 bool runOnFunction(Function &F) override {
231 Module &M = *F.getParent();
232 auto FuncIt = F.getIterator();
233 return applyDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)),
234 "FunctionDebugify: ");
Vedant Kumar195dfd12017-12-08 21:57:28 +0000235 }
236
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000237 DebugifyFunctionPass() : FunctionPass(ID) {}
Vedant Kumar195dfd12017-12-08 21:57:28 +0000238
239 void getAnalysisUsage(AnalysisUsage &AU) const override {
240 AU.setPreservesAll();
241 }
242
243 static char ID; // Pass identification.
244};
245
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000246/// ModulePass for checking debug info inserted by -debugify, used with the
247/// legacy module pass manager.
248struct CheckDebugifyModulePass : public ModulePass {
249 bool runOnModule(Module &M) override {
Anastasis Grammenosb4344c62018-05-15 23:38:05 +0000250 return checkDebugifyMetadata(M, M.functions(), NameOfWrappedPass,
251 "CheckModuleDebugify", Strip);
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000252 }
253
Anastasis Grammenosb4344c62018-05-15 23:38:05 +0000254 CheckDebugifyModulePass(bool Strip = false, StringRef NameOfWrappedPass = "")
255 : ModulePass(ID), Strip(Strip), NameOfWrappedPass(NameOfWrappedPass) {}
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000256
257 static char ID; // Pass identification.
258
259private:
260 bool Strip;
Anastasis Grammenosb4344c62018-05-15 23:38:05 +0000261 StringRef NameOfWrappedPass;
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000262};
263
264/// FunctionPass for checking debug info inserted by -debugify-function, used
265/// with the legacy module pass manager.
266struct CheckDebugifyFunctionPass : public FunctionPass {
267 bool runOnFunction(Function &F) override {
268 Module &M = *F.getParent();
269 auto FuncIt = F.getIterator();
270 return checkDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)),
Anastasis Grammenosb4344c62018-05-15 23:38:05 +0000271 NameOfWrappedPass, "CheckFunctionDebugify", Strip);
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000272 }
273
Anastasis Grammenosb4344c62018-05-15 23:38:05 +0000274 CheckDebugifyFunctionPass(bool Strip = false, StringRef NameOfWrappedPass = "")
275 : FunctionPass(ID), Strip(Strip), NameOfWrappedPass(NameOfWrappedPass) {}
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000276
277 void getAnalysisUsage(AnalysisUsage &AU) const override {
278 AU.setPreservesAll();
279 }
280
281 static char ID; // Pass identification.
282
283private:
284 bool Strip;
Anastasis Grammenosb4344c62018-05-15 23:38:05 +0000285 StringRef NameOfWrappedPass;
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000286};
287
Vedant Kumar195dfd12017-12-08 21:57:28 +0000288} // end anonymous namespace
289
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000290ModulePass *createDebugifyModulePass() {
291 return new DebugifyModulePass();
292}
293
294FunctionPass *createDebugifyFunctionPass() {
295 return new DebugifyFunctionPass();
296}
Vedant Kumar92f7a622018-01-23 20:43:50 +0000297
Vedant Kumar775c7af2018-02-15 21:14:36 +0000298PreservedAnalyses NewPMDebugifyPass::run(Module &M, ModuleAnalysisManager &) {
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000299 applyDebugifyMetadata(M, M.functions(), "ModuleDebugify: ");
Vedant Kumar775c7af2018-02-15 21:14:36 +0000300 return PreservedAnalyses::all();
301}
302
Anastasis Grammenosb4344c62018-05-15 23:38:05 +0000303ModulePass *createCheckDebugifyModulePass(bool Strip, StringRef NameOfWrappedPass) {
304 return new CheckDebugifyModulePass(Strip, NameOfWrappedPass);
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000305}
306
Anastasis Grammenosb4344c62018-05-15 23:38:05 +0000307FunctionPass *createCheckDebugifyFunctionPass(bool Strip, StringRef NameOfWrappedPass) {
308 return new CheckDebugifyFunctionPass(Strip, NameOfWrappedPass);
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000309}
Vedant Kumar92f7a622018-01-23 20:43:50 +0000310
Vedant Kumar775c7af2018-02-15 21:14:36 +0000311PreservedAnalyses NewPMCheckDebugifyPass::run(Module &M,
312 ModuleAnalysisManager &) {
Anastasis Grammenosb4344c62018-05-15 23:38:05 +0000313 checkDebugifyMetadata(M, M.functions(), "", "CheckModuleDebugify", false);
Vedant Kumar775c7af2018-02-15 21:14:36 +0000314 return PreservedAnalyses::all();
315}
316
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000317char DebugifyModulePass::ID = 0;
318static RegisterPass<DebugifyModulePass> DM("debugify",
Vedant Kumar195dfd12017-12-08 21:57:28 +0000319 "Attach debug info to everything");
320
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000321char CheckDebugifyModulePass::ID = 0;
322static RegisterPass<CheckDebugifyModulePass> CDM("check-debugify",
Vedant Kumar195dfd12017-12-08 21:57:28 +0000323 "Check debug info from -debugify");
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000324
325char DebugifyFunctionPass::ID = 0;
326static RegisterPass<DebugifyFunctionPass> DF("debugify-function",
327 "Attach debug info to a function");
328
329char CheckDebugifyFunctionPass::ID = 0;
330static RegisterPass<CheckDebugifyFunctionPass> CDF("check-debugify-function",
331 "Check debug info from -debugify-function");