blob: ba8927fd19c4b741a4bb96a0f55794a58ba28850 [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 Kumar4872535e2018-05-24 23:00:23 +0000124
125 // Claim that this synthetic debug info is valid.
126 StringRef DIVersionKey = "Debug Info Version";
127 if (!M.getModuleFlag(DIVersionKey))
128 M.addModuleFlag(Module::Warning, DIVersionKey, DEBUG_METADATA_VERSION);
129
Vedant Kumar195dfd12017-12-08 21:57:28 +0000130 return true;
131}
132
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000133bool checkDebugifyMetadata(Module &M,
134 iterator_range<Module::iterator> Functions,
Anastasis Grammenosb4344c62018-05-15 23:38:05 +0000135 StringRef NameOfWrappedPass,
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000136 StringRef Banner,
137 bool Strip) {
Vedant Kumar195dfd12017-12-08 21:57:28 +0000138 // Skip modules without debugify metadata.
139 NamedMDNode *NMD = M.getNamedMetadata("llvm.debugify");
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000140 if (!NMD) {
141 errs() << Banner << "Skipping module without debugify metadata\n";
142 return false;
143 }
Vedant Kumar195dfd12017-12-08 21:57:28 +0000144
145 auto getDebugifyOperand = [&](unsigned Idx) -> unsigned {
146 return mdconst::extract<ConstantInt>(NMD->getOperand(Idx)->getOperand(0))
147 ->getZExtValue();
148 };
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000149 assert(NMD->getNumOperands() == 2 &&
150 "llvm.debugify should have exactly 2 operands!");
Vedant Kumar195dfd12017-12-08 21:57:28 +0000151 unsigned OriginalNumLines = getDebugifyOperand(0);
152 unsigned OriginalNumVars = getDebugifyOperand(1);
153 bool HasErrors = false;
154
Vedant Kumar195dfd12017-12-08 21:57:28 +0000155 BitVector MissingLines{OriginalNumLines, true};
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000156 BitVector MissingVars{OriginalNumVars, true};
157 for (Function &F : Functions) {
Vedant Kumar17d8bba2018-02-15 21:28:38 +0000158 if (isFunctionSkipped(F))
159 continue;
160
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000161 // Find missing lines.
Vedant Kumar195dfd12017-12-08 21:57:28 +0000162 for (Instruction &I : instructions(F)) {
163 if (isa<DbgValueInst>(&I))
164 continue;
165
166 auto DL = I.getDebugLoc();
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000167 if (DL && DL.getLine() != 0) {
Vedant Kumar195dfd12017-12-08 21:57:28 +0000168 MissingLines.reset(DL.getLine() - 1);
169 continue;
170 }
171
Anastasis Grammenosd6c66782018-05-17 18:19:58 +0000172 errs() << "ERROR: Instruction with empty DebugLoc in function ";
173 errs() << F.getName() << " --";
174 I.print(errs());
175 errs() << "\n";
Vedant Kumar195dfd12017-12-08 21:57:28 +0000176 HasErrors = true;
177 }
Vedant Kumar195dfd12017-12-08 21:57:28 +0000178
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000179 // Find missing variables.
Vedant Kumar195dfd12017-12-08 21:57:28 +0000180 for (Instruction &I : instructions(F)) {
181 auto *DVI = dyn_cast<DbgValueInst>(&I);
182 if (!DVI)
183 continue;
184
185 unsigned Var = ~0U;
186 (void)to_integer(DVI->getVariable()->getName(), Var, 10);
187 assert(Var <= OriginalNumVars && "Unexpected name for DILocalVariable");
188 MissingVars.reset(Var - 1);
189 }
190 }
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000191
192 // Print the results.
193 for (unsigned Idx : MissingLines.set_bits())
Anastasis Grammenosd6c66782018-05-17 18:19:58 +0000194 errs() << "WARNING: Missing line " << Idx + 1 << "\n";
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000195
Vedant Kumar195dfd12017-12-08 21:57:28 +0000196 for (unsigned Idx : MissingVars.set_bits())
Anastasis Grammenosd6c66782018-05-17 18:19:58 +0000197 errs() << "ERROR: Missing variable " << Idx + 1 << "\n";
Vedant Kumar195dfd12017-12-08 21:57:28 +0000198 HasErrors |= MissingVars.count() > 0;
199
Vedant Kumarb70e3562018-05-24 23:00:22 +0000200 errs() << Banner;
201 if (!NameOfWrappedPass.empty())
202 errs() << " [" << NameOfWrappedPass << "]";
203 errs() << ": " << (HasErrors ? "FAIL" : "PASS") << '\n';
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000204 if (HasErrors) {
Anastasis Grammenosd6c66782018-05-17 18:19:58 +0000205 errs() << "Module IR Dump\n";
206 M.print(errs(), nullptr, false);
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000207 }
208
209 // Strip the Debugify Metadata if required.
210 if (Strip) {
211 StripDebugInfo(M);
212 M.eraseNamedMetadata(NMD);
213 return true;
214 }
215
216 return false;
Vedant Kumar195dfd12017-12-08 21:57:28 +0000217}
218
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000219/// ModulePass for attaching synthetic debug info to everything, used with the
220/// legacy module pass manager.
221struct DebugifyModulePass : public ModulePass {
222 bool runOnModule(Module &M) override {
223 return applyDebugifyMetadata(M, M.functions(), "ModuleDebugify: ");
224 }
Vedant Kumar195dfd12017-12-08 21:57:28 +0000225
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000226 DebugifyModulePass() : ModulePass(ID) {}
Vedant Kumar195dfd12017-12-08 21:57:28 +0000227
228 void getAnalysisUsage(AnalysisUsage &AU) const override {
229 AU.setPreservesAll();
230 }
231
232 static char ID; // Pass identification.
233};
234
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000235/// FunctionPass for attaching synthetic debug info to instructions within a
236/// single function, used with the legacy module pass manager.
237struct DebugifyFunctionPass : public FunctionPass {
238 bool runOnFunction(Function &F) override {
239 Module &M = *F.getParent();
240 auto FuncIt = F.getIterator();
241 return applyDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)),
242 "FunctionDebugify: ");
Vedant Kumar195dfd12017-12-08 21:57:28 +0000243 }
244
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000245 DebugifyFunctionPass() : FunctionPass(ID) {}
Vedant Kumar195dfd12017-12-08 21:57:28 +0000246
247 void getAnalysisUsage(AnalysisUsage &AU) const override {
248 AU.setPreservesAll();
249 }
250
251 static char ID; // Pass identification.
252};
253
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000254/// ModulePass for checking debug info inserted by -debugify, used with the
255/// legacy module pass manager.
256struct CheckDebugifyModulePass : public ModulePass {
257 bool runOnModule(Module &M) override {
Anastasis Grammenosb4344c62018-05-15 23:38:05 +0000258 return checkDebugifyMetadata(M, M.functions(), NameOfWrappedPass,
259 "CheckModuleDebugify", Strip);
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000260 }
261
Anastasis Grammenosb4344c62018-05-15 23:38:05 +0000262 CheckDebugifyModulePass(bool Strip = false, StringRef NameOfWrappedPass = "")
263 : ModulePass(ID), Strip(Strip), NameOfWrappedPass(NameOfWrappedPass) {}
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000264
265 static char ID; // Pass identification.
266
267private:
268 bool Strip;
Anastasis Grammenosb4344c62018-05-15 23:38:05 +0000269 StringRef NameOfWrappedPass;
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000270};
271
272/// FunctionPass for checking debug info inserted by -debugify-function, used
273/// with the legacy module pass manager.
274struct CheckDebugifyFunctionPass : public FunctionPass {
275 bool runOnFunction(Function &F) override {
276 Module &M = *F.getParent();
277 auto FuncIt = F.getIterator();
278 return checkDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)),
Vedant Kumar4872535e2018-05-24 23:00:23 +0000279 NameOfWrappedPass, "CheckFunctionDebugify",
280 Strip);
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000281 }
282
Vedant Kumar4872535e2018-05-24 23:00:23 +0000283 CheckDebugifyFunctionPass(bool Strip = false,
284 StringRef NameOfWrappedPass = "")
Anastasis Grammenosb4344c62018-05-15 23:38:05 +0000285 : FunctionPass(ID), Strip(Strip), NameOfWrappedPass(NameOfWrappedPass) {}
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000286
287 void getAnalysisUsage(AnalysisUsage &AU) const override {
288 AU.setPreservesAll();
289 }
290
291 static char ID; // Pass identification.
292
293private:
294 bool Strip;
Anastasis Grammenosb4344c62018-05-15 23:38:05 +0000295 StringRef NameOfWrappedPass;
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000296};
297
Vedant Kumar195dfd12017-12-08 21:57:28 +0000298} // end anonymous namespace
299
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000300ModulePass *createDebugifyModulePass() {
301 return new DebugifyModulePass();
302}
303
304FunctionPass *createDebugifyFunctionPass() {
305 return new DebugifyFunctionPass();
306}
Vedant Kumar92f7a622018-01-23 20:43:50 +0000307
Vedant Kumar775c7af2018-02-15 21:14:36 +0000308PreservedAnalyses NewPMDebugifyPass::run(Module &M, ModuleAnalysisManager &) {
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000309 applyDebugifyMetadata(M, M.functions(), "ModuleDebugify: ");
Vedant Kumar775c7af2018-02-15 21:14:36 +0000310 return PreservedAnalyses::all();
311}
312
Anastasis Grammenosb4344c62018-05-15 23:38:05 +0000313ModulePass *createCheckDebugifyModulePass(bool Strip, StringRef NameOfWrappedPass) {
314 return new CheckDebugifyModulePass(Strip, NameOfWrappedPass);
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000315}
316
Anastasis Grammenosb4344c62018-05-15 23:38:05 +0000317FunctionPass *createCheckDebugifyFunctionPass(bool Strip, StringRef NameOfWrappedPass) {
318 return new CheckDebugifyFunctionPass(Strip, NameOfWrappedPass);
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000319}
Vedant Kumar92f7a622018-01-23 20:43:50 +0000320
Vedant Kumar775c7af2018-02-15 21:14:36 +0000321PreservedAnalyses NewPMCheckDebugifyPass::run(Module &M,
322 ModuleAnalysisManager &) {
Anastasis Grammenosb4344c62018-05-15 23:38:05 +0000323 checkDebugifyMetadata(M, M.functions(), "", "CheckModuleDebugify", false);
Vedant Kumar775c7af2018-02-15 21:14:36 +0000324 return PreservedAnalyses::all();
325}
326
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000327char DebugifyModulePass::ID = 0;
328static RegisterPass<DebugifyModulePass> DM("debugify",
Vedant Kumar195dfd12017-12-08 21:57:28 +0000329 "Attach debug info to everything");
330
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000331char CheckDebugifyModulePass::ID = 0;
332static RegisterPass<CheckDebugifyModulePass> CDM("check-debugify",
Vedant Kumar195dfd12017-12-08 21:57:28 +0000333 "Check debug info from -debugify");
Vedant Kumar595ba1d2018-05-15 00:29:27 +0000334
335char DebugifyFunctionPass::ID = 0;
336static RegisterPass<DebugifyFunctionPass> DF("debugify-function",
337 "Attach debug info to a function");
338
339char CheckDebugifyFunctionPass::ID = 0;
340static RegisterPass<CheckDebugifyFunctionPass> CDF("check-debugify-function",
341 "Check debug info from -debugify-function");