15ffd83dbSDimitry Andric //===-- WebAssemblyDebugFixup.cpp - Debug Fixup ------------------===// 25ffd83dbSDimitry Andric // 35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65ffd83dbSDimitry Andric // 75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 85ffd83dbSDimitry Andric /// 95ffd83dbSDimitry Andric /// \file 105ffd83dbSDimitry Andric /// Several prior passes may "stackify" registers, here we ensure any references 115ffd83dbSDimitry Andric /// in such registers in debug_value instructions become stack relative also. 125ffd83dbSDimitry Andric /// This is done in a separate pass such that not all previous passes need to 135ffd83dbSDimitry Andric /// track stack depth when values get stackified. 145ffd83dbSDimitry Andric /// 155ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 165ffd83dbSDimitry Andric 175ffd83dbSDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 18fe6060f1SDimitry Andric #include "Utils/WebAssemblyUtilities.h" 195ffd83dbSDimitry Andric #include "WebAssembly.h" 205ffd83dbSDimitry Andric #include "WebAssemblyMachineFunctionInfo.h" 215ffd83dbSDimitry Andric #include "WebAssemblySubtarget.h" 225ffd83dbSDimitry Andric #include "llvm/ADT/SCCIterator.h" 235ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 245ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 255ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 265ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineLoopInfo.h" 275ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 285ffd83dbSDimitry Andric #include "llvm/CodeGen/Passes.h" 295ffd83dbSDimitry Andric #include "llvm/Support/Debug.h" 305ffd83dbSDimitry Andric #include "llvm/Support/raw_ostream.h" 315ffd83dbSDimitry Andric using namespace llvm; 325ffd83dbSDimitry Andric 335ffd83dbSDimitry Andric #define DEBUG_TYPE "wasm-debug-fixup" 345ffd83dbSDimitry Andric 355ffd83dbSDimitry Andric namespace { 365ffd83dbSDimitry Andric class WebAssemblyDebugFixup final : public MachineFunctionPass { 375ffd83dbSDimitry Andric StringRef getPassName() const override { return "WebAssembly Debug Fixup"; } 385ffd83dbSDimitry Andric 395ffd83dbSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 405ffd83dbSDimitry Andric AU.setPreservesCFG(); 415ffd83dbSDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 425ffd83dbSDimitry Andric } 435ffd83dbSDimitry Andric 445ffd83dbSDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 455ffd83dbSDimitry Andric 465ffd83dbSDimitry Andric public: 475ffd83dbSDimitry Andric static char ID; // Pass identification, replacement for typeid 485ffd83dbSDimitry Andric WebAssemblyDebugFixup() : MachineFunctionPass(ID) {} 495ffd83dbSDimitry Andric }; 505ffd83dbSDimitry Andric } // end anonymous namespace 515ffd83dbSDimitry Andric 525ffd83dbSDimitry Andric char WebAssemblyDebugFixup::ID = 0; 535ffd83dbSDimitry Andric INITIALIZE_PASS( 545ffd83dbSDimitry Andric WebAssemblyDebugFixup, DEBUG_TYPE, 555ffd83dbSDimitry Andric "Ensures debug_value's that have been stackified become stack relative", 565ffd83dbSDimitry Andric false, false) 575ffd83dbSDimitry Andric 585ffd83dbSDimitry Andric FunctionPass *llvm::createWebAssemblyDebugFixup() { 595ffd83dbSDimitry Andric return new WebAssemblyDebugFixup(); 605ffd83dbSDimitry Andric } 615ffd83dbSDimitry Andric 62*bdd1243dSDimitry Andric // At this very end of the compilation pipeline, if any DBG_VALUEs with 63*bdd1243dSDimitry Andric // registers remain, it means they are dangling info which we failed to update 64*bdd1243dSDimitry Andric // when their corresponding def instruction was transformed/moved/splitted etc. 65*bdd1243dSDimitry Andric // Because Wasm cannot access values in LLVM virtual registers in the debugger, 66*bdd1243dSDimitry Andric // these dangling DBG_VALUEs in effect kill the effect of any previous DBG_VALUE 67*bdd1243dSDimitry Andric // associated with the variable, which will appear as "optimized out". 68*bdd1243dSDimitry Andric static void nullifyDanglingDebugValues(MachineBasicBlock &MBB, 69*bdd1243dSDimitry Andric const TargetInstrInfo *TII) { 70*bdd1243dSDimitry Andric for (auto &MI : llvm::make_early_inc_range(MBB)) { 71*bdd1243dSDimitry Andric if (MI.isDebugValue() && MI.getDebugOperand(0).isReg() && 72*bdd1243dSDimitry Andric !MI.isUndefDebugValue()) { 73*bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Warning: dangling DBG_VALUE nullified: " << MI 74*bdd1243dSDimitry Andric << "\n"); 75*bdd1243dSDimitry Andric MI.getDebugOperand(0).setReg(Register()); 76*bdd1243dSDimitry Andric } 77*bdd1243dSDimitry Andric } 78*bdd1243dSDimitry Andric } 79*bdd1243dSDimitry Andric 805ffd83dbSDimitry Andric bool WebAssemblyDebugFixup::runOnMachineFunction(MachineFunction &MF) { 815ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "********** Debug Fixup **********\n" 825ffd83dbSDimitry Andric "********** Function: " 835ffd83dbSDimitry Andric << MF.getName() << '\n'); 845ffd83dbSDimitry Andric 855ffd83dbSDimitry Andric WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 865ffd83dbSDimitry Andric const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 875ffd83dbSDimitry Andric 885ffd83dbSDimitry Andric struct StackElem { 895ffd83dbSDimitry Andric unsigned Reg; 905ffd83dbSDimitry Andric MachineInstr *DebugValue; 915ffd83dbSDimitry Andric }; 925ffd83dbSDimitry Andric std::vector<StackElem> Stack; 935ffd83dbSDimitry Andric for (MachineBasicBlock &MBB : MF) { 945ffd83dbSDimitry Andric // We may insert into this list. 955ffd83dbSDimitry Andric for (auto MII = MBB.begin(); MII != MBB.end(); ++MII) { 965ffd83dbSDimitry Andric MachineInstr &MI = *MII; 975ffd83dbSDimitry Andric if (MI.isDebugValue()) { 985ffd83dbSDimitry Andric auto &MO = MI.getOperand(0); 995ffd83dbSDimitry Andric // Also check if not a $noreg: likely a DBG_VALUE we just inserted. 1005ffd83dbSDimitry Andric if (MO.isReg() && MO.getReg().isValid() && 1015ffd83dbSDimitry Andric MFI.isVRegStackified(MO.getReg())) { 1025ffd83dbSDimitry Andric // Found a DBG_VALUE with a stackified register we will 1035ffd83dbSDimitry Andric // change into a stack operand. 1045ffd83dbSDimitry Andric // Search for register rather than assume it is on top (which it 1055ffd83dbSDimitry Andric // typically is if it appears right after the def), since 1065ffd83dbSDimitry Andric // DBG_VALUE's may shift under some circumstances. 1075ffd83dbSDimitry Andric for (auto &Elem : reverse(Stack)) { 1085ffd83dbSDimitry Andric if (MO.getReg() == Elem.Reg) { 1095ffd83dbSDimitry Andric auto Depth = static_cast<unsigned>(&Elem - &Stack[0]); 1105ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "Debug Value VReg " << MO.getReg() 1115ffd83dbSDimitry Andric << " -> Stack Relative " << Depth << "\n"); 1125ffd83dbSDimitry Andric MO.ChangeToTargetIndex(WebAssembly::TI_OPERAND_STACK, Depth); 1135ffd83dbSDimitry Andric // Save the DBG_VALUE instruction that defined this stackified 1145ffd83dbSDimitry Andric // variable since later we need it to construct another one on 1155ffd83dbSDimitry Andric // pop. 1165ffd83dbSDimitry Andric Elem.DebugValue = &MI; 1175ffd83dbSDimitry Andric break; 1185ffd83dbSDimitry Andric } 1195ffd83dbSDimitry Andric } 1205ffd83dbSDimitry Andric // If the Reg was not found, we have a DBG_VALUE outside of its 1215ffd83dbSDimitry Andric // def-use range, and we leave it unmodified as reg, which means 1225ffd83dbSDimitry Andric // it will be culled later. 1235ffd83dbSDimitry Andric } 1245ffd83dbSDimitry Andric } else { 1255ffd83dbSDimitry Andric // Track stack depth. 1265ffd83dbSDimitry Andric for (MachineOperand &MO : reverse(MI.explicit_uses())) { 1275ffd83dbSDimitry Andric if (MO.isReg() && MFI.isVRegStackified(MO.getReg())) { 1285ffd83dbSDimitry Andric auto Prev = Stack.back(); 1295ffd83dbSDimitry Andric Stack.pop_back(); 1305ffd83dbSDimitry Andric assert(Prev.Reg == MO.getReg() && 1315ffd83dbSDimitry Andric "WebAssemblyDebugFixup: Pop: Register not matched!"); 132fe6060f1SDimitry Andric // We should not put a DBG_VALUE after a terminator; debug ranges 133fe6060f1SDimitry Andric // are terminated at the end of a BB anyway. 134fe6060f1SDimitry Andric if (Prev.DebugValue && !MI.isTerminator()) { 1355ffd83dbSDimitry Andric // This stackified reg is a variable that started life at 1365ffd83dbSDimitry Andric // Prev.DebugValue, so now that we're popping it we must insert 1375ffd83dbSDimitry Andric // a $noreg DBG_VALUE for the variable to end it, right after 1385ffd83dbSDimitry Andric // the current instruction. 1395ffd83dbSDimitry Andric BuildMI(*Prev.DebugValue->getParent(), std::next(MII), 140fe6060f1SDimitry Andric Prev.DebugValue->getDebugLoc(), 141fe6060f1SDimitry Andric TII->get(WebAssembly::DBG_VALUE), false, Register(), 142fe6060f1SDimitry Andric Prev.DebugValue->getOperand(2).getMetadata(), 1435ffd83dbSDimitry Andric Prev.DebugValue->getOperand(3).getMetadata()); 1445ffd83dbSDimitry Andric } 1455ffd83dbSDimitry Andric } 1465ffd83dbSDimitry Andric } 1475ffd83dbSDimitry Andric for (MachineOperand &MO : MI.defs()) { 1485ffd83dbSDimitry Andric if (MO.isReg() && MFI.isVRegStackified(MO.getReg())) { 1495ffd83dbSDimitry Andric Stack.push_back({MO.getReg(), nullptr}); 1505ffd83dbSDimitry Andric } 1515ffd83dbSDimitry Andric } 1525ffd83dbSDimitry Andric } 1535ffd83dbSDimitry Andric } 1545ffd83dbSDimitry Andric assert(Stack.empty() && 1555ffd83dbSDimitry Andric "WebAssemblyDebugFixup: Stack not empty at end of basic block!"); 156*bdd1243dSDimitry Andric 157*bdd1243dSDimitry Andric nullifyDanglingDebugValues(MBB, TII); 1585ffd83dbSDimitry Andric } 1595ffd83dbSDimitry Andric 1605ffd83dbSDimitry Andric return true; 1615ffd83dbSDimitry Andric } 162