Index: lib/Target/WebAssembly/WebAssemblyRegStackify.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyRegStackify.cpp +++ lib/Target/WebAssembly/WebAssemblyRegStackify.cpp @@ -466,27 +466,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, @@ -496,8 +475,9 @@ MachineRegisterInfo &MRI) { LLVM_DEBUG(dbgs() << "Move for single use: "; Def->dump()); + WebAssembly::DebugValueManager 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)) { @@ -522,7 +502,7 @@ MFI.stackifyVReg(NewReg); - UpdateDebugValuesReg(Reg, NewReg, MBB, MRI); + DefDIs.updateReg(NewReg); LLVM_DEBUG(dbgs() << " - Replaced register: "; Def->dump()); } @@ -531,29 +511,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( @@ -564,6 +521,8 @@ LLVM_DEBUG(dbgs() << "Rematerializing cheap def: "; Def.dump()); LLVM_DEBUG(dbgs() << " - for use in "; Op.getParent()->dump()); + WebAssembly::DebugValueManager DefDIs(&Def); + unsigned NewReg = MRI.createVirtualRegister(MRI.getRegClass(Reg)); TII->reMaterialize(MBB, Insert, NewReg, 0, Def, *TRI); Op.setReg(NewReg); @@ -573,6 +532,8 @@ MFI.stackifyVReg(NewReg); ImposeStackOrdering(Clone); + DefDIs.reMaterialize(&*Insert, NewReg, TII, TRI); + LLVM_DEBUG(dbgs() << " - Cloned to "; Clone->dump()); // Shrink the interval. @@ -592,11 +553,7 @@ LIS.removeInterval(Reg); LIS.RemoveMachineInstrFromMaps(Def); Def.eraseFromParent(); - - MoveDebugValues(Reg, &*Insert, MBB, MRI); - UpdateDebugValuesReg(Reg, NewReg, MBB, MRI); - } else { - CloneDebugValues(Reg, &*Insert, NewReg, MBB, MRI, TII); + DefDIs.eraseFromParent(); } return Clone; @@ -628,6 +585,8 @@ MachineRegisterInfo &MRI, const WebAssemblyInstrInfo *TII) { LLVM_DEBUG(dbgs() << "Move and tee for multi-use:"; Def->dump()); + WebAssembly::DebugValueManager DefDIs(Def); + // Move Def into place. MBB.splice(Insert, &MBB, Def); LIS.handleMove(*Def); @@ -646,7 +605,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); @@ -664,8 +623,8 @@ ImposeStackOrdering(Def); ImposeStackOrdering(Tee); - CloneDebugValues(Reg, Tee, DefReg, MBB, MRI, TII); - CloneDebugValues(Reg, Insert, TeeReg, MBB, MRI, TII); + DefDIs.clone(Tee, DefReg); + DefDIs.clone(Insert, TeeReg); LLVM_DEBUG(dbgs() << " - Replaced register: "; Def->dump()); LLVM_DEBUG(dbgs() << " - Tee instruction: "; Tee->dump()); Index: lib/Target/WebAssembly/WebAssemblyUtilities.h =================================================================== --- lib/Target/WebAssembly/WebAssemblyUtilities.h +++ lib/Target/WebAssembly/WebAssemblyUtilities.h @@ -21,6 +21,8 @@ namespace llvm { class WebAssemblyFunctionInfo; +class WebAssemblyInstrInfo; +class WebAssemblyRegisterInfo; namespace WebAssembly { @@ -65,6 +67,21 @@ return Bottom; } +class DebugValueManager { + MachineInstr *Instr; + SmallVector DbgValues; + +public: + DebugValueManager(MachineInstr *Instr); + + void move(MachineInstr *Insert); + void updateReg(unsigned Reg); + void clone(MachineInstr *Insert, unsigned NewReg); + void reMaterialize(MachineInstr *Insert, unsigned NewReg, + const WebAssemblyInstrInfo *TII, + const WebAssemblyRegisterInfo *TRI); + void eraseFromParent(); +}; } // end namespace WebAssembly } // end namespace llvm Index: lib/Target/WebAssembly/WebAssemblyUtilities.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyUtilities.cpp +++ lib/Target/WebAssembly/WebAssemblyUtilities.cpp @@ -14,6 +14,7 @@ #include "WebAssemblyUtilities.h" #include "WebAssemblyMachineFunctionInfo.h" +#include "WebAssemblySubtarget.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineLoopInfo.h" using namespace llvm; @@ -347,3 +348,42 @@ } return false; } + +using namespace WebAssembly; + +DebugValueManager::DebugValueManager(MachineInstr *Instr) : Instr(Instr) { + Instr->collectDebugValues(DbgValues); +} + +void DebugValueManager::move(MachineInstr *Insert) { + MachineBasicBlock *MBB = Insert->getParent(); + for (MachineInstr *DBI : DbgValues) + MBB->splice(Insert, Instr->getParent(), DBI); +} + +void DebugValueManager::updateReg(unsigned Reg) { + for (auto *DBI : DbgValues) + DBI->getOperand(0).setReg(Reg); +} + +void DebugValueManager::clone(MachineInstr *Insert, unsigned NewReg) { + MachineBasicBlock *MBB = Insert->getParent(); + MachineFunction *MF = MBB->getParent(); + for (MachineInstr *DBI : DbgValues) { + MachineInstr *Clone = MF->CloneMachineInstr(DBI); + Clone->getOperand(0).setReg(NewReg); + } +} + +void DebugValueManager::reMaterialize(MachineInstr *Insert, unsigned NewReg, + const WebAssemblyInstrInfo *TII, + const WebAssemblyRegisterInfo *TRI) { + MachineBasicBlock *MBB = Insert->getParent(); + for (MachineInstr *DBI : DbgValues) + TII->reMaterialize(*MBB, Insert, NewReg, 0, *DBI, *TRI); +} + +void DebugValueManager::eraseFromParent() { + for (MachineInstr *DBI : DbgValues) + DBI->eraseFromParent(); +} \ No newline at end of file Index: test/DebugInfo/WebAssembly/dbg-value-move-clone.mir =================================================================== --- /dev/null +++ test/DebugInfo/WebAssembly/dbg-value-move-clone.mir @@ -0,0 +1,65 @@ +# RUN: llc < %s -run-pass=wasm-reg-stackify -x=mir 2>&1 | FileCheck %s + +# CHECK: body: +# CHECK: bb.0: +# CHECK: %[[REG1:[0-9]+]]:i32 = CONST_I32 0, +# CHECK-NEXT: DBG_VALUE %[[REG1]], +# CHECK-NEXT: CALL_VOID @foo, %[[REG1]], +# CHECK: bb.1: +# CHECK: %[[REG2:[0-9]+]]:i32 = CONST_I32 0, +# CHECK-NEXT: DBG_VALUE %[[REG2]], +# CHECK-NEXT: CALL_VOID @foo, %[[REG2]], +# CHECK: %[[REG3:[0-9]+]]:i32 = CONST_I32 0, +# CHECK-NEXT: DBG_VALUE %[[REG3]], +# CHECK-NEXT: CALL_VOID @foo, %[[REG3]], + +--- | + 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: + successors: %bb.1 + liveins: $arguments + %0:i64 = ARGUMENT_i64 0, implicit $arguments + %1:i32 = CONST_I32 0, implicit-def dead $arguments + DBG_VALUE %1:i32, $noreg, !10, !DIExpression(), debug-location !13; :357:12 line no:357 + CALL_VOID @foo, %1:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64 + + bb.1: + CALL_VOID @foo, %1:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64 + CALL_VOID @foo, %1:i32, implicit-def dead $arguments, implicit $sp32, implicit $sp64 + RETURN_VOID implicit-def dead $arguments + +... Index: test/DebugInfo/WebAssembly/dbg-value-move-reg-stackify.mir =================================================================== --- /dev/null +++ test/DebugInfo/WebAssembly/dbg-value-move-reg-stackify.mir @@ -0,0 +1,60 @@ +# RUN: llc < %s -run-pass=wasm-reg-stackify -x=mir 2>&1 | FileCheck %s + +# CHECK: body: +# CHECK: %1:i32 = I32_WRAP_I64 %0, +# CHECK-NEXT: DBG_VALUE %1, +# CHECK-NEXT: %1:i32 = CALL_I32 @bar, +# CHECK-NEXT: DBG_VALUE %1, +# CHECK-NEXT: %[[NEWREG:.*]]:i32 = CALL_I32 @bar, +# CHECK-NEXT: DBG_VALUE %[[NEWREG]], +# CHECK-NEXT: CALL_VOID @foo, %[[NEWREG]], + +--- | + 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 + +...