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