diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyDebugValueManager.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyDebugValueManager.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyDebugValueManager.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyDebugValueManager.cpp @@ -226,6 +226,15 @@ return true; } +// Returns true if any instruction in MBB has the same debug locatio as DL. +// Also returns true if DL is an empty location. +static bool hasSameDebugLoc(const MachineBasicBlock *MBB, DebugLoc DL) { + for (const auto &MI : *MBB) + if (MI.getDebugLoc() == DL) + return true; + return false; +} + // Sink 'Def', and also sink its eligible DBG_VALUEs to the place before // 'Insert'. Convert the original DBG_VALUEs into undefs. // @@ -263,6 +272,12 @@ getSinkableDebugValues(Insert); // Sink Def first. + // + // When moving to a different BB, we preserve the debug loc only if the + // destination BB contains the same location. See + // https://llvm.org/docs/HowToUpdateDebugInfo.html#when-to-preserve-an-instruction-location. + if (Def->getParent() != MBB && !hasSameDebugLoc(MBB, Def->getDebugLoc())) + Def->setDebugLoc(DebugLoc()); MBB->splice(Insert, Def->getParent(), Def); if (DbgValues.empty()) @@ -344,6 +359,11 @@ // Clone Def first. if (CloneDef) { MachineInstr *Clone = MF->CloneMachineInstr(Def); + // When cloning to a different BB, we preserve the debug loc only if the + // destination BB contains the same location. See + // https://llvm.org/docs/HowToUpdateDebugInfo.html#when-to-preserve-an-instruction-location. + if (Def->getParent() != MBB && !hasSameDebugLoc(MBB, Def->getDebugLoc())) + Clone->setDebugLoc(DebugLoc()); if (NewReg != CurrentReg && NewReg.isValid()) Clone->getOperand(0).setReg(NewReg); MBB->insert(Insert, Clone); diff --git a/llvm/test/DebugInfo/WebAssembly/dbg-loc-reg-stackify.mir b/llvm/test/DebugInfo/WebAssembly/dbg-loc-reg-stackify.mir new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/WebAssembly/dbg-loc-reg-stackify.mir @@ -0,0 +1,125 @@ +# RUN: llc -run-pass wasm-reg-stackify %s -o - | FileCheck %s + +--- | + target triple = "wasm32-unknown-unknown" + + declare void @use(i32) + + define void @sink_same_bb() { + unreachable + } + define void @clone_same_bb() { + unreachable + } + define void @clone_different_bb_0() { + unreachable + } + define void @clone_different_bb_1() { + unreachable + } + + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!2, !3, !4} + + !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, emissionKind: FullDebug) + !1 = !DIFile(filename: "test.c", directory: "") + !2 = !{i32 7, !"Dwarf Version", i32 5} + !3 = !{i32 2, !"Debug Info Version", i32 3} + !4 = !{i32 1, !"wchar_size", i32 4} + !6 = distinct !DISubprogram(name: "sink_same_bb", scope: !1, file: !1, line: 1, type: !7, scopeLine: 1, unit: !0) + !7 = !DISubroutineType(types: !8) + !8 = !{null} +... + +--- +# Sinking within the same BB preserves the debug location. +# CHECK-LABEL: name: sink_same_bb +name: sink_same_bb +liveins: + - { reg: '$arguments' } +tracksRegLiveness: true +body: | + bb.0: + liveins: $arguments + %0:i32 = CONST_I32 1, implicit-def $arguments, debug-location !DILocation(line:10, scope:!6) + NOP implicit-def $arguments + CALL @use, %0:i32, implicit-def $arguments + RETURN implicit-def $arguments + + ; CHECK: %0:i32 = CONST_I32 1, {{.*}}, debug-location !DILocation(line: 10 + ; CHECK-NEXT: CALL @use +... + +--- +# Cloning within the same BB preserves the debug location. +# CHECK-LABEL: name: clone_same_bb +name: clone_same_bb +liveins: + - { reg: '$arguments' } +tracksRegLiveness: true +body: | + bb.0: + liveins: $arguments + %0:i32 = CONST_I32 1, implicit-def $arguments, debug-location !DILocation(line:10, scope:!6) + NOP implicit-def $arguments + CALL @use, %0:i32, implicit-def $arguments + CALL @use, %0:i32, implicit-def $arguments + RETURN implicit-def $arguments + + ; CHECK: CALL @use + ; CHECK-NEXT: %1:i32 = CONST_I32 1, {{.*}}, debug-location !DILocation(line: 10 + ; CHECK-NEXT: CALL @use +... + +--- +# Cloning to a different BB preserves the debug location in this case because +# the destination BB has an instruction that has the same debug location +# (test.c:10). +# CHECK-LABEL: name: clone_different_bb_0 +name: clone_different_bb_0 +liveins: + - { reg: '$arguments' } +tracksRegLiveness: true +body: | + bb.0: + successors: %bb.1 + liveins: $arguments + %0:i32 = CONST_I32 1, implicit-def $arguments, debug-location !DILocation(line:10, scope:!6) + BR %bb.1, implicit-def $arguments + + bb.1: + ; predecessors: %bb.0 + CALL @use, %0:i32, implicit-def $arguments, debug-location !DILocation(line:10, scope:!6) + RETURN implicit-def $arguments + + ; CHECK: bb.1: + ; CHECK: %1:i32 = CONST_I32 1, {{.*}}, debug-location !DILocation(line: 10 + ; CHECK-NEXT: CALL @use, %1, {{.*}}, debug-location !DILocation(line: 10 +... + +--- +# Cloning to a different BB does NOT preserve the debug location in this case +# because the destination BB doesn't have an instruction that has the same debug +# location (It has test.c:20 but not test.c:10). +# CHECK-LABEL: name: clone_different_bb_1 +name: clone_different_bb_1 +liveins: + - { reg: '$arguments' } +tracksRegLiveness: true +body: | + bb.0: + successors: %bb.1 + liveins: $arguments + %0:i32 = CONST_I32 1, implicit-def $arguments, debug-location !DILocation(line:10, scope:!6) + BR %bb.1, implicit-def $arguments + + bb.1: + ; predecessors: %bb.0 + CALL @use, %0:i32, implicit-def $arguments, debug-location !DILocation(line:20, scope:!6) + RETURN implicit-def $arguments + + ; CHECK: bb.1: + ; CHECK: %1:i32 = CONST_I32 1 + ; CHECK-NOT: %1:i32 = CONST_I32 1, {{.*}}, debug-location !DILocation(line: 10 + ; CHECK-NEXT: CALL @use, %1, {{.*}}, debug-location !DILocation(line: 20 +...