1097a140dSpatrick //===-- WebAssemblyDebugFixup.cpp - Debug Fixup ------------------===// 2097a140dSpatrick // 3097a140dSpatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4097a140dSpatrick // See https://llvm.org/LICENSE.txt for license information. 5097a140dSpatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6097a140dSpatrick // 7097a140dSpatrick //===----------------------------------------------------------------------===// 8097a140dSpatrick /// 9097a140dSpatrick /// \file 10097a140dSpatrick /// Several prior passes may "stackify" registers, here we ensure any references 11097a140dSpatrick /// in such registers in debug_value instructions become stack relative also. 12097a140dSpatrick /// This is done in a separate pass such that not all previous passes need to 13097a140dSpatrick /// track stack depth when values get stackified. 14097a140dSpatrick /// 15097a140dSpatrick //===----------------------------------------------------------------------===// 16097a140dSpatrick 17097a140dSpatrick #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 18*73471bf0Spatrick #include "Utils/WebAssemblyUtilities.h" 19097a140dSpatrick #include "WebAssembly.h" 20097a140dSpatrick #include "WebAssemblyMachineFunctionInfo.h" 21097a140dSpatrick #include "WebAssemblySubtarget.h" 22097a140dSpatrick #include "llvm/ADT/SCCIterator.h" 23097a140dSpatrick #include "llvm/CodeGen/MachineFrameInfo.h" 24097a140dSpatrick #include "llvm/CodeGen/MachineFunction.h" 25097a140dSpatrick #include "llvm/CodeGen/MachineInstrBuilder.h" 26097a140dSpatrick #include "llvm/CodeGen/MachineLoopInfo.h" 27097a140dSpatrick #include "llvm/CodeGen/MachineRegisterInfo.h" 28097a140dSpatrick #include "llvm/CodeGen/Passes.h" 29097a140dSpatrick #include "llvm/Support/Debug.h" 30097a140dSpatrick #include "llvm/Support/raw_ostream.h" 31097a140dSpatrick using namespace llvm; 32097a140dSpatrick 33097a140dSpatrick #define DEBUG_TYPE "wasm-debug-fixup" 34097a140dSpatrick 35097a140dSpatrick namespace { 36097a140dSpatrick class WebAssemblyDebugFixup final : public MachineFunctionPass { 37097a140dSpatrick StringRef getPassName() const override { return "WebAssembly Debug Fixup"; } 38097a140dSpatrick 39097a140dSpatrick void getAnalysisUsage(AnalysisUsage &AU) const override { 40097a140dSpatrick AU.setPreservesCFG(); 41097a140dSpatrick MachineFunctionPass::getAnalysisUsage(AU); 42097a140dSpatrick } 43097a140dSpatrick 44097a140dSpatrick bool runOnMachineFunction(MachineFunction &MF) override; 45097a140dSpatrick 46097a140dSpatrick public: 47097a140dSpatrick static char ID; // Pass identification, replacement for typeid 48097a140dSpatrick WebAssemblyDebugFixup() : MachineFunctionPass(ID) {} 49097a140dSpatrick }; 50097a140dSpatrick } // end anonymous namespace 51097a140dSpatrick 52097a140dSpatrick char WebAssemblyDebugFixup::ID = 0; 53097a140dSpatrick INITIALIZE_PASS( 54097a140dSpatrick WebAssemblyDebugFixup, DEBUG_TYPE, 55097a140dSpatrick "Ensures debug_value's that have been stackified become stack relative", 56097a140dSpatrick false, false) 57097a140dSpatrick 58097a140dSpatrick FunctionPass *llvm::createWebAssemblyDebugFixup() { 59097a140dSpatrick return new WebAssemblyDebugFixup(); 60097a140dSpatrick } 61097a140dSpatrick 62097a140dSpatrick bool WebAssemblyDebugFixup::runOnMachineFunction(MachineFunction &MF) { 63097a140dSpatrick LLVM_DEBUG(dbgs() << "********** Debug Fixup **********\n" 64097a140dSpatrick "********** Function: " 65097a140dSpatrick << MF.getName() << '\n'); 66097a140dSpatrick 67097a140dSpatrick WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 68097a140dSpatrick const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 69097a140dSpatrick 70097a140dSpatrick struct StackElem { 71097a140dSpatrick unsigned Reg; 72097a140dSpatrick MachineInstr *DebugValue; 73097a140dSpatrick }; 74097a140dSpatrick std::vector<StackElem> Stack; 75097a140dSpatrick for (MachineBasicBlock &MBB : MF) { 76097a140dSpatrick // We may insert into this list. 77097a140dSpatrick for (auto MII = MBB.begin(); MII != MBB.end(); ++MII) { 78097a140dSpatrick MachineInstr &MI = *MII; 79097a140dSpatrick if (MI.isDebugValue()) { 80097a140dSpatrick auto &MO = MI.getOperand(0); 81097a140dSpatrick // Also check if not a $noreg: likely a DBG_VALUE we just inserted. 82097a140dSpatrick if (MO.isReg() && MO.getReg().isValid() && 83097a140dSpatrick MFI.isVRegStackified(MO.getReg())) { 84097a140dSpatrick // Found a DBG_VALUE with a stackified register we will 85097a140dSpatrick // change into a stack operand. 86097a140dSpatrick // Search for register rather than assume it is on top (which it 87097a140dSpatrick // typically is if it appears right after the def), since 88097a140dSpatrick // DBG_VALUE's may shift under some circumstances. 89097a140dSpatrick for (auto &Elem : reverse(Stack)) { 90097a140dSpatrick if (MO.getReg() == Elem.Reg) { 91097a140dSpatrick auto Depth = static_cast<unsigned>(&Elem - &Stack[0]); 92097a140dSpatrick LLVM_DEBUG(dbgs() << "Debug Value VReg " << MO.getReg() 93097a140dSpatrick << " -> Stack Relative " << Depth << "\n"); 94097a140dSpatrick MO.ChangeToTargetIndex(WebAssembly::TI_OPERAND_STACK, Depth); 95097a140dSpatrick // Save the DBG_VALUE instruction that defined this stackified 96097a140dSpatrick // variable since later we need it to construct another one on 97097a140dSpatrick // pop. 98097a140dSpatrick Elem.DebugValue = &MI; 99097a140dSpatrick break; 100097a140dSpatrick } 101097a140dSpatrick } 102097a140dSpatrick // If the Reg was not found, we have a DBG_VALUE outside of its 103097a140dSpatrick // def-use range, and we leave it unmodified as reg, which means 104097a140dSpatrick // it will be culled later. 105097a140dSpatrick } 106097a140dSpatrick } else { 107097a140dSpatrick // Track stack depth. 108097a140dSpatrick for (MachineOperand &MO : reverse(MI.explicit_uses())) { 109097a140dSpatrick if (MO.isReg() && MFI.isVRegStackified(MO.getReg())) { 110097a140dSpatrick auto Prev = Stack.back(); 111097a140dSpatrick Stack.pop_back(); 112097a140dSpatrick assert(Prev.Reg == MO.getReg() && 113097a140dSpatrick "WebAssemblyDebugFixup: Pop: Register not matched!"); 114*73471bf0Spatrick // We should not put a DBG_VALUE after a terminator; debug ranges 115*73471bf0Spatrick // are terminated at the end of a BB anyway. 116*73471bf0Spatrick if (Prev.DebugValue && !MI.isTerminator()) { 117097a140dSpatrick // This stackified reg is a variable that started life at 118097a140dSpatrick // Prev.DebugValue, so now that we're popping it we must insert 119097a140dSpatrick // a $noreg DBG_VALUE for the variable to end it, right after 120097a140dSpatrick // the current instruction. 121097a140dSpatrick BuildMI(*Prev.DebugValue->getParent(), std::next(MII), 122*73471bf0Spatrick Prev.DebugValue->getDebugLoc(), 123*73471bf0Spatrick TII->get(WebAssembly::DBG_VALUE), false, Register(), 124*73471bf0Spatrick Prev.DebugValue->getOperand(2).getMetadata(), 125097a140dSpatrick Prev.DebugValue->getOperand(3).getMetadata()); 126097a140dSpatrick } 127097a140dSpatrick } 128097a140dSpatrick } 129097a140dSpatrick for (MachineOperand &MO : MI.defs()) { 130097a140dSpatrick if (MO.isReg() && MFI.isVRegStackified(MO.getReg())) { 131097a140dSpatrick Stack.push_back({MO.getReg(), nullptr}); 132097a140dSpatrick } 133097a140dSpatrick } 134097a140dSpatrick } 135097a140dSpatrick } 136097a140dSpatrick assert(Stack.empty() && 137097a140dSpatrick "WebAssemblyDebugFixup: Stack not empty at end of basic block!"); 138097a140dSpatrick } 139097a140dSpatrick 140097a140dSpatrick return true; 141097a140dSpatrick } 142