From 193a4fdafd9d4d4d6bbb7a1885fb30427434fe97 Mon Sep 17 00:00:00 2001 From: "Duncan P. N. Exon Smith" Date: Fri, 13 Feb 2015 01:07:46 +0000 Subject: [PATCH] IR: Add MDExpression::ExprOperand Port `DIExpression::Operand` over to `MDExpression::ExprOperand`. The logic is needed directly in `MDExpression` to support printing in assembly. llvm-svn: 229002 --- llvm/include/llvm/IR/DebugInfoMetadata.h | 79 ++++++++++++++++++++++++ llvm/lib/IR/DebugInfoMetadata.cpp | 32 ++++++++++ llvm/lib/IR/Verifier.cpp | 1 + llvm/unittests/IR/MetadataTest.cpp | 36 +++++++++++ 4 files changed, 148 insertions(+) diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h index 34d03568eb00..f4a7ae9b79e2 100644 --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -1401,6 +1401,85 @@ public: element_iterator elements_begin() const { return getElements().begin(); } element_iterator elements_end() const { return getElements().end(); } + /// \brief A lightweight wrapper around an expression operand. + /// + /// TODO: Store arguments directly and change \a MDExpression to store a + /// range of these. + class ExprOperand { + const uint64_t *Op; + + public: + explicit ExprOperand(const uint64_t *Op) : Op(Op) {} + + const uint64_t *get() const { return Op; } + + /// \brief Get the operand code. + uint64_t getOp() const { return *Op; } + + /// \brief Get an argument to the operand. + /// + /// Never returns the operand itself. + uint64_t getArg(unsigned I) const { return Op[I + 1]; } + + unsigned getNumArgs() const { return getSize() - 1; } + + /// \brief Return the size of the operand. + /// + /// Return the number of elements in the operand (1 + args). + unsigned getSize() const; + }; + + /// \brief An iterator for expression operands. + class expr_op_iterator + : public std::iterator { + ExprOperand Op; + + public: + explicit expr_op_iterator(element_iterator I) : Op(I) {} + + element_iterator getBase() const { return Op.get(); } + const ExprOperand &operator*() const { return Op; } + const ExprOperand *operator->() const { return &Op; } + + expr_op_iterator &operator++() { + increment(); + return *this; + } + expr_op_iterator operator++(int) { + expr_op_iterator T(*this); + increment(); + return T; + } + + bool operator==(const expr_op_iterator &X) const { + return getBase() == X.getBase(); + } + bool operator!=(const expr_op_iterator &X) const { + return getBase() != X.getBase(); + } + + private: + void increment() { Op = ExprOperand(getBase() + Op.getSize()); } + }; + + /// \brief Visit the elements via ExprOperand wrappers. + /// + /// These range iterators visit elements through \a ExprOperand wrappers. + /// This is not guaranteed to be a valid range unless \a isValid() gives \c + /// true. + /// + /// \pre \a isValid() gives \c true. + /// @{ + expr_op_iterator expr_op_begin() const { + return expr_op_iterator(elements_begin()); + } + expr_op_iterator expr_op_end() const { + return expr_op_iterator(elements_end()); + } + /// @} + + bool isValid() const; + static bool classof(const Metadata *MD) { return MD->getMetadataID() == MDExpressionKind; } diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp index aaf1bc6e1ab1..46ac98a7d0cf 100644 --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -350,6 +350,38 @@ MDExpression *MDExpression::getImpl(LLVMContext &Context, DEFINE_GETIMPL_STORE_NO_OPS(MDExpression, (Elements)); } +unsigned MDExpression::ExprOperand::getSize() const { + switch (getOp()) { + case dwarf::DW_OP_bit_piece: + return 3; + case dwarf::DW_OP_plus: + return 2; + default: + return 1; + } +} + +bool MDExpression::isValid() const { + for (auto I = expr_op_begin(), E = expr_op_end(); I != E; ++I) { + // Check that there's space for the operand. + if (I->get() + I->getSize() > E->get()) + return false; + + // Check that the operand is valid. + switch (I->getOp()) { + default: + return false; + case dwarf::DW_OP_bit_piece: + // Piece expressions must be at the end. + return I->get() + I->getSize() == E->get(); + case dwarf::DW_OP_plus: + case dwarf::DW_OP_deref: + break; + } + } + return true; +} + MDObjCProperty *MDObjCProperty::getImpl( LLVMContext &Context, MDString *Name, Metadata *File, unsigned Line, MDString *GetterName, MDString *SetterName, unsigned Attributes, diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 5d4de30e4401..22a5a9620b0a 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -780,6 +780,7 @@ void Verifier::visitMDLocalVariable(const MDLocalVariable &N) { void Verifier::visitMDExpression(const MDExpression &N) { Assert1(N.getTag() == dwarf::DW_TAG_expression, "invalid tag", &N); + Assert1(N.isValid(), "invalid expression", &N); } void Verifier::visitMDObjCProperty(const MDObjCProperty &N) { diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp index e8e6d68c5fa3..162f30e640a0 100644 --- a/llvm/unittests/IR/MetadataTest.cpp +++ b/llvm/unittests/IR/MetadataTest.cpp @@ -1407,6 +1407,42 @@ TEST_F(MDExpressionTest, get) { EXPECT_EQ(0u, N->getElement(4)); } +TEST_F(MDExpressionTest, isValid) { +#define EXPECT_VALID(...) \ + do { \ + uint64_t Elements[] = {__VA_ARGS__}; \ + EXPECT_TRUE(MDExpression::get(Context, Elements)->isValid()); \ + } while (false) +#define EXPECT_INVALID(...) \ + do { \ + uint64_t Elements[] = {__VA_ARGS__}; \ + EXPECT_FALSE(MDExpression::get(Context, Elements)->isValid()); \ + } while (false) + + // Empty expression should be valid. + EXPECT_TRUE(MDExpression::get(Context, None)); + + // Valid constructions. + EXPECT_VALID(dwarf::DW_OP_plus, 6); + EXPECT_VALID(dwarf::DW_OP_deref); + EXPECT_VALID(dwarf::DW_OP_bit_piece, 3, 7); + EXPECT_VALID(dwarf::DW_OP_plus, 6, dwarf::DW_OP_deref); + EXPECT_VALID(dwarf::DW_OP_deref, dwarf::DW_OP_plus, 6); + EXPECT_VALID(dwarf::DW_OP_deref, dwarf::DW_OP_bit_piece, 3, 7); + EXPECT_VALID(dwarf::DW_OP_deref, dwarf::DW_OP_plus, 6, dwarf::DW_OP_bit_piece, 3, 7); + + // Invalid constructions. + EXPECT_INVALID(~0u); + EXPECT_INVALID(dwarf::DW_OP_plus); + EXPECT_INVALID(dwarf::DW_OP_bit_piece); + EXPECT_INVALID(dwarf::DW_OP_bit_piece, 3); + EXPECT_INVALID(dwarf::DW_OP_bit_piece, 3, 7, dwarf::DW_OP_plus, 3); + EXPECT_INVALID(dwarf::DW_OP_bit_piece, 3, 7, dwarf::DW_OP_deref); + +#undef EXPECT_VALID +#undef EXPECT_INVALID +} + typedef MetadataTest MDObjCPropertyTest; TEST_F(MDObjCPropertyTest, get) {