1*39584ae5SXiang1 Zhang //===- MachineCheckDebugify.cpp - Check debug info ------------------------===//
2*39584ae5SXiang1 Zhang //
3*39584ae5SXiang1 Zhang // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*39584ae5SXiang1 Zhang // See https://llvm.org/LICENSE.txt for license information.
5*39584ae5SXiang1 Zhang // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*39584ae5SXiang1 Zhang //
7*39584ae5SXiang1 Zhang //===----------------------------------------------------------------------===//
8*39584ae5SXiang1 Zhang ///
9*39584ae5SXiang1 Zhang /// \file This checks debug info after mir-debugify (+ pass-to-test). Currently
10*39584ae5SXiang1 Zhang /// it simply checks the integrity of line info in DILocation and
11*39584ae5SXiang1 Zhang /// DILocalVariable which mir-debugifiy generated before.
12*39584ae5SXiang1 Zhang //===----------------------------------------------------------------------===//
13*39584ae5SXiang1 Zhang 
14*39584ae5SXiang1 Zhang #include "llvm/CodeGen/MachineFunctionPass.h"
15*39584ae5SXiang1 Zhang #include "llvm/CodeGen/MachineModuleInfo.h"
16*39584ae5SXiang1 Zhang #include "llvm/CodeGen/Passes.h"
17*39584ae5SXiang1 Zhang #include "llvm/IR/DebugInfo.h"
18*39584ae5SXiang1 Zhang #include "llvm/InitializePasses.h"
19*39584ae5SXiang1 Zhang #include "llvm/Support/CommandLine.h"
20*39584ae5SXiang1 Zhang #include "llvm/Transforms/Utils/Debugify.h"
21*39584ae5SXiang1 Zhang 
22*39584ae5SXiang1 Zhang #define DEBUG_TYPE "mir-check-debugify"
23*39584ae5SXiang1 Zhang 
24*39584ae5SXiang1 Zhang using namespace llvm;
25*39584ae5SXiang1 Zhang 
26*39584ae5SXiang1 Zhang namespace {
27*39584ae5SXiang1 Zhang 
28*39584ae5SXiang1 Zhang struct CheckDebugMachineModule : public ModulePass {
29*39584ae5SXiang1 Zhang   bool runOnModule(Module &M) override {
30*39584ae5SXiang1 Zhang     MachineModuleInfo &MMI =
31*39584ae5SXiang1 Zhang         getAnalysis<MachineModuleInfoWrapperPass>().getMMI();
32*39584ae5SXiang1 Zhang 
33*39584ae5SXiang1 Zhang     NamedMDNode *NMD = M.getNamedMetadata("llvm.mir.debugify");
34*39584ae5SXiang1 Zhang     if (!NMD) {
35*39584ae5SXiang1 Zhang       errs() << "WARNING: Please run mir-debugify to generate "
36*39584ae5SXiang1 Zhang                 "llvm.mir.debugify metadata first.\n";
37*39584ae5SXiang1 Zhang       return false;
38*39584ae5SXiang1 Zhang     }
39*39584ae5SXiang1 Zhang 
40*39584ae5SXiang1 Zhang     auto getDebugifyOperand = [&](unsigned Idx) -> unsigned {
41*39584ae5SXiang1 Zhang       return mdconst::extract<ConstantInt>(NMD->getOperand(Idx)->getOperand(0))
42*39584ae5SXiang1 Zhang           ->getZExtValue();
43*39584ae5SXiang1 Zhang     };
44*39584ae5SXiang1 Zhang     assert(NMD->getNumOperands() == 2 &&
45*39584ae5SXiang1 Zhang            "llvm.mir.debugify should have exactly 2 operands!");
46*39584ae5SXiang1 Zhang     unsigned NumLines = getDebugifyOperand(0);
47*39584ae5SXiang1 Zhang     unsigned NumVars = getDebugifyOperand(1);
48*39584ae5SXiang1 Zhang     BitVector MissingLines{NumLines, true};
49*39584ae5SXiang1 Zhang     BitVector MissingVars{NumVars, true};
50*39584ae5SXiang1 Zhang 
51*39584ae5SXiang1 Zhang     for (Function &F : M.functions()) {
52*39584ae5SXiang1 Zhang       MachineFunction *MF = MMI.getMachineFunction(F);
53*39584ae5SXiang1 Zhang       if (!MF)
54*39584ae5SXiang1 Zhang         continue;
55*39584ae5SXiang1 Zhang       for (MachineBasicBlock &MBB : *MF) {
56*39584ae5SXiang1 Zhang         // Find missing lines.
57*39584ae5SXiang1 Zhang         // TODO: Avoid meta instructions other than dbg_val.
58*39584ae5SXiang1 Zhang         for (MachineInstr &MI : MBB) {
59*39584ae5SXiang1 Zhang           if (MI.isDebugValue())
60*39584ae5SXiang1 Zhang             continue;
61*39584ae5SXiang1 Zhang           const DebugLoc DL = MI.getDebugLoc();
62*39584ae5SXiang1 Zhang           if (DL && DL.getLine() != 0) {
63*39584ae5SXiang1 Zhang             MissingLines.reset(DL.getLine() - 1);
64*39584ae5SXiang1 Zhang             continue;
65*39584ae5SXiang1 Zhang           }
66*39584ae5SXiang1 Zhang 
67*39584ae5SXiang1 Zhang           if (!DL) {
68*39584ae5SXiang1 Zhang             errs() << "WARNING: Instruction with empty DebugLoc in function ";
69*39584ae5SXiang1 Zhang             errs() << F.getName() << " --";
70*39584ae5SXiang1 Zhang             MI.print(errs());
71*39584ae5SXiang1 Zhang           }
72*39584ae5SXiang1 Zhang         }
73*39584ae5SXiang1 Zhang 
74*39584ae5SXiang1 Zhang         // Find missing variables.
75*39584ae5SXiang1 Zhang         // TODO: Handle DBG_INSTR_REF which is under an experimental option now.
76*39584ae5SXiang1 Zhang         for (MachineInstr &MI : MBB) {
77*39584ae5SXiang1 Zhang           if (!MI.isDebugValue())
78*39584ae5SXiang1 Zhang             continue;
79*39584ae5SXiang1 Zhang           const DILocalVariable *LocalVar = MI.getDebugVariable();
80*39584ae5SXiang1 Zhang           unsigned Var = ~0U;
81*39584ae5SXiang1 Zhang 
82*39584ae5SXiang1 Zhang           (void)to_integer(LocalVar->getName(), Var, 10);
83*39584ae5SXiang1 Zhang           assert(Var <= NumVars && "Unexpected name for DILocalVariable");
84*39584ae5SXiang1 Zhang           MissingVars.reset(Var - 1);
85*39584ae5SXiang1 Zhang         }
86*39584ae5SXiang1 Zhang       }
87*39584ae5SXiang1 Zhang     }
88*39584ae5SXiang1 Zhang 
89*39584ae5SXiang1 Zhang     bool Fail = false;
90*39584ae5SXiang1 Zhang     for (unsigned Idx : MissingLines.set_bits()) {
91*39584ae5SXiang1 Zhang       errs() << "WARNING: Missing line " << Idx + 1 << "\n";
92*39584ae5SXiang1 Zhang       Fail = true;
93*39584ae5SXiang1 Zhang     }
94*39584ae5SXiang1 Zhang 
95*39584ae5SXiang1 Zhang     for (unsigned Idx : MissingVars.set_bits()) {
96*39584ae5SXiang1 Zhang       errs() << "WARNING: Missing variable " << Idx + 1 << "\n";
97*39584ae5SXiang1 Zhang       Fail = true;
98*39584ae5SXiang1 Zhang     }
99*39584ae5SXiang1 Zhang     errs() << "Machine IR debug info check: ";
100*39584ae5SXiang1 Zhang     errs() << (Fail ? "FAIL" : "PASS") << "\n";
101*39584ae5SXiang1 Zhang 
102*39584ae5SXiang1 Zhang     return false;
103*39584ae5SXiang1 Zhang   }
104*39584ae5SXiang1 Zhang 
105*39584ae5SXiang1 Zhang   CheckDebugMachineModule() : ModulePass(ID) {}
106*39584ae5SXiang1 Zhang 
107*39584ae5SXiang1 Zhang   void getAnalysisUsage(AnalysisUsage &AU) const override {
108*39584ae5SXiang1 Zhang     AU.addRequired<MachineModuleInfoWrapperPass>();
109*39584ae5SXiang1 Zhang     AU.addPreserved<MachineModuleInfoWrapperPass>();
110*39584ae5SXiang1 Zhang     AU.setPreservesCFG();
111*39584ae5SXiang1 Zhang   }
112*39584ae5SXiang1 Zhang 
113*39584ae5SXiang1 Zhang   static char ID; // Pass identification.
114*39584ae5SXiang1 Zhang };
115*39584ae5SXiang1 Zhang char CheckDebugMachineModule::ID = 0;
116*39584ae5SXiang1 Zhang 
117*39584ae5SXiang1 Zhang } // end anonymous namespace
118*39584ae5SXiang1 Zhang 
119*39584ae5SXiang1 Zhang INITIALIZE_PASS_BEGIN(CheckDebugMachineModule, DEBUG_TYPE,
120*39584ae5SXiang1 Zhang                       "Machine Check Debug Module", false, false)
121*39584ae5SXiang1 Zhang INITIALIZE_PASS_END(CheckDebugMachineModule, DEBUG_TYPE,
122*39584ae5SXiang1 Zhang                     "Machine Check Debug Module", false, false)
123*39584ae5SXiang1 Zhang 
124*39584ae5SXiang1 Zhang ModulePass *llvm::createCheckDebugMachineModulePass() {
125*39584ae5SXiang1 Zhang   return new CheckDebugMachineModule();
126*39584ae5SXiang1 Zhang }
127