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
This commit is contained in:
Duncan P. N. Exon Smith 2015-02-13 01:07:46 +00:00
parent 3b631d291e
commit 193a4fdafd
4 changed files with 148 additions and 0 deletions

View File

@ -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<std::input_iterator_tag, ExprOperand> {
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;
}

View File

@ -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,

View File

@ -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) {

View File

@ -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) {