Skip to content

[NFC] Allow fragment expressions in extractIfOffset #69006

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions llvm/lib/IR/DebugInfoMetadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1673,18 +1673,21 @@ bool DIExpression::extractIfOffset(int64_t &Offset) const {
return false;
auto SingleLocElts = *SingleLocEltsOpt;

if (SingleLocElts.size() == 0) {
unsigned FragmentOpsCount = isFragment() ? 3 : 0;

if (SingleLocElts.size() == FragmentOpsCount) {
Offset = 0;
return true;
}

if (SingleLocElts.size() == 2 &&
if (SingleLocElts.size() == 2 + FragmentOpsCount &&
SingleLocElts[0] == dwarf::DW_OP_plus_uconst) {
Offset = SingleLocElts[1];
return true;
}

if (SingleLocElts.size() == 3 && SingleLocElts[0] == dwarf::DW_OP_constu) {
if (SingleLocElts.size() == 3 + FragmentOpsCount &&
SingleLocElts[0] == dwarf::DW_OP_constu) {
if (SingleLocElts[2] == dwarf::DW_OP_plus) {
Offset = SingleLocElts[1];
return true;
Expand Down
51 changes: 51 additions & 0 deletions llvm/unittests/IR/MetadataTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3511,6 +3511,57 @@ TEST_F(DIExpressionTest, isEqualExpression) {
#undef GET_EXPR
}

TEST_F(DIExpressionTest, extractIfOffset) {
#define GET_EXPR(...) DIExpression::get(Context, {__VA_ARGS__})
#define GET_FRAG(...) \
DIExpression::get(Context, {__VA_ARGS__, dwarf::DW_OP_LLVM_fragment, 0, 32})
#define EXPECT_OFFSET_IMPL(Offset, Success, Expr) \
do { \
int64_t ActualOffset; \
bool Result = Expr->extractIfOffset(ActualOffset); \
EXPECT_EQ(Success, Result); \
if (Success) { \
EXPECT_EQ(Offset, ActualOffset); \
} \
} while (0)
#define EXPECT_OFFSET_EQ(Offset, Expr) EXPECT_OFFSET_IMPL(Offset, true, Expr)
#define EXPECT_NO_OFFSET(Expr) EXPECT_OFFSET_IMPL(0, false, Expr)

// Check extractIfOffset behaves as expected with and without a fragment
// in the expression. extractIfOffset reads a constant offset out from the
// expression. It fails for all but exactly these with and without fragments:
// no expression
// DW_OP_plus_uconst, <u>
// DW_OP_constu, <u>, DW_OP_plus/minus
EXPECT_OFFSET_EQ(0, GET_EXPR());
EXPECT_OFFSET_EQ(0, GET_EXPR(dwarf::DW_OP_LLVM_fragment, 0, 32));

EXPECT_OFFSET_EQ(1, GET_EXPR(dwarf::DW_OP_plus_uconst, 1));
EXPECT_OFFSET_EQ(1, GET_FRAG(dwarf::DW_OP_plus_uconst, 1));

EXPECT_OFFSET_EQ(2, GET_EXPR(dwarf::DW_OP_constu, 2, dwarf::DW_OP_plus));
EXPECT_OFFSET_EQ(2, GET_FRAG(dwarf::DW_OP_constu, 2, dwarf::DW_OP_plus));

EXPECT_OFFSET_EQ(-3, GET_EXPR(dwarf::DW_OP_constu, 3, dwarf::DW_OP_minus));
EXPECT_OFFSET_EQ(-3, GET_FRAG(dwarf::DW_OP_constu, 3, dwarf::DW_OP_minus));

// Test some failure cases, e.g. unsupported operations and too many
// operations.
EXPECT_NO_OFFSET(GET_EXPR(dwarf::DW_OP_constu, 3, dwarf::DW_OP_mul));
EXPECT_NO_OFFSET(GET_FRAG(dwarf::DW_OP_constu, 3, dwarf::DW_OP_mul));

EXPECT_NO_OFFSET(
GET_EXPR(dwarf::DW_OP_constu, 3, dwarf::DW_OP_plus, dwarf::DW_OP_deref));
EXPECT_NO_OFFSET(
GET_FRAG(dwarf::DW_OP_constu, 3, dwarf::DW_OP_plus, dwarf::DW_OP_deref));

#undef EXPECT_NO_OFFSET
#undef EXPECT_OFFSET_EQ
#undef EXPECT_OFFSET_IMPL
#undef GET_FRAG
#undef GET_EXPR
}

TEST_F(DIExpressionTest, foldConstant) {
const ConstantInt *Int;
const ConstantInt *NewInt;
Expand Down