mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-06-24 08:24:33 +00:00
IR: Add MDExpression::ExprOperand
Port `DIExpression::Operand` over to `MDExpression::ExprOperand`. The logic is needed directly in `MDExpression` to support printing in assembly. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@229002 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@ -1401,6 +1401,85 @@ public:
|
|||||||
element_iterator elements_begin() const { return getElements().begin(); }
|
element_iterator elements_begin() const { return getElements().begin(); }
|
||||||
element_iterator elements_end() const { return getElements().end(); }
|
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) {
|
static bool classof(const Metadata *MD) {
|
||||||
return MD->getMetadataID() == MDExpressionKind;
|
return MD->getMetadataID() == MDExpressionKind;
|
||||||
}
|
}
|
||||||
|
@ -350,6 +350,38 @@ MDExpression *MDExpression::getImpl(LLVMContext &Context,
|
|||||||
DEFINE_GETIMPL_STORE_NO_OPS(MDExpression, (Elements));
|
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(
|
MDObjCProperty *MDObjCProperty::getImpl(
|
||||||
LLVMContext &Context, MDString *Name, Metadata *File, unsigned Line,
|
LLVMContext &Context, MDString *Name, Metadata *File, unsigned Line,
|
||||||
MDString *GetterName, MDString *SetterName, unsigned Attributes,
|
MDString *GetterName, MDString *SetterName, unsigned Attributes,
|
||||||
|
@ -780,6 +780,7 @@ void Verifier::visitMDLocalVariable(const MDLocalVariable &N) {
|
|||||||
|
|
||||||
void Verifier::visitMDExpression(const MDExpression &N) {
|
void Verifier::visitMDExpression(const MDExpression &N) {
|
||||||
Assert1(N.getTag() == dwarf::DW_TAG_expression, "invalid tag", &N);
|
Assert1(N.getTag() == dwarf::DW_TAG_expression, "invalid tag", &N);
|
||||||
|
Assert1(N.isValid(), "invalid expression", &N);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Verifier::visitMDObjCProperty(const MDObjCProperty &N) {
|
void Verifier::visitMDObjCProperty(const MDObjCProperty &N) {
|
||||||
|
@ -1407,6 +1407,42 @@ TEST_F(MDExpressionTest, get) {
|
|||||||
EXPECT_EQ(0u, N->getElement(4));
|
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;
|
typedef MetadataTest MDObjCPropertyTest;
|
||||||
|
|
||||||
TEST_F(MDObjCPropertyTest, get) {
|
TEST_F(MDObjCPropertyTest, get) {
|
||||||
|
Reference in New Issue
Block a user