diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp index f7f36129ec855..2ab41e55db1ca 100644 --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -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; diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp index 1570631287b2a..e68d27b360547 100644 --- a/llvm/unittests/IR/MetadataTest.cpp +++ b/llvm/unittests/IR/MetadataTest.cpp @@ -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, + // DW_OP_constu, , 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;