1*097a140dSpatrick //===-- WebAssemblyDebugFixup.cpp - Debug Fixup ------------------===// 2*097a140dSpatrick // 3*097a140dSpatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*097a140dSpatrick // See https://llvm.org/LICENSE.txt for license information. 5*097a140dSpatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*097a140dSpatrick // 7*097a140dSpatrick //===----------------------------------------------------------------------===// 8*097a140dSpatrick /// 9*097a140dSpatrick /// \file 10*097a140dSpatrick /// Several prior passes may "stackify" registers, here we ensure any references 11*097a140dSpatrick /// in such registers in debug_value instructions become stack relative also. 12*097a140dSpatrick /// This is done in a separate pass such that not all previous passes need to 13*097a140dSpatrick /// track stack depth when values get stackified. 14*097a140dSpatrick /// 15*097a140dSpatrick //===----------------------------------------------------------------------===// 16*097a140dSpatrick 17*097a140dSpatrick #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 18*097a140dSpatrick #include "WebAssembly.h" 19*097a140dSpatrick #include "WebAssemblyMachineFunctionInfo.h" 20*097a140dSpatrick #include "WebAssemblySubtarget.h" 21*097a140dSpatrick #include "WebAssemblyUtilities.h" 22*097a140dSpatrick #include "llvm/ADT/SCCIterator.h" 23*097a140dSpatrick #include "llvm/CodeGen/MachineFrameInfo.h" 24*097a140dSpatrick #include "llvm/CodeGen/MachineFunction.h" 25*097a140dSpatrick #include "llvm/CodeGen/MachineInstrBuilder.h" 26*097a140dSpatrick #include "llvm/CodeGen/MachineLoopInfo.h" 27*097a140dSpatrick #include "llvm/CodeGen/MachineRegisterInfo.h" 28*097a140dSpatrick #include "llvm/CodeGen/Passes.h" 29*097a140dSpatrick #include "llvm/Support/Debug.h" 30*097a140dSpatrick #include "llvm/Support/raw_ostream.h" 31*097a140dSpatrick using namespace llvm; 32*097a140dSpatrick 33*097a140dSpatrick #define DEBUG_TYPE "wasm-debug-fixup" 34*097a140dSpatrick 35*097a140dSpatrick namespace { 36*097a140dSpatrick class WebAssemblyDebugFixup final : public MachineFunctionPass { 37*097a140dSpatrick StringRef getPassName() const override { return "WebAssembly Debug Fixup"; } 38*097a140dSpatrick 39*097a140dSpatrick void getAnalysisUsage(AnalysisUsage &AU) const override { 40*097a140dSpatrick AU.setPreservesCFG(); 41*097a140dSpatrick MachineFunctionPass::getAnalysisUsage(AU); 42*097a140dSpatrick } 43*097a140dSpatrick 44*097a140dSpatrick bool runOnMachineFunction(MachineFunction &MF) override; 45*097a140dSpatrick 46*097a140dSpatrick public: 47*097a140dSpatrick static char ID; // Pass identification, replacement for typeid 48*097a140dSpatrick WebAssemblyDebugFixup() : MachineFunctionPass(ID) {} 49*097a140dSpatrick }; 50*097a140dSpatrick } // end anonymous namespace 51*097a140dSpatrick 52*097a140dSpatrick char WebAssemblyDebugFixup::ID = 0; 53*097a140dSpatrick INITIALIZE_PASS( 54*097a140dSpatrick WebAssemblyDebugFixup, DEBUG_TYPE, 55*097a140dSpatrick "Ensures debug_value's that have been stackified become stack relative", 56*097a140dSpatrick false, false) 57*097a140dSpatrick 58*097a140dSpatrick FunctionPass *llvm::createWebAssemblyDebugFixup() { 59*097a140dSpatrick return new WebAssemblyDebugFixup(); 60*097a140dSpatrick } 61*097a140dSpatrick 62*097a140dSpatrick bool WebAssemblyDebugFixup::runOnMachineFunction(MachineFunction &MF) { 63*097a140dSpatrick LLVM_DEBUG(dbgs() << "********** Debug Fixup **********\n" 64*097a140dSpatrick "********** Function: " 65*097a140dSpatrick << MF.getName() << '\n'); 66*097a140dSpatrick 67*097a140dSpatrick WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 68*097a140dSpatrick const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 69*097a140dSpatrick 70*097a140dSpatrick struct StackElem { 71*097a140dSpatrick unsigned Reg; 72*097a140dSpatrick MachineInstr *DebugValue; 73*097a140dSpatrick }; 74*097a140dSpatrick std::vector<StackElem> Stack; 75*097a140dSpatrick for (MachineBasicBlock &MBB : MF) { 76*097a140dSpatrick // We may insert into this list. 77*097a140dSpatrick for (auto MII = MBB.begin(); MII != MBB.end(); ++MII) { 78*097a140dSpatrick MachineInstr &MI = *MII; 79*097a140dSpatrick if (MI.isDebugValue()) { 80*097a140dSpatrick auto &MO = MI.getOperand(0); 81*097a140dSpatrick // Also check if not a $noreg: likely a DBG_VALUE we just inserted. 82*097a140dSpatrick if (MO.isReg() && MO.getReg().isValid() && 83*097a140dSpatrick MFI.isVRegStackified(MO.getReg())) { 84*097a140dSpatrick // Found a DBG_VALUE with a stackified register we will 85*097a140dSpatrick // change into a stack operand. 86*097a140dSpatrick // Search for register rather than assume it is on top (which it 87*097a140dSpatrick // typically is if it appears right after the def), since 88*097a140dSpatrick // DBG_VALUE's may shift under some circumstances. 89*097a140dSpatrick for (auto &Elem : reverse(Stack)) { 90*097a140dSpatrick if (MO.getReg() == Elem.Reg) { 91*097a140dSpatrick auto Depth = static_cast<unsigned>(&Elem - &Stack[0]); 92*097a140dSpatrick LLVM_DEBUG(dbgs() << "Debug Value VReg " << MO.getReg() 93*097a140dSpatrick << " -> Stack Relative " << Depth << "\n"); 94*097a140dSpatrick MO.ChangeToTargetIndex(WebAssembly::TI_OPERAND_STACK, Depth); 95*097a140dSpatrick // Save the DBG_VALUE instruction that defined this stackified 96*097a140dSpatrick // variable since later we need it to construct another one on 97*097a140dSpatrick // pop. 98*097a140dSpatrick Elem.DebugValue = &MI; 99*097a140dSpatrick break; 100*097a140dSpatrick } 101*097a140dSpatrick } 102*097a140dSpatrick // If the Reg was not found, we have a DBG_VALUE outside of its 103*097a140dSpatrick // def-use range, and we leave it unmodified as reg, which means 104*097a140dSpatrick // it will be culled later. 105*097a140dSpatrick } 106*097a140dSpatrick } else { 107*097a140dSpatrick // Track stack depth. 108*097a140dSpatrick for (MachineOperand &MO : reverse(MI.explicit_uses())) { 109*097a140dSpatrick if (MO.isReg() && MFI.isVRegStackified(MO.getReg())) { 110*097a140dSpatrick auto Prev = Stack.back(); 111*097a140dSpatrick Stack.pop_back(); 112*097a140dSpatrick assert(Prev.Reg == MO.getReg() && 113*097a140dSpatrick "WebAssemblyDebugFixup: Pop: Register not matched!"); 114*097a140dSpatrick if (Prev.DebugValue) { 115*097a140dSpatrick // This stackified reg is a variable that started life at 116*097a140dSpatrick // Prev.DebugValue, so now that we're popping it we must insert 117*097a140dSpatrick // a $noreg DBG_VALUE for the variable to end it, right after 118*097a140dSpatrick // the current instruction. 119*097a140dSpatrick BuildMI(*Prev.DebugValue->getParent(), std::next(MII), 120*097a140dSpatrick Prev.DebugValue->getDebugLoc(), TII->get(WebAssembly::DBG_VALUE), false, 121*097a140dSpatrick Register(), Prev.DebugValue->getOperand(2).getMetadata(), 122*097a140dSpatrick Prev.DebugValue->getOperand(3).getMetadata()); 123*097a140dSpatrick } 124*097a140dSpatrick } 125*097a140dSpatrick } 126*097a140dSpatrick for (MachineOperand &MO : MI.defs()) { 127*097a140dSpatrick if (MO.isReg() && MFI.isVRegStackified(MO.getReg())) { 128*097a140dSpatrick Stack.push_back({MO.getReg(), nullptr}); 129*097a140dSpatrick } 130*097a140dSpatrick } 131*097a140dSpatrick } 132*097a140dSpatrick } 133*097a140dSpatrick assert(Stack.empty() && 134*097a140dSpatrick "WebAssemblyDebugFixup: Stack not empty at end of basic block!"); 135*097a140dSpatrick } 136*097a140dSpatrick 137*097a140dSpatrick return true; 138*097a140dSpatrick } 139