Skip to content

[WebAssembly] DEBUG_VALUEs not collected for non-first defs #136506

@SingleAccretion

Description

@SingleAccretion

In writing a test for an unrelated issue, I came across this code:

// This code differs from MachineInstr::collectDebugValues in that it scans
// the whole BB, not just contiguous DBG_VALUEs, until another definition to
// the same register is encountered.
if (!Def->getOperand(0).isReg())
return;
CurrentReg = Def->getOperand(0).getReg();
for (MachineBasicBlock::iterator MI = std::next(Def->getIterator()),
ME = Def->getParent()->end();
MI != ME; ++MI) {
// If another definition appears, stop
if (MI->definesRegister(CurrentReg, /*TRI=*/nullptr))
break;
if (MI->isDebugValue() && MI->hasDebugOperandForReg(CurrentReg))
DbgValues.push_back(&*MI);
}

This means that any non-first defs of multivalue instructions will get their DEBUG_VALUEs dropped. The reproduction is something like below:

target triple = "wasm32-unknown-unknown"

declare {i32, i32} @extern_func_multivalue(i32, i32)

define i32 @single_non_dbg_use_multivalue(i32 %0, i32 %1) !dbg !15 {
  %full_value = call {i32, i32} @extern_func_multivalue(i32 1, i32 2), !dbg !27
  %full_value_one = extractvalue {i32, i32} %full_value, 0, !dbg !27
  %full_value_two = extractvalue {i32, i32} %full_value, 1, !dbg !27
  call void @llvm.dbg.value(metadata i32 %full_value_two, metadata !16, metadata !DIExpression()), !dbg !28
  %partial_value = call {i32, i32} @extern_func_multivalue(i32 %full_value_one, i32 %full_value_two), !dbg !28
  %partial_value_one = extractvalue {i32, i32} %partial_value, 0, !dbg !28
  %partial_value_two = extractvalue {i32, i32} %partial_value, 1, !dbg !28
  call void @llvm.dbg.value(metadata i32 %partial_value_two, metadata !17, metadata !DIExpression()), !dbg !28
  ret i32 %partial_value_one, !dbg !29
}

!15 = distinct !DISubprogram(name: "single_non_dbg_use_multivalue", scope: !1, file: !1, type: !7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0)
!16 = !DILocalVariable(name: "value_used", scope: !15, type: !9)
!17 = !DILocalVariable(name: "value_unused", scope: !15, type: !9)
!27 = !DILocation(line: 27, scope: !15)
!28 = !DILocation(line: 28, scope: !15)
!29 = !DILocation(line: 29, scope: !15)

!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!2, !3}

!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "LLC", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
!1 = !DIFile(filename: "test.ll", directory: "")
!2 = !{i32 7, !"Dwarf Version", i32 4}
!3 = !{i32 2, !"Debug Info Version", i32 3}
!7 = !DISubroutineType(types: !8)
!8 = !{!9, !9, !9}
!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
> llc test.ll -mattr=+multivalue -target-abi=experimental-mv -O0 -o - --filetype=obj | llvm-dwarfdump -
0x0000000b: DW_TAG_compile_unit
              DW_AT_producer    ("LLC")
              DW_AT_language    (DW_LANG_C_plus_plus_14)
              DW_AT_name        ("test.ll")
              DW_AT_stmt_list   (0x00000000)
              DW_AT_low_pc      (0x00000002)
              DW_AT_high_pc     (0x0000002c)

0x00000022:   DW_TAG_subprogram
                DW_AT_low_pc    (0x00000002)
                DW_AT_high_pc   (0x0000002c)
                DW_AT_frame_base        (DW_OP_WASM_location 0x3 0x0, DW_OP_stack_value)
                DW_AT_name      ("single_non_dbg_use_multivalue")
                DW_AT_type      (0x0000003b "int")
                DW_AT_external  (true)

0x0000003b:   DW_TAG_base_type
                DW_AT_name      ("int")
                DW_AT_encoding  (DW_ATE_signed)
                DW_AT_byte_size (0x04)

We should expect to see the variable record for at least value_used (value_unused looks to be getting dropped earlier).

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions