Index: lib/Target/WebAssembly/CMakeLists.txt =================================================================== --- lib/Target/WebAssembly/CMakeLists.txt +++ lib/Target/WebAssembly/CMakeLists.txt @@ -19,6 +19,7 @@ WebAssemblyCallIndirectFixup.cpp WebAssemblyCFGStackify.cpp WebAssemblyCFGSort.cpp + WebAssemblyDebugValueManager.cpp WebAssemblyLateEHPrepare.cpp WebAssemblyEHRestoreStackPointer.cpp WebAssemblyExceptionInfo.cpp Index: lib/Target/WebAssembly/WebAssemblyDebugValueManager.h =================================================================== --- /dev/null +++ lib/Target/WebAssembly/WebAssemblyDebugValueManager.h @@ -0,0 +1,39 @@ +//===-- WebAssemblyUtilities - WebAssembly Utility Functions ---*- C++ -*-====// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the declaration of the WebAssembly-specific +/// utility functions. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_WEBASSEMBLY_WEBASSEMBLYDEBUGVALUEMANAGER_H +#define LLVM_LIB_TARGET_WEBASSEMBLY_WEBASSEMBLYDEBUGVALUEMANAGER_H + +#include "llvm/CodeGen/MachineBasicBlock.h" + +namespace llvm { + +class WebAssemblyInstrInfo; +class WebAssemblyRegisterInfo; + +class WebAssemblyDebugValueManager { + SmallVector DbgValues; + +public: + WebAssemblyDebugValueManager(MachineInstr *Instr); + + void move(MachineInstr *Insert); + void updateReg(unsigned Reg); + void clone(MachineInstr *Insert, unsigned NewReg); +}; + +} // end namespace llvm + +#endif Index: lib/Target/WebAssembly/WebAssemblyDebugValueManager.cpp =================================================================== --- /dev/null +++ lib/Target/WebAssembly/WebAssemblyDebugValueManager.cpp @@ -0,0 +1,47 @@ +//===-- WebAssemblyUtilities.cpp - WebAssembly Utility Functions ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file implements several utility functions for WebAssembly. +/// +//===----------------------------------------------------------------------===// + +#include "WebAssemblyDebugValueManager.h" +#include "WebAssemblyMachineFunctionInfo.h" +#include "WebAssemblySubtarget.h" +#include "llvm/CodeGen/MachineInstr.h" + +using namespace llvm; + +WebAssemblyDebugValueManager::WebAssemblyDebugValueManager( + MachineInstr *Instr) { + Instr->collectDebugValues(DbgValues); +} + +void WebAssemblyDebugValueManager::move(MachineInstr *Insert) { + MachineBasicBlock *MBB = Insert->getParent(); + for (MachineInstr *DBI : DbgValues) + MBB->splice(Insert, DBI->getParent(), DBI); +} + +void WebAssemblyDebugValueManager::updateReg(unsigned Reg) { + for (auto *DBI : DbgValues) + DBI->getOperand(0).setReg(Reg); +} + +void WebAssemblyDebugValueManager::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); + MBB->insert(Insert, Clone); + } +} Index: lib/Target/WebAssembly/WebAssemblyRegStackify.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyRegStackify.cpp +++ lib/Target/WebAssembly/WebAssemblyRegStackify.cpp @@ -22,6 +22,7 @@ #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" // for WebAssembly::ARGUMENT_* #include "WebAssembly.h" +#include "WebAssemblyDebugValueManager.h" #include "WebAssemblyMachineFunctionInfo.h" #include "WebAssemblySubtarget.h" #include "WebAssemblyUtilities.h" @@ -466,27 +467,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 +476,9 @@ MachineRegisterInfo &MRI) { LLVM_DEBUG(dbgs() << "Move for single use: "; Def->dump()); + WebAssemblyDebugValueManager 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 +503,7 @@ MFI.stackifyVReg(NewReg); - UpdateDebugValuesReg(Reg, NewReg, MBB, MRI); + DefDIs.updateReg(NewReg); LLVM_DEBUG(dbgs() << " - Replaced register: "; Def->dump()); } @@ -531,29 +512,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 +522,8 @@ LLVM_DEBUG(dbgs() << "Rematerializing cheap def: "; Def.dump()); LLVM_DEBUG(dbgs() << " - for use in "; Op.getParent()->dump()); + WebAssemblyDebugValueManager DefDIs(&Def); + unsigned NewReg = MRI.createVirtualRegister(MRI.getRegClass(Reg)); TII->reMaterialize(MBB, Insert, NewReg, 0, Def, *TRI); Op.setReg(NewReg); @@ -593,10 +553,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); } return Clone; @@ -628,6 +588,8 @@ MachineRegisterInfo &MRI, const WebAssemblyInstrInfo *TII) { LLVM_DEBUG(dbgs() << "Move and tee for multi-use:"; Def->dump()); + WebAssemblyDebugValueManager DefDIs(Def); + // Move Def into place. MBB.splice(Insert, &MBB, Def); LIS.handleMove(*Def); @@ -646,7 +608,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 +626,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: 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 + +...