Skip to content

Commit 438181a

Browse files
[DebugInfo] Handle DW_OP_LLVM_extract_bits in SROA
This doesn't need any work to be done in SROA itself, but rather in functions that it uses. Specifically: * DIExpression::createFragmentExpression is made to understand DW_OP_LLVM_extract_bits * valueCoversEntireFragment is made to check the active bits instead of the fragment size, so that it handles extract_bits correctly
1 parent ec81c9b commit 438181a

File tree

4 files changed

+283
-5
lines changed

4 files changed

+283
-5
lines changed

llvm/include/llvm/IR/DebugInfoMetadata.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2910,6 +2910,12 @@ class DIExpression : public MDNode {
29102910
}
29112911
};
29122912

2913+
/// Return the number of bits that have an active value, i.e. those that
2914+
/// aren't known to be zero/sign (depending on the type of Var) and which
2915+
/// are within the size of this fragment (if it is one). If we can't deduce
2916+
/// anything from the expression this will return the size of Var.
2917+
std::optional<uint64_t> getActiveBits(DIVariable *Var);
2918+
29132919
/// Retrieve the details of this fragment expression.
29142920
static std::optional<FragmentInfo> getFragmentInfo(expr_op_iterator Start,
29152921
expr_op_iterator End);

llvm/lib/IR/DebugInfoMetadata.cpp

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1679,6 +1679,41 @@ DIExpression::getFragmentInfo(expr_op_iterator Start, expr_op_iterator End) {
16791679
return std::nullopt;
16801680
}
16811681

