Skip to content

Commit 3137fe4

Browse files
committed
[DebugInfo][DAG] Distinguish different kinds of location indirection
From SelectionDAGs point of view, debug variable locations specified with dbg.declare and dbg.addr are indirect -- they specify the address of something. But calling conventions might mean that a Value is placed on the stack somewhere, and this too is indirection. Previously this was mixed up in the "IsIndirect" field of DBG_VALUE insts; this patch separates them by encoding the indirection in a DIExpression. If we have a dbg.declare or dbg.addr, then the expression produces an address that then becomes a DWARF memory location. We can represent this by putting a DW_OP_deref on the _end_ of the expression. If a Value has been placed on the stack, then we need to put a DW_OP_deref on the _start_ of the expression, to load the Value from the stack and have the rest of the expression operate on it. Differential Revision: https://reviews.llvm.org/D69028
1 parent 9f0ff0b commit 3137fe4

File tree

2 files changed

+104
-5
lines changed

2 files changed

+104
-5
lines changed

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5493,7 +5493,6 @@ bool SelectionDAGBuilder::EmitFuncArgumentDbgValue(
54935493
MachineFunction &MF = DAG.getMachineFunction();
54945494
const TargetInstrInfo *TII = DAG.getSubtarget().getInstrInfo();
54955495

5496-
bool IsIndirect = false;
54975496
Optional<MachineOperand> Op;
54985497
// Some arguments' frame index is recorded during argument lowering.
54995498
int FI = FuncInfo.getArgumentFrameIndex(Arg);
@@ -5515,7 +5514,6 @@ bool SelectionDAGBuilder::EmitFuncArgumentDbgValue(
55155514
}
55165515
if (Reg) {
55175516
Op = MachineOperand::CreateReg(Reg, false);
5518-
IsIndirect = IsDbgDeclare;
55195517
}
55205518
}
55215519

@@ -5559,7 +5557,6 @@ bool SelectionDAGBuilder::EmitFuncArgumentDbgValue(
55595557
}
55605558

