Skip to content

Commit efaae60

Browse files
committed
[NFC] Add DIExpression::extractLeadingOffset
Patch [2/x] to fix structured bindings debug info in SROA. It extracts a constant offset from the DIExpression if there is one and fills RemainingOps with the ops that come after it. This function will be used in a subsequent patch.
1 parent 40fe73e commit efaae60

File tree

3 files changed

+127
-0
lines changed

3 files changed

+127
-0
lines changed

llvm/include/llvm/IR/DebugInfoMetadata.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2982,6 +2982,16 @@ class DIExpression : public MDNode {
29822982
/// return true with an offset of zero.
29832983
bool extractIfOffset(int64_t &Offset) const;
29842984

2985+
/// Assuming that the expression operates on an address, extract a constant
2986+
/// offset and the succsessive ops. Return false if the expression contains
2987+
/// any incompatible ops (including non-zero DW_OP_LLVM_args - only a single
2988+
/// address operand to the expression is permitted).
2989+
///
2990+
/// We don't try very hard to interpret the expression because we assume that
2991+
/// foldConstantMath has canonicalized the expression.
2992+
bool extractLeadingOffset(int64_t &Offset,
2993+
SmallVectorImpl<uint64_t> &RemainingOps) const;
2994+
29852995
/// Returns true iff this DIExpression contains at least one instance of
29862996
/// `DW_OP_LLVM_arg, n` for all n in [0, N).
29872997
bool hasAllLocationOps(unsigned N) const;

llvm/lib/IR/DebugInfoMetadata.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1760,6 +1760,45 @@ bool DIExpression::extractIfOffset(int64_t &Offset) const {
17601760
return false;
17611761
}
17621762

1763+
bool DIExpression::extractLeadingOffset(
1764+
int64_t &Offset, SmallVectorImpl<uint64_t> &RemainingOps) const {
1765+
Offset = 0;
1766+
RemainingOps.clear();
1767+
1768+
auto SingleLocEltsOpt = getSingleLocationExpressionElements();
1769+
if (!SingleLocEltsOpt)
1770+
return false;
1771+
1772+
auto ExprOpEnd = expr_op_iterator(SingleLocEltsOpt->end());
1773+
auto ExprOpIt = expr_op_iterator(SingleLocEltsOpt->begin());
1774+
while (ExprOpIt != ExprOpEnd) {
1775+
uint64_t Op = ExprOpIt->getOp();
1776+
if (Op == dwarf::DW_OP_deref || Op == dwarf::DW_OP_deref_size ||
1777+
Op == dwarf::DW_OP_deref_type || Op == dwarf::DW_OP_LLVM_fragment ||
1778+
Op == dwarf::DW_OP_LLVM_extract_bits_zext ||
1779+
Op == dwarf::DW_OP_LLVM_extract_bits_sext) {
1780+
break;
1781+
} else if (Op == dwarf::DW_OP_plus_uconst) {
1782+
Offset += ExprOpIt->getArg(0);
1783+
} else if (Op == dwarf::DW_OP_constu) {
1784+
uint64_t Value = ExprOpIt->getArg(0);
1785+
++ExprOpIt;
1786+
if (ExprOpIt->getOp() == dwarf::DW_OP_plus)
1787+
Offset += Value;
1788+
else if (ExprOpIt->getOp() == dwarf::DW_OP_minus)
1789+
Offset -= Value;
1790+
else
1791+
return false;
1792+
} else {
1793+
// Not a const plus/minus operation or deref.
1794+
return false;
1795+
}
1796+
++ExprOpIt;
1797+
}
1798+
RemainingOps.append(ExprOpIt.getBase(), ExprOpEnd.getBase());
1799+
return true;
1800+
}
1801+
17631802
bool DIExpression::hasAllLocationOps(unsigned N) const {
17641803
SmallDenseSet<uint64_t, 4> SeenOps;
17651804
for (auto ExprOp : expr_ops())

llvm/unittests/IR/MetadataTest.cpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3870,6 +3870,84 @@ TEST_F(DIExpressionTest, createFragmentExpression) {
38703870
#undef EXPECT_INVALID_FRAGMENT
38713871
}
38723872

3873+
TEST_F(DIExpressionTest, extractLeadingOffset) {
3874+
int64_t Offset;
3875+
SmallVector<uint64_t> Remaining;
3876+
using namespace dwarf;
3877+
#define OPS(...) SmallVector<uint64_t>(ArrayRef<uint64_t>{__VA_ARGS__})
3878+
#define EXTRACT_FROM(...) \
3879+
DIExpression::get(Context, {__VA_ARGS__}) \
3880+
->extractLeadingOffset(Offset, Remaining)
3881+
// Test the number of expression inputs
3882+
// ------------------------------------
3883+
//
3884+
// Single location expressions are permitted.
3885+
EXPECT_TRUE(EXTRACT_FROM(DW_OP_plus_uconst, 2));
3886+
EXPECT_EQ(Offset, 2);
3887+
EXPECT_EQ(Remaining.size(), 0);
3888+
// This is also a single-location.
3889+
EXPECT_TRUE(EXTRACT_FROM(DW_OP_LLVM_arg, 0, DW_OP_plus_uconst, 2));
3890+
EXPECT_EQ(Offset, 2);
3891+
EXPECT_EQ(Remaining.size(), 0);
3892+
// Variadic locations are not permitted. A non-zero arg is assumed to
3893+
// indicate multiple inputs.
3894+
EXPECT_FALSE(EXTRACT_FROM(DW_OP_LLVM_arg, 1));
3895+
EXPECT_FALSE(EXTRACT_FROM(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus));
3896+
3897+
// Test offsets expressions
3898+
// ------------------------
3899+
EXPECT_TRUE(EXTRACT_FROM());
3900+
EXPECT_EQ(Offset, 0);
3901+
EXPECT_EQ(Remaining.size(), 0u);
3902+
3903+
EXPECT_TRUE(EXTRACT_FROM(DW_OP_constu, 4, DW_OP_plus));
3904+
EXPECT_EQ(Offset, 4);
3905+
EXPECT_EQ(Remaining.size(), 0u);
3906+
3907+
EXPECT_TRUE(EXTRACT_FROM(DW_OP_constu, 2, DW_OP_minus));
3908+
EXPECT_EQ(Offset, -2);
3909+
EXPECT_EQ(Remaining.size(), 0u);
3910+
3911+
EXPECT_TRUE(EXTRACT_FROM(DW_OP_plus_uconst, 8));
3912+
EXPECT_EQ(Offset, 8);
3913+
EXPECT_EQ(Remaining.size(), 0u);
3914+
3915+
EXPECT_TRUE(EXTRACT_FROM(DW_OP_plus_uconst, 4, DW_OP_constu, 2, DW_OP_minus));
3916+
EXPECT_EQ(Offset, 2);
3917+
EXPECT_EQ(Remaining.size(), 0u);
3918+
3919+
// Not all operations are permitted for simplicity. Can be added
3920+
// if needed in future.
3921+
EXPECT_FALSE(EXTRACT_FROM(DW_OP_constu, 2, DW_OP_mul));
3922+
3923+
// Test "remaining ops"
3924+
// --------------------
3925+
EXPECT_TRUE(EXTRACT_FROM(DW_OP_plus_uconst, 4, DW_OP_constu, 8, DW_OP_minus,
3926+
DW_OP_LLVM_fragment, 0, 32));
3927+
EXPECT_EQ(Remaining, OPS(DW_OP_LLVM_fragment, 0, 32));
3928+
EXPECT_EQ(Offset, -4);
3929+
3930+
EXPECT_TRUE(EXTRACT_FROM(DW_OP_deref));
3931+
EXPECT_EQ(Remaining, OPS(DW_OP_deref));
3932+
EXPECT_EQ(Offset, 0);
3933+
3934+
// Check things after the non-offset ops are added too.
3935+
EXPECT_TRUE(EXTRACT_FROM(DW_OP_plus_uconst, 2, DW_OP_deref_size, 4,
3936+
DW_OP_stack_value));
3937+
EXPECT_EQ(Remaining, OPS(DW_OP_deref_size, 4, DW_OP_stack_value));
3938+
EXPECT_EQ(Offset, 2);
3939+
3940+
// DW_OP_deref_type isn't supported in LLVM so this currently fails.
3941+
EXPECT_FALSE(EXTRACT_FROM(DW_OP_deref_type, 0));
3942+
3943+
EXPECT_TRUE(EXTRACT_FROM(DW_OP_LLVM_extract_bits_zext, 0, 8));
3944+
EXPECT_EQ(Remaining, OPS(DW_OP_LLVM_extract_bits_zext, 0, 8));
3945+
3946+
EXPECT_TRUE(EXTRACT_FROM(DW_OP_LLVM_extract_bits_sext, 4, 4));
3947+
EXPECT_EQ(Remaining, OPS(DW_OP_LLVM_extract_bits_sext, 4, 4));
3948+
#undef EXTRACT_FROM
3949+
}
3950+
38733951
TEST_F(DIExpressionTest, convertToUndefExpression) {
38743952
#define EXPECT_UNDEF_OPS_EQUAL(TestExpr, Expected) \
38753953
do { \

0 commit comments

Comments
 (0)