Index: lib/Target/WebAssembly/WebAssemblyRegStackify.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyRegStackify.cpp +++ lib/Target/WebAssembly/WebAssemblyRegStackify.cpp @@ -40,6 +40,47 @@ #define DEBUG_TYPE "wasm-reg-stackify" +class AdjacentDebugValues { + MachineInstr *Def; + SmallVector DbgValues; + +public: + AdjacentDebugValues(MachineInstr *Def) : Def(Def) { + Def->collectDebugValues(DbgValues); + } + + void move(MachineInstr *Insert) { + MachineBasicBlock *MBB = Insert->getParent(); + for (MachineInstr *DBI : DbgValues) { + MBB->splice(Insert, Def->getParent(), DBI); + LLVM_DEBUG(dbgs() << " - - Moved with DBG_VALUE: "; DBI->dump()); + } + } + + void updateReg(unsigned Reg) { + for (auto *DBI : DbgValues) { + DBI->getOperand(0).setReg(Reg); + LLVM_DEBUG(dbgs() << " - - Updated op in DBG_VALUE: "; DBI->dump()); + } + } + + void clone(MachineInstr *Insert, unsigned NewReg, + const WebAssemblyInstrInfo *TII) { + MachineBasicBlock *MBB = Insert->getParent(); + for (MachineInstr *DBI : DbgValues) { + MachineInstr &Clone = TII->duplicate(*MBB, Insert, *DBI); + for (unsigned I = 0, E = Clone.getNumOperands(); I != E; ++I) { + MachineOperand &MO = Clone.getOperand(I); + if (I == 0) { + assert(MO.isReg()); + MO.setReg(NewReg); + } + } + LLVM_DEBUG(dbgs() << " - - Cloned DBG_VALUE: "; Clone.dump()); + } + } +}; + namespace { class WebAssemblyRegStackify final : public MachineFunctionPass { StringRef getPassName() const override { @@ -474,27 +515,6 @@ } } -static void MoveDebugValues(unsigned Reg, MachineInstr *Insert, - MachineBasicBlock &MBB, MachineRegisterInfo &MRI) { - for (auto &Op : MRI.reg_operands(Reg)) { - MachineInstr *MI = Op.getParent(); - assert(MI != nullptr); - if (MI->isDebugValue() && MI->getParent() == &MBB) - MBB.splice(Insert, &MBB, MI); - } -} - -static void UpdateDebugValuesReg(unsigned Reg, unsigned NewReg, - MachineBasicBlock &MBB, - MachineRegisterInfo &MRI) { - for (auto &Op : MRI.reg_operands(Reg)) { - MachineInstr *MI = Op.getParent(); - assert(MI != nullptr); - if (MI->isDebugValue() && MI->getParent() == &MBB) - Op.setReg(NewReg); - } -} - /// A single-use def in the same block with no intervening memory or register /// dependencies; move the def down and nest it with the current instruction. static MachineInstr *MoveForSingleUse(unsigned Reg, MachineOperand &Op, @@ -504,8 +524,9 @@ MachineRegisterInfo &MRI) { LLVM_DEBUG(dbgs() << "Move for single use: "; Def->dump()); + AdjacentDebugValues DefDIs(Def); MBB.splice(Insert, &MBB, Def); - MoveDebugValues(Reg, Insert, MBB, MRI); + DefDIs.move(Insert); LIS.handleMove(*Def); if (MRI.hasOneDef(Reg) && MRI.hasOneUse(Reg)) { @@ -530,7 +551,7 @@ MFI.stackifyVReg(NewReg); - UpdateDebugValuesReg(Reg, NewReg, MBB, MRI); + DefDIs.updateReg(NewReg); LLVM_DEBUG(dbgs() << " - Replaced register: "; Def->dump()); } @@ -539,29 +560,6 @@ return Def; } -static void CloneDebugValues(unsigned Reg, MachineInstr *Insert, - unsigned TargetReg, MachineBasicBlock &MBB, - MachineRegisterInfo &MRI, - const WebAssemblyInstrInfo *TII) { - SmallPtrSet Instrs; - for (auto &Op : MRI.reg_operands(Reg)) { - MachineInstr *MI = Op.getParent(); - assert(MI != nullptr); - if (MI->isDebugValue() && MI->getParent() == &MBB && - Instrs.find(MI) == Instrs.end()) - Instrs.insert(MI); - } - for (const auto &MI : Instrs) { - MachineInstr &Clone = TII->duplicate(MBB, Insert, *MI); - for (unsigned i = 0, e = Clone.getNumOperands(); i != e; ++i) { - MachineOperand &MO = Clone.getOperand(i); - if (MO.isReg() && MO.getReg() == Reg) - MO.setReg(TargetReg); - } - LLVM_DEBUG(dbgs() << " - - Cloned DBG_VALUE: "; Clone.dump()); - } -} - /// A trivially cloneable instruction; clone it and nest the new copy with the /// current instruction. static MachineInstr *RematerializeCheapDef( @@ -572,6 +570,8 @@ LLVM_DEBUG(dbgs() << "Rematerializing cheap def: "; Def.dump()); LLVM_DEBUG(dbgs() << " - for use in "; Op.getParent()->dump()); + AdjacentDebugValues DefDIs(&Def); + unsigned NewReg = MRI.createVirtualRegister(MRI.getRegClass(Reg)); TII->reMaterialize(MBB, Insert, NewReg, 0, Def, *TRI); Op.setReg(NewReg); @@ -601,10 +601,10 @@ LIS.RemoveMachineInstrFromMaps(Def); Def.eraseFromParent(); - MoveDebugValues(Reg, &*Insert, MBB, MRI); - UpdateDebugValuesReg(Reg, NewReg, MBB, MRI); + DefDIs.move(&*Insert); + DefDIs.updateReg(NewReg); } else { - CloneDebugValues(Reg, &*Insert, NewReg, MBB, MRI, TII); + DefDIs.clone(&*Insert, NewReg, TII); } return Clone; @@ -636,6 +636,8 @@ MachineRegisterInfo &MRI, const WebAssemblyInstrInfo *TII) { LLVM_DEBUG(dbgs() << "Move and tee for multi-use:"; Def->dump()); + AdjacentDebugValues DefDIs(Def); + // Move Def into place. MBB.splice(Insert, &MBB, Def); LIS.handleMove(*Def); @@ -654,7 +656,7 @@ SlotIndex TeeIdx = LIS.InsertMachineInstrInMaps(*Tee).getRegSlot(); SlotIndex DefIdx = LIS.getInstructionIndex(*Def).getRegSlot(); - MoveDebugValues(Reg, Insert, MBB, MRI); + DefDIs.move(Insert); // Tell LiveIntervals we moved the original vreg def from Def to Tee. LiveInterval &LI = LIS.getInterval(Reg); @@ -672,8 +674,8 @@ ImposeStackOrdering(Def); ImposeStackOrdering(Tee); - CloneDebugValues(Reg, Tee, DefReg, MBB, MRI, TII); - CloneDebugValues(Reg, Insert, TeeReg, MBB, MRI, TII); + DefDIs.clone(Tee, DefReg, TII); + DefDIs.clone(Insert, TeeReg, TII); LLVM_DEBUG(dbgs() << " - Replaced register: "; Def->dump()); LLVM_DEBUG(dbgs() << " - Tee instruction: "; Tee->dump()); Index: test/DebugInfo/WebAssembly/dbg-value-move-reg-stackify.mir =================================================================== --- /dev/null +++ test/DebugInfo/WebAssembly/dbg-value-move-reg-stackify.mir @@ -0,0 +1,57 @@ +# RUN: llc < %s -run-pass=wasm-reg-stackify -x=mir 2>&1 | FileCheck %s + +# CHECK: body: +# CHECK: %1:i32 = CALL_I32 @bar, +# CHECK: DBG_VALUE %1, +# CHECK: %2:i32 = CALL_I32 @bar, +# CHECK: DBG_VALUE %2, + +--- | + target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" + target triple = "wasm32-unknown-unknown" + + declare void @foo(i32) + declare i32 @bar() + + define void @test(i64 %arg) { + unreachable + } + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!4} + !0 = distinct !DICompileUnit(language: DW_LANG_Rust, file: !2, producer: "clang LLVM (rustc version 1.30.0-dev)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !1, globals: !1) + !1 = !{} + !2 = !DIFile(filename: "", directory: "") + !3 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "&str", file: !2, size: 64, align: 32, elements: !{}, identifier: "111094d970b097647de579f9c509ef08") + !4 = !{i32 2, !"Debug Info Version", i32 3} + !5 = distinct !DILexicalBlock(scope: !6, file: !2, line: 357, column: 8) + !6 = distinct !DISubprogram(name: "testfoo", linkageName: "_testba", scope: !7, file: !2, line: 353, type: !8, isLocal: true, isDefinition: true, scopeLine: 353, flags: DIFlagPrototyped, isOptimized: true, unit: !0, templateParams: !1, retainedNodes: !9) + !7 = !DINamespace(name: "ptr", scope: null) + !8 = !DISubroutineType(types: !1) + !9 = !{!10} + !10 = !DILocalVariable(name: "val0", scope: !5, file: !2, line: 357, type: !3, align: 4) + !11 = !DILocalVariable(name: "val1", scope: !5, file: !2, line: 358, type: !3, align: 4) + !12 = !DILocalVariable(name: "val2", scope: !5, file: !2, line: 359, type: !3, align: 4) + !13 = !DILocation(line: 357, column: 12, scope: !5) + !14 = !DILocation(line: 358, column: 12, scope: !5) + !15 = !DILocation(line: 359, column: 12, scope: !5) + +--- +name: test +liveins: + - { reg: '$arguments' } +tracksRegLiveness: true +body: | + bb.0: + liveins: $arguments + %0:i64 = ARGUMENT_i64 0, implicit $arguments + %1:i32 = I32_WRAP_I64 %0:i64, implicit-def dead $arguments + DBG_VALUE %1:i32, $noreg, !10, !DIExpression(), debug-location !13; :357:12 line no:357 + %1:i32 = CALL_I32 @bar, implicit-def dead $arguments, implicit $sp32, implicit $sp64 + DBG_VALUE %1:i32, $noreg, !11, !DIExpression(), debug-location !14; :357:12 line no:357 + %1:i32 = CALL_I32 @bar, implicit-def dead $arguments, implicit $sp32, implicit $sp64 + DBG_VALUE %1:i32, $noreg, !12, !DIExpression(), debug-location !15; :357:12 line no:357 + CALL_VOID @foo, %1:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64 + RETURN_VOID implicit-def dead $arguments + +...