55615559
Op = MachineOperand::CreateReg(VMI->second, false);
5562-
IsIndirect = IsDbgDeclare;
55635560
} else if (ArgRegsAndSizes.size() > 1) {
55645561
// This was split due to the calling convention, and no virtual register
55655562
// mapping exists for the value.
@@ -5573,9 +5570,26 @@ bool SelectionDAGBuilder::EmitFuncArgumentDbgValue(
55735570

55745571
assert(Variable->isValidLocationForIntrinsic(DL) &&
55755572
"Expected inlined-at fields to agree");
5576-
IsIndirect = (Op->isReg()) ? IsIndirect : true;
5577-
if (IsIndirect)
5573+
5574+
// If the argument arrives in a stack slot, then what the IR thought was a
5575+
// normal Value is actually in memory, and we must add a deref to load it.
5576+
if (Op->isFI()) {
5577+
int FI = Op->getIndex();
5578+
unsigned Size = DAG.getMachineFunction().getFrameInfo().getObjectSize(FI);
5579+
if (Expr->isImplicit()) {
5580+
SmallVector<uint64_t, 2> Ops = {dwarf::DW_OP_deref_size, Size};
5581+
Expr = DIExpression::prependOpcodes(Expr, Ops);
5582+
} else {
5583+
Expr = DIExpression::prepend(Expr, DIExpression::DerefBefore);
5584+
}
5585+
}
5586+
5587+
// If this location was specified with a dbg.declare, then it and its
5588+
// expression calculate the address of the variable. Append a deref to
5589+
// force it to be a memory location.
5590+
if (IsDbgDeclare)
55785591
Expr = DIExpression::append(Expr, {dwarf::DW_OP_deref});
5592+
55795593
FuncInfo.ArgDbgValues.push_back(
55805594
BuildMI(MF, DL, TII->get(TargetOpcode::DBG_VALUE), false,
55815595
*Op, Variable, Expr));
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
; RUN: llc -stop-before=finalize-isel -o - %s -mtriple=i386-- | FileCheck %s --check-prefix=MIR
2+
; RUN: llc -o - %s -mtriple=i386-- --filetype=obj | llvm-dwarfdump - | FileCheck %s --check-prefix=DWARF --implicit-check-not=DW_TAG_subprogram
3+
; REQUIRES: object-emission
4+
;
5+
; Test that, when arguments are passed on the stack (such as i386),
6+
; variable location dereferences occur in the right place. When referring to
7+
; argument stack slots a deref must be used to load the slot first.
8+
9+
; MIR: ![[FOOVAR:[0-9]+]] = !DILocalVariable(name: "foovar"
10+
; MIR: ![[BARVAR:[0-9]+]] = !DILocalVariable(name: "barvar"
11+
; MIR: ![[BAZVAR:[0-9]+]] = !DILocalVariable(name: "bazvar"
12+
13+
; Plain i32 on the stack.
14+
; MIR-LABEL: name: foo
15+
; MIR: DBG_VALUE %fixed-stack.0, $noreg, ![[FOOVAR]],
16+
; MIR-SAME: !DIExpression(DW_OP_deref)
17+
; DWARF: DW_TAG_subprogram
18+
; DWARF-LABEL: DW_AT_name ("cheese")
19+
; DWARF: DW_TAG_variable
20+
; DWARF-NEXT: DW_AT_location (DW_OP_fbreg +4)
21+
; DWARF-NEXT: DW_AT_name ("foovar")
22+
define i8 @foo(i32 %blah) !dbg !20 {
23+
entry:
24+
call void @llvm.dbg.value(metadata i32 %blah, metadata !23, metadata !DIExpression()), !dbg !21
25+
ret i8 0, !dbg !21
26+
}
27+
28+
; Pointer on the stack that we fiddle with.
29+
; MIR-LABEL: name: bar
30+
; MIR: DBG_VALUE %fixed-stack.0, $noreg, ![[BARVAR]],
31+
; MIR-SAME: !DIExpression(DW_OP_deref_size, 4, DW_OP_plus_uconst, 4, DW_OP_stack_value)
32+
; DWARF: DW_TAG_subprogram
33+
; DWARF-LABEL: DW_AT_name ("nope")
34+
; DWARF: DW_TAG_variable
35+
; DWARF-NEXT: DW_AT_location (DW_OP_fbreg +4, DW_OP_deref_size 0x4, DW_OP_plus_uconst 0x4, DW_OP_stack_value)
36+
; DWARF-NEXT: DW_AT_name ("barvar")
37+
define i8 @bar(i32 *%blah) !dbg !30 {
38+
entry:
39+
call void @llvm.dbg.value(metadata i32* %blah, metadata !33, metadata !DIExpression(DW_OP_plus_uconst, 4, DW_OP_stack_value)), !dbg !31
40+
ret i8 0, !dbg !31
41+
}
42+
43+
; Pointer that we use as a dbg.declare variable location, after fiddling with
44+
; the pointer value.
45+
; MIR-LABEL: name: baz
46+
; MIR: DBG_VALUE %fixed-stack.0, $noreg, ![[BAZVAR]],
47+
; MIR-SAME: !DIExpression(DW_OP_deref, DW_OP_plus_uconst, 4, DW_OP_deref)
48+
; DWARF: DW_TAG_subprogram
49+
; DWARF-LABEL: DW_AT_name ("brains")
50+
; DWARF: DW_TAG_variable
51+
; DWARF-NEXT: DW_AT_location (DW_OP_fbreg +4, DW_OP_deref, DW_OP_plus_uconst 0x4)
52+
; DWARF-NEXT: DW_AT_name ("bazvar")
53+
define i8 @baz(i32 *%blah) !dbg !40 {
54+
entry:
55+
call void @llvm.dbg.declare(metadata i32* %blah, metadata !43, metadata !DIExpression(DW_OP_plus_uconst, 4)), !dbg !41
56+
ret i8 0, !dbg !41
57+
}
58+
59+
declare void @llvm.dbg.value(metadata, metadata, metadata)
60+
declare void @llvm.dbg.declare(metadata, metadata, metadata)
61+
62+
!llvm.dbg.cu = !{!0}
63+
!llvm.module.flags = !{!5}
64+
65+
!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "asdf", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
66+
!1 = !DIFile(filename: "nil", directory: "/")
67+
!2 = !{}
68+
!5 = !{i32 2, !"Debug Info Version", i32 3}
69+
!7 = !DISubroutineType(types: !2)
70+
!8 = !DIBasicType(name: "i32", size: 32, encoding: DW_ATE_signed)
71+
72+
!20 = distinct !DISubprogram(name: "cheese", linkageName: "cheese", scope: null, file: !1, line: 12, type: !7, isLocal: false, isDefinition: true, scopeLine: 12, isOptimized: true, unit: !0, retainedNodes: !22)
73+
!21 = !DILocation(line: 1, column: 1, scope: !20)
74+
!22 = !{!23}
75+
!23 = !DILocalVariable(name: "foovar", scope: !20, file: !1, line: 14, type: !8)
76+
77+
!30 = distinct !DISubprogram(name: "nope", linkageName: "nope", scope: null, file: !1, line: 12, type: !7, isLocal: false, isDefinition: true, scopeLine: 12, isOptimized: true, unit: !0, retainedNodes: !32)
78+
!31 = !DILocation(line: 1, column: 1, scope: !30)
79+
!32 = !{!33}
80+
!33 = !DILocalVariable(name: "barvar", scope: !30, file: !1, line: 14, type: !8)
81+
82+
!40 = distinct !DISubprogram(name: "brains", linkageName: "brains", scope: null, file: !1, line: 12, type: !7, isLocal: false, isDefinition: true, scopeLine: 12, isOptimized: true, unit: !0, retainedNodes: !42)
83+
!41 = !DILocation(line: 1, column: 1, scope: !40)
84+
!42 = !{!43}
85+
!43 = !DILocalVariable(name: "bazvar", scope: !40, file: !1, line: 14, type: !8)

0 commit comments

Comments
 (0)