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