1682+
std::optional<uint64_t> DIExpression::getActiveBits(DIVariable *Var) {
1683+
std::optional<uint64_t> InitialActiveBits = Var->getSizeInBits();
1684+
std::optional<uint64_t> ActiveBits = InitialActiveBits;
1685+
for (auto Op : expr_ops()) {
1686+
switch (Op.getOp()) {
1687+
default:
1688+
// We assume the worst case for anything we don't currently handle and
1689+
// revert to the initial active bits.
1690+
ActiveBits = InitialActiveBits;
1691+
break;
1692+
case dwarf::DW_OP_LLVM_extract_bits_zext:
1693+
case dwarf::DW_OP_LLVM_extract_bits_sext: {
1694+
// We can't handle an extract whose sign doesn't match that of the
1695+
// variable.
1696+
std::optional<DIBasicType::Signedness> VarSign = Var->getSignedness();
1697+
bool VarSigned = (VarSign == DIBasicType::Signedness::Signed);
1698+
bool OpSigned = (Op.getOp() == dwarf::DW_OP_LLVM_extract_bits_sext);
1699+
if (!VarSign || VarSigned != OpSigned) {
1700+
ActiveBits = InitialActiveBits;
1701+
break;
1702+
}
1703+
[[fallthrough]];
1704+
}
1705+
case dwarf::DW_OP_LLVM_fragment:
1706+
// Extract or fragment narrows the active bits
1707+
if (ActiveBits)
1708+
ActiveBits = std::min(*ActiveBits, Op.getArg(1));
1709+
else
1710+
ActiveBits = Op.getArg(1);
1711+
break;
1712+
}
1713+
}
1714+
return ActiveBits;
1715+
}
1716+
16821717
void DIExpression::appendOffset(SmallVectorImpl<uint64_t> &Ops,
16831718
int64_t Offset) {
16841719
if (Offset > 0) {
@@ -1931,6 +1966,8 @@ std::optional<DIExpression *> DIExpression::createFragmentExpression(
19311966
// Track whether it's safe to split the value at the top of the DWARF stack,
19321967
// assuming that it'll be used as an implicit location value.
19331968
bool CanSplitValue = true;
1969+
// Track whether we need to add a fragment expression to the end of Expr.
1970+
bool EmitFragment = true;
19341971
// Copy over the expression, but leave off any trailing DW_OP_LLVM_fragment.
19351972
if (Expr) {
19361973
for (auto Op : Expr->expr_ops()) {
@@ -1966,6 +2003,11 @@ std::optional<DIExpression *> DIExpression::createFragmentExpression(
19662003
return std::nullopt;
19672004
break;
19682005
case dwarf::DW_OP_LLVM_fragment: {
2006+
// If we've decided we don't need a fragment then give up if we see that
2007+
// there's already a fragment expression.
2008+
// FIXME: We could probably do better here
2009+
if (!EmitFragment)
2010+
return std::nullopt;
19692011
// Make the new offset point into the existing fragment.
19702012
uint64_t FragmentOffsetInBits = Op.getArg(0);
19712013
uint64_t FragmentSizeInBits = Op.getArg(1);
@@ -1975,15 +2017,38 @@ std::optional<DIExpression *> DIExpression::createFragmentExpression(
19752017
OffsetInBits += FragmentOffsetInBits;
19762018
continue;
19772019
}
2020+
case dwarf::DW_OP_LLVM_extract_bits_zext:
2021+
case dwarf::DW_OP_LLVM_extract_bits_sext: {
2022+
// If we're extracting bits from inside of the fragment that we're
2023+
// creating then we don't have a fragment after all, and just need to
2024+
// adjust the offset that we're extracting from.
2025+
uint64_t ExtractOffsetInBits = Op.getArg(0);
2026+
uint64_t ExtractSizeInBits = Op.getArg(1);
2027+
if (ExtractOffsetInBits >= OffsetInBits &&
2028+
ExtractOffsetInBits + ExtractSizeInBits <=
2029+
OffsetInBits + SizeInBits) {
2030+
Ops.push_back(Op.getOp());
2031+
Ops.push_back(ExtractOffsetInBits - OffsetInBits);
2032+
Ops.push_back(ExtractSizeInBits);
2033+
EmitFragment = false;
2034+
continue;
2035+
}
2036+
// If the extracted bits aren't fully contained within the fragment then
2037+
// give up.
2038+
// FIXME: We could probably do better here
2039+
return std::nullopt;
2040+
}
19782041
}
19792042
Op.appendToVector(Ops);
19802043
}
19812044
}
19822045
assert((!Expr->isImplicit() || CanSplitValue) && "Expr can't be split");
19832046
assert(Expr && "Unknown DIExpression");
1984-
Ops.push_back(dwarf::DW_OP_LLVM_fragment);
1985-
Ops.push_back(OffsetInBits);
1986-
Ops.push_back(SizeInBits);
2047+
if (EmitFragment) {
2048+
Ops.push_back(dwarf::DW_OP_LLVM_fragment);
2049+
Ops.push_back(OffsetInBits);
2050+
Ops.push_back(SizeInBits);
2051+
}
19872052
return DIExpression::get(Expr->getContext(), Ops);
19882053
}
19892054

llvm/lib/Transforms/Utils/Local.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1603,7 +1603,8 @@ static bool PhiHasDebugValue(DILocalVariable *DIVar,
16031603
static bool valueCoversEntireFragment(Type *ValTy, DbgVariableIntrinsic *DII) {
16041604
const DataLayout &DL = DII->getModule()->getDataLayout();
16051605
TypeSize ValueSize = DL.getTypeAllocSizeInBits(ValTy);
1606-
if (std::optional<uint64_t> FragmentSize = DII->getFragmentSizeInBits())
1606+
if (std::optional<uint64_t> FragmentSize =
1607+
DII->getExpression()->getActiveBits(DII->getVariable()))
16071608
return TypeSize::isKnownGE(ValueSize, TypeSize::getFixed(*FragmentSize));
16081609

16091610
// We can't always calculate the size of the DI variable (e.g. if it is a
@@ -1629,7 +1630,8 @@ static bool valueCoversEntireFragment(Type *ValTy, DbgVariableIntrinsic *DII) {
16291630
static bool valueCoversEntireFragment(Type *ValTy, DbgVariableRecord *DVR) {
16301631
const DataLayout &DL = DVR->getModule()->getDataLayout();
16311632
TypeSize ValueSize = DL.getTypeAllocSizeInBits(ValTy);
1632-
if (std::optional<uint64_t> FragmentSize = DVR->getFragmentSizeInBits())
1633+
if (std::optional<uint64_t> FragmentSize =
1634+
DVR->getExpression()->getActiveBits(DVR->getVariable()))
16331635
return TypeSize::isKnownGE(ValueSize, TypeSize::getFixed(*FragmentSize));
16341636

16351637
// We can't always calculate the size of the DI variable (e.g. if it is a
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
2+
; RUN: opt -passes='sroa<preserve-cfg>' %s -S | FileCheck %s
3+
; RUN: opt -passes='sroa<modify-cfg>' %s -S | FileCheck %s
4+
5+
declare void @llvm.dbg.declare(metadata, metadata, metadata) #0
6+
7+
; The alloca is split into two fragments: variable x is in the first, variables y and z are in the second
8+
define i8 @test1(i32 %arg) {
9+
; CHECK-LABEL: define i8 @test1(
10+
; CHECK-SAME: i32 [[ARG:%.*]]) {
11+
; CHECK-NEXT: entry:
12+
; CHECK-NEXT: [[PTR_SROA_0_0_EXTRACT_TRUNC:%.*]] = trunc i32 [[ARG]] to i8
13+
; CHECK-NEXT: tail call void @llvm.dbg.value(metadata i8 [[PTR_SROA_0_0_EXTRACT_TRUNC]], metadata [[META2:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 0, 8)), !dbg [[DBG7:![0-9]+]]
14+
; CHECK-NEXT: [[PTR_SROA_2_0_EXTRACT_SHIFT:%.*]] = lshr i32 [[ARG]], 8
15+
; CHECK-NEXT: [[PTR_SROA_2_0_EXTRACT_TRUNC:%.*]] = trunc i32 [[PTR_SROA_2_0_EXTRACT_SHIFT]] to i24
16+
; CHECK-NEXT: tail call void @llvm.dbg.value(metadata i24 [[PTR_SROA_2_0_EXTRACT_TRUNC]], metadata [[META8:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 8, 16)), !dbg [[DBG7]]
17+
; CHECK-NEXT: tail call void @llvm.dbg.value(metadata i24 [[PTR_SROA_2_0_EXTRACT_TRUNC]], metadata [[META9:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_extract_bits_sext, 0, 8)), !dbg [[DBG7]]
18+
; CHECK-NEXT: ret i8 [[PTR_SROA_0_0_EXTRACT_TRUNC]]
19+
;
20+
entry:
21+
%ptr = alloca i32, align 4
22+
call void @llvm.dbg.declare(metadata ptr %ptr, metadata !2, metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 0, 8)), !dbg !7
23+
call void @llvm.dbg.declare(metadata ptr %ptr, metadata !9, metadata !DIExpression(DW_OP_LLVM_extract_bits_sext, 8, 8)), !dbg !7
24+
call void @llvm.dbg.declare(metadata ptr %ptr, metadata !8, metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 16, 16)), !dbg !7
25+
store i32 %arg, ptr %ptr, align 4
26+
%ret = load i8, ptr %ptr, align 4
27+
ret i8 %ret
28+
}
29+
30+
; The alloca is split into three fragments corresponding to the variables x, y, z
31+
define i8 @test2(i32 %arg1, i8 %arg2) {
32+
; CHECK-LABEL: define i8 @test2(
33+
; CHECK-SAME: i32 [[ARG1:%.*]], i8 [[ARG2:%.*]]) {
34+
; CHECK-NEXT: entry:
35+
; CHECK-NEXT: [[PTR_SROA_0_0_EXTRACT_TRUNC:%.*]] = trunc i32 [[ARG1]] to i8
36+
; CHECK-NEXT: tail call void @llvm.dbg.value(metadata i8 [[PTR_SROA_0_0_EXTRACT_TRUNC]], metadata [[META2]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 0, 8)), !dbg [[DBG7]]
37+
; CHECK-NEXT: [[PTR_SROA_2_0_EXTRACT_SHIFT:%.*]] = lshr i32 [[ARG1]], 8
38+
; CHECK-NEXT: [[PTR_SROA_2_0_EXTRACT_TRUNC:%.*]] = trunc i32 [[PTR_SROA_2_0_EXTRACT_SHIFT]] to i16
39+
; CHECK-NEXT: tail call void @llvm.dbg.value(metadata i16 [[PTR_SROA_2_0_EXTRACT_TRUNC]], metadata [[META9]], metadata !DIExpression(DW_OP_LLVM_extract_bits_sext, 0, 16)), !dbg [[DBG7]]
40+
; CHECK-NEXT: [[PTR_SROA_21_0_EXTRACT_SHIFT:%.*]] = lshr i32 [[ARG1]], 24
41+
; CHECK-NEXT: [[PTR_SROA_21_0_EXTRACT_TRUNC:%.*]] = trunc i32 [[PTR_SROA_21_0_EXTRACT_SHIFT]] to i8
42+
; CHECK-NEXT: tail call void @llvm.dbg.value(metadata i8 [[PTR_SROA_21_0_EXTRACT_TRUNC]], metadata [[META8]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 0, 8)), !dbg [[DBG7]]
43+
; CHECK-NEXT: tail call void @llvm.dbg.value(metadata i8 [[ARG2]], metadata [[META8]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 0, 8)), !dbg [[DBG7]]
44+
; CHECK-NEXT: ret i8 [[PTR_SROA_0_0_EXTRACT_TRUNC]]
45+
;
46+
entry:
47+
%ptr = alloca i32, align 4
48+
call void @llvm.dbg.declare(metadata ptr %ptr, metadata !2, metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 0, 8)), !dbg !7
49+
call void @llvm.dbg.declare(metadata ptr %ptr, metadata !9, metadata !DIExpression(DW_OP_LLVM_extract_bits_sext, 8, 16)), !dbg !7
50+
call void @llvm.dbg.declare(metadata ptr %ptr, metadata !8, metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 24, 8)), !dbg !7
51+
store i32 %arg1, ptr %ptr, align 4
52+
%gep = getelementptr i8, ptr %ptr, i32 3
53+
store i8 %arg2, ptr %gep, align 1
54+
%ret = load i8, ptr %ptr, align 4
55+
ret i8 %ret
56+
}
57+
58+
; The alloca is split into two fragments, with variable x being half in one and half in the other
59+
; FIXME: We currently generate no debug info for x in this case
60+
define i8 @test3(i32 %arg) {
61+
; CHECK-LABEL: define i8 @test3(
62+
; CHECK-SAME: i32 [[ARG:%.*]]) {
63+
; CHECK-NEXT: entry:
64+
; CHECK-NEXT: [[PTR_SROA_0_0_EXTRACT_TRUNC:%.*]] = trunc i32 [[ARG]] to i8
65+
; CHECK-NEXT: [[PTR_SROA_2_0_EXTRACT_SHIFT:%.*]] = lshr i32 [[ARG]], 8
66+
; CHECK-NEXT: [[PTR_SROA_2_0_EXTRACT_TRUNC:%.*]] = trunc i32 [[PTR_SROA_2_0_EXTRACT_SHIFT]] to i24
67+
; CHECK-NEXT: ret i8 [[PTR_SROA_0_0_EXTRACT_TRUNC]]
68+
;
69+
entry:
70+
%ptr = alloca i32, align 4
71+
call void @llvm.dbg.declare(metadata ptr %ptr, metadata !2, metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 0, 16)), !dbg !7
72+
store i32 %arg, ptr %ptr, align 4
73+
%ret = load i8, ptr %ptr, align 4
74+
ret i8 %ret
75+
}
76+
77+
; The alloca is split into two fragments, with variable y being half in one and half in the other
78+
; FIXME: We currently generate no debug info for y in this case
79+
define i16 @test4(i32 %arg) {
80+
; CHECK-LABEL: define i16 @test4(
81+
; CHECK-SAME: i32 [[ARG:%.*]]) {
82+
; CHECK-NEXT: entry:
83+
; CHECK-NEXT: [[PTR_SROA_0_0_EXTRACT_TRUNC:%.*]] = trunc i32 [[ARG]] to i16
84+
; CHECK-NEXT: tail call void @llvm.dbg.value(metadata i16 [[PTR_SROA_0_0_EXTRACT_TRUNC]], metadata [[META2]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 0, 8)), !dbg [[DBG7]]
85+
; CHECK-NEXT: [[PTR_SROA_2_0_EXTRACT_SHIFT:%.*]] = lshr i32 [[ARG]], 16
86+
; CHECK-NEXT: [[PTR_SROA_2_0_EXTRACT_TRUNC:%.*]] = trunc i32 [[PTR_SROA_2_0_EXTRACT_SHIFT]] to i16
87+
; CHECK-NEXT: tail call void @llvm.dbg.value(metadata i16 [[PTR_SROA_2_0_EXTRACT_TRUNC]], metadata [[META8]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 8, 8)), !dbg [[DBG7]]
88+
; CHECK-NEXT: ret i16 [[PTR_SROA_0_0_EXTRACT_TRUNC]]
89+
;
90+
entry:
91+
%ptr = alloca i32, align 4
92+
call void @llvm.dbg.declare(metadata ptr %ptr, metadata !2, metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 0, 8)), !dbg !7
93+
call void @llvm.dbg.declare(metadata ptr %ptr, metadata !9, metadata !DIExpression(DW_OP_LLVM_extract_bits_sext, 8, 16)), !dbg !7
94+
call void @llvm.dbg.declare(metadata ptr %ptr, metadata !8, metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 24, 8)), !dbg !7
95+
store i32 %arg, ptr %ptr, align 4
96+
%ret = load i16, ptr %ptr, align 4
97+
ret i16 %ret
98+
}
99+
100+
; Struct where the first element is an ordinary char, the second is a bitfield of two elements, and the third is padding
101+
%struct.struct_t = type <{ i8, i16, i8 }>
102+
define i8 @test5(i32 %arg) {
103+
; CHECK-LABEL: define i8 @test5(
104+
; CHECK-SAME: i32 [[ARG:%.*]]) {
105+
; CHECK-NEXT: entry:
106+
; CHECK-NEXT: [[PTR_SROA_0_0_EXTRACT_TRUNC:%.*]] = trunc i32 [[ARG]] to i8
107+
; CHECK-NEXT: tail call void @llvm.dbg.value(metadata i8 [[PTR_SROA_0_0_EXTRACT_TRUNC]], metadata [[META11:![0-9]+]], metadata !DIExpression()), !dbg [[DBG7]]
108+
; CHECK-NEXT: [[PTR_SROA_2_0_EXTRACT_SHIFT:%.*]] = lshr i32 [[ARG]], 8
109+
; CHECK-NEXT: [[PTR_SROA_2_0_EXTRACT_TRUNC:%.*]] = trunc i32 [[PTR_SROA_2_0_EXTRACT_SHIFT]] to i24
110+
; CHECK-NEXT: tail call void @llvm.dbg.value(metadata i24 [[PTR_SROA_2_0_EXTRACT_TRUNC]], metadata [[META8]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 8, 8)), !dbg [[DBG7]]
111+
; CHECK-NEXT: tail call void @llvm.dbg.value(metadata i24 [[PTR_SROA_2_0_EXTRACT_TRUNC]], metadata [[META9]], metadata !DIExpression(DW_OP_LLVM_extract_bits_sext, 0, 8)), !dbg [[DBG7]]
112+
; CHECK-NEXT: ret i8 [[PTR_SROA_0_0_EXTRACT_TRUNC]]
113+
;
114+
entry:
115+
%ptr = alloca %struct.struct_t, align 4
116+
call void @llvm.dbg.declare(metadata ptr %ptr, metadata !11, metadata !DIExpression()), !dbg !7
117+
call void @llvm.dbg.declare(metadata ptr %ptr, metadata !9, metadata !DIExpression(DW_OP_LLVM_extract_bits_sext, 8, 8)), !dbg !7
118+
call void @llvm.dbg.declare(metadata ptr %ptr, metadata !8, metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 16, 8)), !dbg !7
119+
store i32 %arg, ptr %ptr, align 4
120+
%ret = load i8, ptr %ptr, align 4
121+
ret i8 %ret
122+
}
123+
124+
; Sign mismatch between extract expression and debug variable type.
125+
define i8 @test6(i32 %arg1, i8 %arg2) {
126+
; CHECK-LABEL: define i8 @test6(
127+
; CHECK-SAME: i32 [[ARG1:%.*]], i8 [[ARG2:%.*]]) {
128+
; CHECK-NEXT: entry:
129+
; CHECK-NEXT: [[PTR_SROA_0_0_EXTRACT_TRUNC:%.*]] = trunc i32 [[ARG1]] to i8
130+
; CHECK-NEXT: tail call void @llvm.dbg.value(metadata i8 undef, metadata [[META2]], metadata !DIExpression(DW_OP_LLVM_extract_bits_sext, 0, 8)), !dbg [[DBG7]]
131+
; CHECK-NEXT: [[PTR_SROA_2_0_EXTRACT_SHIFT:%.*]] = lshr i32 [[ARG1]], 8
132+
; CHECK-NEXT: [[PTR_SROA_2_0_EXTRACT_TRUNC:%.*]] = trunc i32 [[PTR_SROA_2_0_EXTRACT_SHIFT]] to i16
133+
; CHECK-NEXT: tail call void @llvm.dbg.value(metadata i16 undef, metadata [[META9]], metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 0, 16)), !dbg [[DBG7]]
134+
; CHECK-NEXT: [[PTR_SROA_21_0_EXTRACT_SHIFT:%.*]] = lshr i32 [[ARG1]], 24
135+
; CHECK-NEXT: [[PTR_SROA_21_0_EXTRACT_TRUNC:%.*]] = trunc i32 [[PTR_SROA_21_0_EXTRACT_SHIFT]] to i8
136+
; CHECK-NEXT: tail call void @llvm.dbg.value(metadata i8 undef, metadata [[META8]], metadata !DIExpression(DW_OP_LLVM_extract_bits_sext, 0, 8)), !dbg [[DBG7]]
137+
; CHECK-NEXT: tail call void @llvm.dbg.value(metadata i8 undef, metadata [[META8]], metadata !DIExpression(DW_OP_LLVM_extract_bits_sext, 0, 8)), !dbg [[DBG7]]
138+
; CHECK-NEXT: ret i8 [[PTR_SROA_0_0_EXTRACT_TRUNC]]
139+
;
140+
entry:
141+
%ptr = alloca i32, align 4
142+
call void @llvm.dbg.declare(metadata ptr %ptr, metadata !2, metadata !DIExpression(DW_OP_LLVM_extract_bits_sext, 0, 8)), !dbg !7
143+
call void @llvm.dbg.declare(metadata ptr %ptr, metadata !9, metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 8, 16)), !dbg !7
144+
call void @llvm.dbg.declare(metadata ptr %ptr, metadata !8, metadata !DIExpression(DW_OP_LLVM_extract_bits_sext, 24, 8)), !dbg !7
145+
store i32 %arg1, ptr %ptr, align 4
146+
%gep = getelementptr i8, ptr %ptr, i32 3
147+
store i8 %arg2, ptr %gep, align 1
148+
%ret = load i8, ptr %ptr, align 4
149+
ret i8 %ret
150+
}
151+
152+
; Combine extract_bits and fragment in a way such that the bottom 8 bits of
153+
; the alloca are the top 8 bits of variable x and vice versa.
154+
; FIXME: We currently don't handle this and generate no debug info
155+
define i8 @test7(i32 %arg1, i8 %arg2) {
156+
; CHECK-LABEL: define i8 @test7(
157+
; CHECK-SAME: i32 [[ARG1:%.*]], i8 [[ARG2:%.*]]) {
158+
; CHECK-NEXT: entry:
159+
; CHECK-NEXT: [[PTR_SROA_0_0_EXTRACT_TRUNC:%.*]] = trunc i32 [[ARG1]] to i8
160+
; CHECK-NEXT: [[PTR_SROA_2_0_EXTRACT_SHIFT:%.*]] = lshr i32 [[ARG1]], 8
161+
; CHECK-NEXT: [[PTR_SROA_2_0_EXTRACT_TRUNC:%.*]] = trunc i32 [[PTR_SROA_2_0_EXTRACT_SHIFT]] to i16
162+
; CHECK-NEXT: [[PTR_SROA_21_0_EXTRACT_SHIFT:%.*]] = lshr i32 [[ARG1]], 24
163+
; CHECK-NEXT: [[PTR_SROA_21_0_EXTRACT_TRUNC:%.*]] = trunc i32 [[PTR_SROA_21_0_EXTRACT_SHIFT]] to i8
164+
; CHECK-NEXT: ret i8 [[PTR_SROA_0_0_EXTRACT_TRUNC]]
165+
;
166+
entry:
167+
%ptr = alloca i32, align 4
168+
call void @llvm.dbg.declare(metadata ptr %ptr, metadata !2, metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 0, 8, DW_OP_LLVM_fragment, 24, 8)), !dbg !7
169+
call void @llvm.dbg.declare(metadata ptr %ptr, metadata !2, metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 8, 16, DW_OP_LLVM_fragment, 8, 16)), !dbg !7
170+
call void @llvm.dbg.declare(metadata ptr %ptr, metadata !2, metadata !DIExpression(DW_OP_LLVM_extract_bits_zext, 24, 8, DW_OP_LLVM_fragment, 0, 8)), !dbg !7
171+
store i32 %arg1, ptr %ptr, align 4
172+
%gep = getelementptr i8, ptr %ptr, i32 3
173+
store i8 %arg2, ptr %gep, align 1
174+
%ret = load i8, ptr %ptr, align 4
175+
ret i8 %ret
176+
}
177+
178+
!llvm.module.flags = !{!0, !1}
179+
!0 = !{i32 7, !"Dwarf Version", i32 5}
180+
!1 = !{i32 2, !"Debug Info Version", i32 3}
181+
!2 = !DILocalVariable(name: "x", scope: !3, type: !6)
182+
!3 = distinct !DISubprogram(name: "test", unit: !4)
183+
!4 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !5, emissionKind: FullDebug)
184+
!5 = !DIFile(filename: "dbg-bit-piece.cpp", directory: "")
185+
!6 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
186+
!7 = !DILocation(line: 0, column: 0, scope: !3)
187+
!8 = !DILocalVariable(name: "z", scope: !3, type: !6)
188+
!9 = !DILocalVariable(name: "y", scope: !3, type: !10)
189+
!10 = !DIBasicType(name: "signed int", size: 32, encoding: DW_ATE_signed)
190+
!11 = !DILocalVariable(name: "x", scope: !3, type: !12)
191+
!12 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
192+
193+
;.
194+
; CHECK: [[META2]] = !DILocalVariable(name: "x", scope: [[META3:![0-9]+]], type: [[META6:![0-9]+]])
195+
; CHECK: [[META3]] = distinct !DISubprogram(name: "test", scope: null, spFlags: DISPFlagDefinition, unit: [[META4:![0-9]+]])
196+
; CHECK: [[META4]] = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: [[META5:![0-9]+]], isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug)
197+
; CHECK: [[META5]] = !DIFile(filename: "dbg-bit-piece.cpp", directory: "")
198+
; CHECK: [[META6]] = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
199+
; CHECK: [[DBG7]] = !DILocation(line: 0, scope: [[META3]])
200+
; CHECK: [[META8]] = !DILocalVariable(name: "z", scope: [[META3]], type: [[META6]])
201+
; CHECK: [[META9]] = !DILocalVariable(name: "y", scope: [[META3]], type: [[META10:![0-9]+]])
202+
; CHECK: [[META10]] = !DIBasicType(name: "signed int", size: 32, encoding: DW_ATE_signed)
203+
; CHECK: [[META11]] = !DILocalVariable(name: "x", scope: [[META3]], type: [[META12:![0-9]+]])
204+
; CHECK: [[META12]] = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
205+
;.

0 commit comments

Comments
 (0)