summaryrefslogtreecommitdiff
path: root/include/llvm/IR/Value.h
diff options
context:
space:
mode:
authorChandler Carruth <chandlerc@gmail.com>2014-03-09 03:16:01 +0000
committerChandler Carruth <chandlerc@gmail.com>2014-03-09 03:16:01 +0000
commit36b699f2b139a30a2dfa4448223d6985b55daa8a (patch)
treed6844c991f0c06de4b66a2615259607d8349e5b3 /include/llvm/IR/Value.h
parentb033b03c23fb3ae066937b2ec09eb9d7a3f1d522 (diff)
downloadllvm-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.h96
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