diff options
author | Chandler Carruth <chandlerc@gmail.com> | 2014-03-09 03:16:01 +0000 |
---|---|---|
committer | Chandler Carruth <chandlerc@gmail.com> | 2014-03-09 03:16:01 +0000 |
commit | 36b699f2b139a30a2dfa4448223d6985b55daa8a (patch) | |
tree | d6844c991f0c06de4b66a2615259607d8349e5b3 /include/llvm/IR/Value.h | |
parent | b033b03c23fb3ae066937b2ec09eb9d7a3f1d522 (diff) | |
download | llvm-36b699f2b139a30a2dfa4448223d6985b55daa8a.tar.gz llvm-36b699f2b139a30a2dfa4448223d6985b55daa8a.tar.bz2 llvm-36b699f2b139a30a2dfa4448223d6985b55daa8a.tar.xz |
[C++11] Add range based accessors for the Use-Def chain of a Value.
This requires a number of steps.
1) Move value_use_iterator into the Value class as an implementation
detail
2) Change it to actually be a *Use* iterator rather than a *User*
iterator.
3) Add an adaptor which is a User iterator that always looks through the
Use to the User.
4) Wrap these in Value::use_iterator and Value::user_iterator typedefs.
5) Add the range adaptors as Value::uses() and Value::users().
6) Update *all* of the callers to correctly distinguish between whether
they wanted a use_iterator (and to explicitly dig out the User when
needed), or a user_iterator which makes the Use itself totally
opaque.
Because #6 requires churning essentially everything that walked the
Use-Def chains, I went ahead and added all of the range adaptors and
switched them to range-based loops where appropriate. Also because the
renaming requires at least churning every line of code, it didn't make
any sense to split these up into multiple commits -- all of which would
touch all of the same lies of code.
The result is still not quite optimal. The Value::use_iterator is a nice
regular iterator, but Value::user_iterator is an iterator over User*s
rather than over the User objects themselves. As a consequence, it fits
a bit awkwardly into the range-based world and it has the weird
extra-dereferencing 'operator->' that so many of our iterators have.
I think this could be fixed by providing something which transforms
a range of T&s into a range of T*s, but that *can* be separated into
another patch, and it isn't yet 100% clear whether this is the right
move.
However, this change gets us most of the benefit and cleans up
a substantial amount of code around Use and User. =]
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@203364 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'include/llvm/IR/Value.h')
-rw-r--r-- | include/llvm/IR/Value.h | 96 |
1 files changed, 77 insertions, 19 deletions
diff --git a/include/llvm/IR/Value.h b/include/llvm/IR/Value.h index b2ed39e917..d5b9f11a6d 100644 --- a/include/llvm/IR/Value.h +++ b/include/llvm/IR/Value.h @@ -15,6 +15,7 @@ #define LLVM_IR_VALUE_H #include "llvm-c/Core.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/IR/Use.h" #include "llvm/Support/CBindingWrapping.h" #include "llvm/Support/Casting.h" @@ -75,13 +76,54 @@ protected: unsigned char SubclassOptionalData : 7; private: + template <typename UseT> // UseT == 'Use' or 'const Use' + class use_iterator_impl + : public std::iterator<std::forward_iterator_tag, UseT *, ptrdiff_t> { + typedef std::iterator<std::forward_iterator_tag, UseT *, ptrdiff_t> super; + + UseT *U; + explicit use_iterator_impl(UseT *u) : U(u) {} + friend class Value; + + public: + typedef typename super::reference reference; + typedef typename super::pointer pointer; + + use_iterator_impl() : U() {} + + bool operator==(const use_iterator_impl &x) const { return U == x.U; } + bool operator!=(const use_iterator_impl &x) const { return !operator==(x); } + + use_iterator_impl &operator++() { // Preincrement + assert(U && "Cannot increment end iterator!"); + U = U->getNext(); + return *this; + } + use_iterator_impl operator++(int) { // Postincrement + auto tmp = *this; + ++*this; + return tmp; + } + + UseT &operator*() const { + assert(U && "Cannot dereference end iterator!"); + return *U; + } + + UseT *operator->() const { return &operator*(); } + + operator use_iterator_impl<const UseT>() const { + return use_iterator_impl<const UseT>(U); + } + }; + template <typename UserTy> // UserTy == 'User' or 'const User' class user_iterator_impl : public std::iterator<std::forward_iterator_tag, UserTy *, ptrdiff_t> { typedef std::iterator<std::forward_iterator_tag, UserTy *, ptrdiff_t> super; - Use *U; - explicit user_iterator_impl(Use *u) : U(u) {} + use_iterator_impl<Use> UI; + explicit user_iterator_impl(Use *U) : UI(U) {} friend class Value; public: @@ -90,16 +132,14 @@ private: user_iterator_impl() {} - bool operator==(const user_iterator_impl &x) const { return U == x.U; } + bool operator==(const user_iterator_impl &x) const { return UI == x.UI; } bool operator!=(const user_iterator_impl &x) const { return !operator==(x); } - /// \brief Returns true if this iterator is equal to use_end() on the value. - bool atEnd() const { return U == 0; } + /// \brief Returns true if this iterator is equal to user_end() on the value. + bool atEnd() const { return *this == user_iterator_impl(); } - // Iterator traversal: forward iteration only user_iterator_impl &operator++() { // Preincrement - assert(U && "Cannot increment end iterator!"); - U = U->getNext(); + ++UI; return *this; } user_iterator_impl operator++(int) { // Postincrement @@ -110,21 +150,20 @@ private: // Retrieve a pointer to the current User. UserTy *operator*() const { - assert(U && "Cannot dereference end iterator!"); - return U->getUser(); + return UI->getUser(); } UserTy *operator->() const { return operator*(); } operator user_iterator_impl<const UserTy>() const { - return user_iterator_impl<const UserTy>(U); + return user_iterator_impl<const UserTy>(*UI); } - Use &getUse() const { return *U; } + Use &getUse() const { return *UI; } /// \brief Return the operand # of this use in its User. /// FIXME: Replace all callers with a direct call to Use::getOperandNo. - unsigned getOperandNo() const { return U->getOperandNo(); } + unsigned getOperandNo() const { return UI->getOperandNo(); } }; /// SubclassData - This member is defined by this class, but is not used for @@ -205,14 +244,33 @@ public: // bool use_empty() const { return UseList == 0; } - typedef user_iterator_impl<User> use_iterator; - typedef user_iterator_impl<const User> const_use_iterator; + typedef use_iterator_impl<Use> use_iterator; + typedef use_iterator_impl<const Use> const_use_iterator; use_iterator use_begin() { return use_iterator(UseList); } const_use_iterator use_begin() const { return const_use_iterator(UseList); } - use_iterator use_end() { return use_iterator(0); } - const_use_iterator use_end() const { return const_use_iterator(0); } - User *use_back() { return *use_begin(); } - const User *use_back() const { return *use_begin(); } + use_iterator use_end() { return use_iterator(); } + const_use_iterator use_end() const { return const_use_iterator(); } + iterator_range<use_iterator> uses() { + return iterator_range<use_iterator>(use_begin(), use_end()); + } + iterator_range<const_use_iterator> uses() const { + return iterator_range<const_use_iterator>(use_begin(), use_end()); + } + + typedef user_iterator_impl<User> user_iterator; + typedef user_iterator_impl<const User> const_user_iterator; + user_iterator user_begin() { return user_iterator(UseList); } + const_user_iterator user_begin() const { return const_user_iterator(UseList); } + user_iterator user_end() { return user_iterator(); } + const_user_iterator user_end() const { return const_user_iterator(); } + User *user_back() { return *user_begin(); } + const User *user_back() const { return *user_begin(); } + iterator_range<user_iterator> users() { + return iterator_range<user_iterator>(user_begin(), user_end()); + } + iterator_range<const_user_iterator> users() const { + return iterator_range<const_user_iterator>(user_begin(), user_end()); + } /// hasOneUse - Return true if there is exactly one user of this value. This /// is specialized because it is a common request and does not require |