enum VarLocKind {
InvalidKind = 0,
RegisterKind,
- SpillLocKind
+ SpillLocKind,
+ ImmediateKind
} Kind = InvalidKind;
/// The value location. Stored separately to avoid repeatedly
uint64_t RegNo;
SpillLoc SpillLocation;
uint64_t Hash;
+ int64_t Immediate;
+ const ConstantFP *FPImm;
+ const ConstantInt *CImm;
} Loc;
VarLoc(const MachineInstr &MI, LexicalScopes &LS)
if (int RegNo = isDbgValueDescribedByReg(MI)) {
Kind = RegisterKind;
Loc.RegNo = RegNo;
+ } else if (MI.getOperand(0).isImm()) {
+ Kind = ImmediateKind;
+ Loc.Immediate = MI.getOperand(0).getImm();
+ } else if (MI.getOperand(0).isFPImm()) {
+ Kind = ImmediateKind;
+ Loc.FPImm = MI.getOperand(0).getFPImm();
+ } else if (MI.getOperand(0).isCImm()) {
+ Kind = ImmediateKind;
+ Loc.CImm = MI.getOperand(0).getCImm();
}
}
Loc.SpillLocation = {SpillBase, SpillOffset};
}
+ // Is the Loc field a constant or constant object?
+ bool isConstant() const { return Kind == ImmediateKind; }
+
/// If this variable is described by a register, return it,
/// otherwise return 0.
unsigned isDescribedByReg() const {
#endif
bool operator==(const VarLoc &Other) const {
- return Var == Other.Var && Loc.Hash == Other.Loc.Hash;
+ return Kind == Other.Kind && Var == Other.Var &&
+ Loc.Hash == Other.Loc.Hash;
}
/// This operator guarantees that VarLocs are sorted by Variable first.
OpenRanges.erase(V);
// Add the VarLoc to OpenRanges from this DBG_VALUE.
- // TODO: Currently handles DBG_VALUE which has only reg as location.
- if (isDbgValueDescribedByReg(MI)) {
+ unsigned ID;
+ if (isDbgValueDescribedByReg(MI) || MI.getOperand(0).isImm() ||
+ MI.getOperand(0).isFPImm() || MI.getOperand(0).isCImm()) {
+ // Use normal VarLoc constructor for registers and immediates.
VarLoc VL(MI, LS);
- unsigned ID = VarLocIDs.insert(VL);
+ ID = VarLocIDs.insert(VL);
+ OpenRanges.insert(ID, VL.Var);
+ } else if (MI.hasOneMemOperand()) {
+ // It's a stack spill -- fetch spill base and offset.
+ VarLoc::SpillLoc SpillLocation = extractSpillBaseRegAndOffset(MI);
+ VarLoc VL(MI, SpillLocation.SpillBase, SpillLocation.SpillOffset, LS);
+ ID = VarLocIDs.insert(VL);
OpenRanges.insert(ID, VL.Var);
+ } else {
+ // This must be an undefined location. We should leave OpenRanges closed.
+ assert(MI.getOperand(0).isReg() && MI.getOperand(0).getReg() == 0 &&
+ "Unexpected non-undef DBG_VALUE encountered");
}
}
// a new DBG_VALUE. process() will end this range however appropriate.
const VarLoc &DiffIt = VarLocIDs[ID];
const MachineInstr *DMI = &DiffIt.MI;
- MachineInstr *MI =
- BuildMI(MBB, MBB.instr_begin(), DMI->getDebugLoc(), DMI->getDesc(),
- DMI->isIndirectDebugValue(), DMI->getOperand(0).getReg(),
- DMI->getDebugVariable(), DMI->getDebugExpression());
- if (DMI->isIndirectDebugValue())
- MI->getOperand(1).setImm(DMI->getOperand(1).getImm());
+ MachineInstr *MI = nullptr;
+ if (DiffIt.isConstant()) {
+ MachineOperand MO(DMI->getOperand(0));
+ MI = BuildMI(MBB, MBB.instr_begin(), DMI->getDebugLoc(), DMI->getDesc(),
+ false, MO, DMI->getDebugVariable(),
+ DMI->getDebugExpression());
+ } else {
+ MI = BuildMI(MBB, MBB.instr_begin(), DMI->getDebugLoc(), DMI->getDesc(),
+ DMI->isIndirectDebugValue(), DMI->getOperand(0).getReg(),
+ DMI->getDebugVariable(), DMI->getDebugExpression());
+ if (DMI->isIndirectDebugValue())
+ MI->getOperand(1).setImm(DMI->getOperand(1).getImm());
+ }
LLVM_DEBUG(dbgs() << "Inserted: "; MI->dump(););
ILS.set(ID);
++NumInserted;
--- /dev/null
+# RUN: llc %s -o - -run-pass=livedebugvalues -mtriple=x86_64-unknown-unknown | FileCheck %s --check-prefix=CHECK
+# RUN: llc %s -o - -start-before=livedebugvalues -filetype=obj -mtriple=x86_64-unknown-unknown | llvm-dwarfdump - | FileCheck %s --check-prefix=RANGES
+# Check that livedebugvalues does the right thing when register and constant
+# DBG_VALUEs interact, and that their ranges are correctly terminated by the
+# debug printing backend.
+--- |
+ ; All these IR functions are duds, see the MIR below.
+ source_filename = "<stdin>"
+ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+ define i32 @foo(i32* %bees, i32* %output) !dbg !4 {
+ entry:
+ br i1 undef, label %bb1, label %bb1
+ bb1:
+ br label %bb3
+ bb2:
+ br label %bb3
+ bb3:
+ ret i32 0
+ }
+
+ define i32 @bar(i32* %bees, i32* %output) !dbg !40 {
+ entry:
+ br i1 undef, label %bb1, label %bb1
+ bb1:
+ br label %bb3
+ bb2:
+ br label %bb3
+ bb3:
+ ret i32 0
+ }
+
+ define i32 @baz(i32* %bees, i32* %output) !dbg !80 {
+ entry:
+ br i1 undef, label %bb1, label %bb1
+ bb1:
+ br label %bb3
+ bb2:
+ br label %bb3
+ bb3:
+ ret i32 0
+ }
+
+ define i32 @qux(i32* %bees, i32* %output) !dbg !120 {
+ entry:
+ br i1 undef, label %bb1, label %bb1
+ bb1:
+ br label %bb3
+ bb2:
+ br label %bb3
+ bb3:
+ ret i32 0
+ }
+
+ ; Function Attrs: nounwind readnone speculatable
+ declare void @llvm.dbg.value(metadata, metadata, metadata)
+
+ ; Function Attrs: nounwind readnone speculatable
+ declare void @llvm.dbg.declare(metadata, metadata, metadata)
+
+ ; Function Attrs: nounwind
+ declare void @llvm.stackprotector(i8*, i8**)
+
+ !llvm.module.flags = !{!0, !100}
+ !llvm.dbg.cu = !{!1}
+
+ !100 = !{i32 2, !"Dwarf Version", i32 4}
+ !0 = !{i32 2, !"Debug Info Version", i32 3}
+ !1 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !2, producer: "beards", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug)
+ !2 = !DIFile(filename: "bees.cpp", directory: ".")
+ !3 = !DILocalVariable(name: "flannel", scope: !4, file: !2, line: 1, type: !16)
+ !4 = distinct !DISubprogram(name: "nope", scope: !2, file: !2, line: 1, spFlags: DISPFlagDefinition, unit: !1, retainedNodes: !13, type: !14, isDefinition: true)
+ !5 = !DILocation(line: 0, scope: !4)
+ !6 = !DILocation(line: 1, scope: !4)
+ !7 = !DILocation(line: 2, scope: !4)
+ !8 = !DILocation(line: 4, scope: !4)
+ !9 = !DILocation(line: 5, scope: !4)
+ !10 = !DILocation(line: 6, scope: !4)
+ !11 = !DILocation(line: 7, scope: !4)
+ !12 = !DILocation(line: 8, scope: !4)
+ !13 = !{!3}
+ !14 = !DISubroutineType(types: !15)
+ !15 = !{!16}
+ !16 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
+ !40 = distinct !DISubprogram(name: "bar", scope: !2, file: !2, line: 1, spFlags: DISPFlagDefinition, unit: !1, retainedNodes: !13, type: !14, isDefinition: true)
+ !41 = !DILocalVariable(name: "towel", scope: !40, file: !2, line: 1, type: !16)
+ !42 = !DILocation(line: 40, scope: !40)
+ !80 = distinct !DISubprogram(name: "baz", scope: !2, file: !2, line: 1, spFlags: DISPFlagDefinition, unit: !1, retainedNodes: !13, type: !14, isDefinition: true)
+ !81 = !DILocalVariable(name: "socks", scope: !80, file: !2, line: 1, type: !16)
+ !82 = !DILocation(line: 40, scope: !80)
+ !120 = distinct !DISubprogram(name: "qux", scope: !2, file: !2, line: 1, spFlags: DISPFlagDefinition, unit: !1, retainedNodes: !13, type: !14, isDefinition: true)
+ !121 = !DILocalVariable(name: "shoes", scope: !120, file: !2, line: 1, type: !16)
+ !122 = !DILocation(line: 40, scope: !120)
+
+...
+---
+name: foo
+alignment: 4
+tracksRegLiveness: true
+registers: []
+liveins:
+ - { reg: '$rdi', virtual-reg: '' }
+body: |
+
+ ; Two DBG_VALUEs for eax merge into bb3, check that livedebugvalues propagates
+ ; the location.
+ ; CHECK-LABEL: name: foo
+ ; CHECK-LABEL: bb.1.bb1
+ ; CHECK: $eax = MOV32rr
+ ; CHECK-NEXT: DBG_VALUE $eax
+ ; CHECK-NEXT: JMP_1 %bb.3
+ ; CHECK-LABEL: bb.2.bb2
+ ; CHECK: $eax = ADD32ri8
+ ; CHECK-NEXT: DBG_VALUE $eax
+ ; CHECK-NEXT: JMP_1 %bb.3
+ ; CHECK-LABEL: bb.3.bb3
+ ; CHECK: DBG_VALUE $eax
+ ; Test for there being a location-list gap between bb1 and bb2, as the
+ ; variable does not have a location over the ADD32ri. The range should also
+ ; extend over the final bb.
+ ; RANGES-LABEL: DW_TAG_subprogram
+ ; RANGES: DW_AT_high_pc (0x[[NOPEHIGHPC:[0-9a-f]+]])
+ ; RANGES-LABEL: DW_AT_name ("nope")
+ ; RANGES: DW_AT_location (0x{{[0-9a-f]+}}
+ ; RANGES-NEXT: [0x{{[0-9a-f]+}}, 0x[[NOPEADDR:[0-9a-f]+]]): DW_OP_reg0 RAX
+ ; RANGES-NEXT: [
+ ; RANGES-NOT: 0x[[NOPEADDR]]
+ ; RANGES-SAME: , 0x[[NOPEHIGHPC]]): DW_OP_reg0 RAX
+
+ bb.0.entry:
+ successors: %bb.1, %bb.2
+ liveins: $rdi
+
+ $ecx = XOR32rr undef $ecx, undef $ecx, implicit-def $eflags
+ JCC_1 %bb.1, 2, implicit killed $eflags
+ JMP_1 %bb.2
+
+ bb.1.bb1 (align 4):
+ successors: %bb.3
+ liveins: $ecx, $rdi
+
+ $eax = MOV32rr killed $ecx, implicit-def $rax
+ DBG_VALUE $eax, $noreg, !3, !DIExpression(), debug-location !8
+ JMP_1 %bb.3
+
+ bb.2.bb2:
+ successors: %bb.3
+ liveins: $rax
+
+ $eax = ADD32ri8 $eax, 3, implicit-def dead $eflags, implicit killed $rax, implicit-def $rax
+ DBG_VALUE $eax, $noreg, !3, !DIExpression(), debug-location !8
+ JMP_1 %bb.3
+
+ bb.3.bb3:
+ liveins: $rax
+ RETQ $eax, debug-location !9
+
+...
+---
+name: bar
+alignment: 4
+tracksRegLiveness: true
+registers: []
+liveins:
+ - { reg: '$rdi', virtual-reg: '' }
+body: |
+ ; Two DBG_VALUEs, one for eax, the other for zero, merge into bb3. Check that
+ ; livedebugvalues does not propagate anything.
+ ; the location.
+ ; CHECK-LABEL: name: bar
+ ; CHECK-LABEL: bb.1.bb1
+ ; CHECK: $eax = MOV32rr
+ ; CHECK-NEXT: DBG_VALUE 0
+ ; CHECK-NEXT: JMP_1 %bb.3
+ ; CHECK-LABEL: bb.2.bb2
+ ; CHECK: $eax = ADD32ri8
+ ; CHECK-NEXT: DBG_VALUE $eax
+ ; CHECK-NEXT: JMP_1 %bb.3
+ ; CHECK-LABEL: bb.3.bb3
+ ; CHECK-NOT: DBG_VALUE
+ ; Test for there being a location-list gap between bb1 and bb2, the variable
+ ; should not have a location over the ADD32ri. The range of the last entry
+ ; should not cover the last block.
+ ; RANGES-LABEL: DW_TAG_subprogram
+ ; RANGES: DW_AT_high_pc (0x[[BARHIGHPC:[0-9a-f]+]])
+ ; RANGES-LABEL: DW_AT_name ("bar")
+ ; RANGES: DW_AT_location (0x{{[0-9a-f]+}}
+ ; RANGES-NEXT: [0x{{[0-9a-f]+}}, 0x[[BARADDR:[0-9a-f]+]]): DW_OP_consts +0, DW_OP_stack_value
+ ; RANGES-NEXT: [
+ ; RANGES-NOT: 0x[[BARADDR]]
+ ; RANGES-NOT: 0x[[BARHIGHPC]]
+ ; RANGES-SAME: ): DW_OP_reg0 RAX
+
+ bb.0.entry:
+ successors: %bb.1, %bb.2
+ liveins: $rdi
+
+ $ecx = XOR32rr undef $ecx, undef $ecx, implicit-def $eflags
+ JCC_1 %bb.1, 2, implicit killed $eflags
+ JMP_1 %bb.2
+
+ bb.1.bb1 (align 4):
+ successors: %bb.3
+ liveins: $ecx, $rdi
+
+ $eax = MOV32rr killed $ecx, implicit-def $rax
+ DBG_VALUE 0, $noreg, !41, !DIExpression(), debug-location !42
+ JMP_1 %bb.3
+
+ bb.2.bb2:
+ successors: %bb.3
+ liveins: $rax
+
+ $eax = ADD32ri8 $eax, 3, implicit-def dead $eflags, implicit killed $rax, implicit-def $rax
+ DBG_VALUE $eax, $noreg, !41, !DIExpression(), debug-location !42
+ JMP_1 %bb.3
+
+ bb.3.bb3:
+ liveins: $rax
+ RETQ $eax, debug-location !42
+
+...
+---
+name: baz
+alignment: 4
+tracksRegLiveness: true
+registers: []
+liveins:
+ - { reg: '$rdi', virtual-reg: '' }
+body: |
+ ; Two DBG_VALUEs, one for zero, the other for eax, merge into bb3. Check that
+ ; livedebugvalues does not propagate anything.
+ ; the location.
+ ; CHECK-LABEL: name: baz
+ ; CHECK-LABEL: bb.1.bb1
+ ; CHECK: $eax = MOV32rr
+ ; CHECK-NEXT: DBG_VALUE $eax
+ ; CHECK-NEXT: JMP_1 %bb.3
+ ; CHECK-LABEL: bb.2.bb2
+ ; CHECK: $eax = ADD32ri8
+ ; CHECK-NEXT: DBG_VALUE 0
+ ; CHECK-NEXT: JMP_1 %bb.3
+ ; CHECK-LABEL: bb.3.bb3
+ ; CHECK-NOT: DBG_VALUE
+ ; Test for there being a location-list gap between bb1 and bb2, the variable
+ ; should not have a location over the ADD32ri. The range of the last item
+ ; should not cover the last block.
+ ; RANGES-LABEL: DW_TAG_subprogram
+ ; RANGES: DW_AT_high_pc (0x[[BAZHIGHPC:[0-9a-f]+]])
+ ; RANGES-LABEL: DW_AT_name ("baz")
+ ; RANGES: DW_AT_location (0x{{[0-9a-f]+}}
+ ; RANGES-NEXT: [0x{{[0-9a-f]+}}, 0x[[BAZADDR:[0-9a-f]+]]): DW_OP_reg0 RAX
+ ; RANGES-NEXT: [
+ ; RANGES-NOT: 0x[[BAZADDR]]
+ ; RANGES-NOT: 0x[[BAZHIGHPC]]
+ ; RANGES-SAME: ): DW_OP_consts +0, DW_OP_stack_value
+
+ bb.0.entry:
+ successors: %bb.1, %bb.2
+ liveins: $rdi
+
+ $ecx = XOR32rr undef $ecx, undef $ecx, implicit-def $eflags
+ JCC_1 %bb.1, 2, implicit killed $eflags
+ JMP_1 %bb.2
+
+ bb.1.bb1 (align 4):
+ successors: %bb.3
+ liveins: $ecx, $rdi
+
+ $eax = MOV32rr killed $ecx, implicit-def $rax
+ DBG_VALUE $eax, $noreg, !81, !DIExpression(), debug-location !82
+ JMP_1 %bb.3
+
+ bb.2.bb2:
+ successors: %bb.3
+ liveins: $rax
+
+ $eax = ADD32ri8 $eax, 3, implicit-def dead $eflags, implicit killed $rax, implicit-def $rax
+ DBG_VALUE 0, $noreg, !81, !DIExpression(), debug-location !82
+ JMP_1 %bb.3
+
+ bb.3.bb3:
+ liveins: $rax
+ RETQ $eax, debug-location !82
+
+...
+---
+name: qux
+alignment: 4
+tracksRegLiveness: true
+registers: []
+liveins:
+ - { reg: '$rdi', virtual-reg: '' }
+body: |
+ ; Two DBG_VALUEs for zero merging into bb3, Check that livedebugvalues does
+ ; propagate the zero into the merging block.
+ ; CHECK-LABEL: name: qux
+ ; CHECK-LABEL: bb.1.bb1
+ ; CHECK: $eax = MOV32rr
+ ; CHECK-NEXT: DBG_VALUE 0
+ ; CHECK-NEXT: JMP_1 %bb.3
+ ; CHECK-LABEL: bb.2.bb2
+ ; CHECK: $eax = ADD32ri8
+ ; CHECK-NEXT: DBG_VALUE 0
+ ; CHECK-NEXT: JMP_1 %bb.3
+ ; CHECK-LABEL: bb.3.bb3
+ ; CHECK: DBG_VALUE 0
+ ; Test for there being a location-list gap between bb1 and bb2, the variable
+ ; should not have a location over the ADD32ri. The final entry should cover
+ ; the final block.
+ ; RANGES-LABEL: DW_TAG_subprogram
+ ; RANGES: DW_AT_high_pc (0x[[QUXHIGHPC:[0-9a-f]+]])
+ ; RANGES-LABEL: DW_AT_name ("qux")
+ ; RANGES: DW_AT_location (0x{{[0-9a-f]+}}
+ ; RANGES-NEXT: [0x{{[0-9a-f]+}}, 0x[[QUXADDR:[0-9a-f]+]]): DW_OP_consts +0, DW_OP_stack_value
+ ; RANGES-NOT: 0x[[QUXADDR]]
+ ; RANGES-NEXT: [0x{{[0-9a-f]+}}, 0x[[QUXHIGHPC]]): DW_OP_consts +0, DW_OP_stack_value
+
+ bb.0.entry:
+ successors: %bb.1, %bb.2
+ liveins: $rdi
+
+ $ecx = XOR32rr undef $ecx, undef $ecx, implicit-def $eflags
+ JCC_1 %bb.1, 2, implicit killed $eflags
+ JMP_1 %bb.2
+
+ bb.1.bb1 (align 4):
+ successors: %bb.3
+ liveins: $ecx, $rdi
+
+ $eax = MOV32rr killed $ecx, implicit-def $rax
+ DBG_VALUE 0, $noreg, !121, !DIExpression(), debug-location !122
+ JMP_1 %bb.3
+
+ bb.2.bb2:
+ successors: %bb.3
+ liveins: $rax
+
+ $eax = ADD32ri8 $eax, 3, implicit-def dead $eflags, implicit killed $rax, implicit-def $rax
+ DBG_VALUE 0, $noreg, !121, !DIExpression(), debug-location !122
+ JMP_1 %bb.3
+
+ bb.3.bb3:
+ liveins: $rax
+ RETQ $eax, debug-location !122
+
+...