Skip to content

Commit ef55a1a

Browse files
committed
Switch from using an ilist for uses to using a custom doubly linked list.
This list does not provide the ability to go backwards in the list (its more of an unordered collection, stored in the shape of a list). This change means that use iterators are now only forward iterators, not bidirectional. This improves the memory usage of use lists from '5 + 4*#use' per value to '1 + 4*#use'. While it would be better to reduce the multiplied factor, I'm not smart enough to do so. This list also has slightly more efficient operators for manipulating list nodes (a few less loads/stores), due to not needing to be able to iterate backwards through the list. This change reduces the memory footprint required to hold 176.gcc from 66.025M -> 57.687M, a 14% reduction. It also speeds up the compiler, 7.73% in the case of bytecode loading alone (release build loading 176.gcc). llvm-svn: 19956
1 parent 1230cf2 commit ef55a1a

File tree

3 files changed

+79
-118
lines changed

3 files changed

+79
-118
lines changed

llvm/include/llvm/Support/CFG.h

+5-10
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,22 @@ namespace llvm {
2727
//===--------------------------------------------------------------------===//
2828

2929
template <class _Ptr, class _USE_iterator> // Predecessor Iterator
30-
class PredIterator : public bidirectional_iterator<_Ptr, ptrdiff_t> {
31-
typedef bidirectional_iterator<_Ptr, ptrdiff_t> super;
30+
class PredIterator : public forward_iterator<_Ptr, ptrdiff_t> {
31+
typedef forward_iterator<_Ptr, ptrdiff_t> super;
3232
_Ptr *BB;
3333
_USE_iterator It;
3434
public:
3535
typedef PredIterator<_Ptr,_USE_iterator> _Self;
3636
typedef typename super::pointer pointer;
3737

38-
inline void advancePastConstants() {
38+
inline void advancePastNonTerminators() {
3939
// Loop to ignore non terminator uses (for example PHI nodes)...
4040
while (It != BB->use_end() && !isa<TerminatorInst>(*It))
4141
++It;
4242
}
4343

4444
inline PredIterator(_Ptr *bb) : BB(bb), It(bb->use_begin()) {
45-
advancePastConstants();
45+
advancePastNonTerminators();
4646
}
4747
inline PredIterator(_Ptr *bb, bool) : BB(bb), It(bb->use_end()) {}
4848

@@ -57,18 +57,13 @@ class PredIterator : public bidirectional_iterator<_Ptr, ptrdiff_t> {
5757

5858
inline _Self& operator++() { // Preincrement
5959
assert(It != BB->use_end() && "pred_iterator out of range!");
60-
++It; advancePastConstants();
60+
++It; advancePastNonTerminators();
6161
return *this;
6262
}
6363

6464
inline _Self operator++(int) { // Postincrement
6565
_Self tmp = *this; ++*this; return tmp;
6666
}
67-
68-
inline _Self& operator--() { --It; return *this; } // Predecrement
69-
inline _Self operator--(int) { // Postdecrement
70-
_Self tmp = *this; --*this; return tmp;
71-
}
7267
};
7368

7469
typedef PredIterator<BasicBlock, Value::use_iterator> pred_iterator;

llvm/include/llvm/Use.h

+50-80
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@
1616
#ifndef LLVM_USE_H
1717
#define LLVM_USE_H
1818

19-
#include "llvm/ADT/ilist"
19+
#include "llvm/Support/Casting.h"
20+
#include "llvm/ADT/iterator"
2021

2122
namespace llvm {
2223

23-
template<typename NodeTy> struct ilist_traits;
2424
class Value;
2525
class User;
2626

@@ -62,43 +62,28 @@ class Use {
6262
Value *operator->() { return Val; }
6363
const Value *operator->() const { return Val; }
6464

65+
Use *getNext() const { return Next; }
6566
private:
66-
// NOTE!! The Next/Prev fields MUST stay at the start of this structure. The
67-
// end-token for the ilist is allocated as JUST the next/prev pair to reduce
68-
// memory usage instead of allocating an entire Use.
69-
struct NextPrevPtrs {
70-
Use *Next, *Prev;
71-
} UseLinks;
72-
67+
Use *Next, **Prev;
7368
Value *Val;
7469
User *U;
75-
friend struct ilist_traits<Use>;
76-
};
7770

78-
template<>
79-
struct ilist_traits<Use> {
80-
static Use *getPrev(Use *N) { return N->UseLinks.Prev; }
81-
static Use *getNext(Use *N) { return N->UseLinks.Next; }
82-
static const Use *getPrev(const Use *N) { return N->UseLinks.Prev; }
83-
static const Use *getNext(const Use *N) { return N->UseLinks.Next; }
84-
static void setPrev(Use *N, Use *Prev) { N->UseLinks.Prev = Prev; }
85-
static void setNext(Use *N, Use *Next) { N->UseLinks.Next = Next; }
86-
87-
/// createSentinel - this is used to create the end marker for the use list.
88-
/// Note that we only allocate a UseLinks structure, which is just enough to
89-
/// hold the next/prev pointers. This saves us 8 bytes of memory for every
90-
/// Value allocated.
91-
static Use *createSentinel() { return (Use*)new Use::NextPrevPtrs(); }
92-
static void destroySentinel(Use *S) { delete (Use::NextPrevPtrs*)S; }
93-
94-
void addNodeToList(Use *NTy) {}
95-
void removeNodeFromList(Use *NTy) {}
96-
void transferNodesFromList(iplist<Use, ilist_traits> &L2,
97-
ilist_iterator<Use> first,
98-
ilist_iterator<Use> last) {}
99-
};
71+
void addToList(Use **List) {
72+
Next = *List;
73+
if (Next) Next->Prev = &Next;
74+
Prev = List;
75+
*List = this;
76+
}
77+
void removeFromList() {
78+
*Prev = Next;
79+
if (Next) Next->Prev = Prev;
80+
}
10081

82+
friend class Value;
83+
};
10184

85+
// simplify_type - Allow clients to treat uses just like values when using
86+
// casting operators.
10287
template<> struct simplify_type<Use> {
10388
typedef Value* SimpleType;
10489
static SimpleType getSimplifiedValue(const Use &Val) {
@@ -112,64 +97,49 @@ template<> struct simplify_type<const Use> {
11297
}
11398
};
11499

115-
struct UseListIteratorWrapper : public iplist<Use>::iterator {
116-
typedef iplist<Use>::iterator Super;
117-
UseListIteratorWrapper() {}
118-
UseListIteratorWrapper(const Super &RHS) : Super(RHS) {}
119100

120-
UseListIteratorWrapper &operator=(const Super &RHS) {
121-
Super::operator=(RHS);
122-
return *this;
123-
}
124101

125-
inline User *operator*() const;
126-
User *operator->() const { return operator*(); }
102+
template<typename UserTy> // UserTy == 'User' or 'const User'
103+
class value_use_iterator : public forward_iterator<UserTy*, ptrdiff_t> {
104+
typedef forward_iterator<UserTy*, ptrdiff_t> super;
105+
typedef value_use_iterator<UserTy> _Self;
106+
107+
Use *U;
108+
value_use_iterator(Use *u) : U(u) {}
109+
friend class Value;
110+
public:
111+
typedef typename super::reference reference;
112+
typedef typename super::pointer pointer;
127113

128-
UseListIteratorWrapper operator--() { return Super::operator--(); }
129-
UseListIteratorWrapper operator++() { return Super::operator++(); }
114+
value_use_iterator(const _Self &I) : U(I.U) {}
115+
value_use_iterator() {}
130116

131-
UseListIteratorWrapper operator--(int) { // postdecrement operators...
132-
UseListIteratorWrapper tmp = *this;
133-
--*this;
134-
return tmp;
117+
bool operator==(const _Self &x) const {
118+
return U == x.U;
135119
}
136-
UseListIteratorWrapper operator++(int) { // postincrement operators...
137-
UseListIteratorWrapper tmp = *this;
138-
++*this;
139-
return tmp;
120+
bool operator!=(const _Self &x) const {
121+
return !operator==(x);
140122
}
141-
};
142-
143-
struct UseListConstIteratorWrapper : public iplist<Use>::const_iterator {
144-
typedef iplist<Use>::const_iterator Super;
145-
UseListConstIteratorWrapper() {}
146-
UseListConstIteratorWrapper(const Super &RHS) : Super(RHS) {}
147123

148-
// Allow conversion from non-const to const iterators
149-
UseListConstIteratorWrapper(const UseListIteratorWrapper &RHS) : Super(RHS) {}
150-
UseListConstIteratorWrapper(const iplist<Use>::iterator &RHS) : Super(RHS) {}
151-
152-
UseListConstIteratorWrapper &operator=(const Super &RHS) {
153-
Super::operator=(RHS);
154-
return *this;
124+
// Iterator traversal: forward iteration only
125+
_Self &operator++() { // Preincrement
126+
assert(U && "Cannot increment end iterator!");
127+
U = U->getNext();
128+
return *this;
129+
}
130+
_Self operator++(int) { // Postincrement
131+
_Self tmp = *this; ++*this; return tmp;
155132
}
156133

157-
inline const User *operator*() const;
158-
const User *operator->() const { return operator*(); }
134+
// Retrieve a reference to the current SCC
135+
UserTy *operator*() const {
136+
assert(U && "Cannot increment end iterator!");
137+
return U->getUser();
138+
}
159139

160-
UseListConstIteratorWrapper operator--() { return Super::operator--(); }
161-
UseListConstIteratorWrapper operator++() { return Super::operator++(); }
140+
UserTy *operator->() const { return operator*(); }
162141

163-
UseListConstIteratorWrapper operator--(int) { // postdecrement operators...
164-
UseListConstIteratorWrapper tmp = *this;
165-
--*this;
166-
return tmp;
167-
}
168-
UseListConstIteratorWrapper operator++(int) { // postincrement operators...
169-
UseListConstIteratorWrapper tmp = *this;
170-
++*this;
171-
return tmp;
172-
}
142+
Use &getUse() const { return *U; }
173143
};
174144

175145
} // End llvm namespace

llvm/include/llvm/Value.h

+24-28
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class SymbolTable;
4343
class Value {
4444
unsigned SubclassID; // Subclass identifier (for isa/dyn_cast)
4545
PATypeHolder Ty;
46-
iplist<Use> Uses;
46+
Use *UseList;
4747
std::string Name;
4848

4949
void operator=(const Value &); // Do not implement
@@ -86,33 +86,39 @@ class Value {
8686
//----------------------------------------------------------------------
8787
// Methods for handling the vector of uses of this Value.
8888
//
89-
typedef UseListIteratorWrapper use_iterator;
90-
typedef UseListConstIteratorWrapper use_const_iterator;
91-
typedef iplist<Use>::size_type size_type;
92-
93-
size_type use_size() const { return Uses.size(); }
94-
bool use_empty() const { return Uses.empty(); }
95-
use_iterator use_begin() { return Uses.begin(); }
96-
use_const_iterator use_begin() const { return Uses.begin(); }
97-
use_iterator use_end() { return Uses.end(); }
98-
use_const_iterator use_end() const { return Uses.end(); }
99-
User *use_back() { return Uses.back().getUser(); }
100-
const User *use_back() const { return Uses.back().getUser(); }
89+
typedef value_use_iterator<User> use_iterator;
90+
typedef value_use_iterator<const User> use_const_iterator;
91+
92+
bool use_empty() const { return UseList == 0; }
93+
use_iterator use_begin() { return use_iterator(UseList); }
94+
use_const_iterator use_begin() const { return use_const_iterator(UseList); }
95+
use_iterator use_end() { return use_iterator(0); }
96+
use_const_iterator use_end() const { return use_const_iterator(0); }
97+
User *use_back() { return *use_begin(); }
98+
const User *use_back() const { return *use_begin(); }
10199

102100
/// hasOneUse - Return true if there is exactly one user of this value. This
103101
/// is specialized because it is a common request and does not require
104102
/// traversing the whole use list.
105103
///
106104
bool hasOneUse() const {
107-
iplist<Use>::const_iterator I = Uses.begin(), E = Uses.end();
105+
use_const_iterator I = use_begin(), E = use_end();
108106
if (I == E) return false;
109107
return ++I == E;
110108
}
111109

110+
/// hasNUses - Return true if this Value has exactly N users.
111+
///
112+
bool hasNUses(unsigned N) const;
113+
114+
/// getNumUses - This method computes the number of uses of this Value. This
115+
/// is a linear time operation. Use hasOneUse or hasNUses to check for
116+
/// specific values.
117+
unsigned getNumUses() const;
118+
112119
/// addUse/killUse - These two methods should only be used by the Use class.
113120
///
114-
void addUse(Use &U) { Uses.push_back(&U); }
115-
void killUse(Use &U) { Uses.remove(&U); }
121+
void addUse(Use &U) { U.addToList(&UseList); }
116122

117123
/// getValueType - Return an ID for the concrete type of this object. This is
118124
/// used to implement the classof checks. This should not be used for any
@@ -157,28 +163,18 @@ inline std::ostream &operator<<(std::ostream &OS, const Value &V) {
157163
return OS;
158164
}
159165

160-
161-
inline User *UseListIteratorWrapper::operator*() const {
162-
return Super::operator*().getUser();
163-
}
164-
165-
inline const User *UseListConstIteratorWrapper::operator*() const {
166-
return Super::operator*().getUser();
167-
}
168-
169-
170166
void Use::init(Value *v, User *user) {
171167
Val = v;
172168
U = user;
173169
if (Val) Val->addUse(*this);
174170
}
175171

176172
Use::~Use() {
177-
if (Val) Val->killUse(*this);
173+
if (Val) removeFromList();
178174
}
179175

180176
void Use::set(Value *V) {
181-
if (Val) Val->killUse(*this);
177+
if (Val) removeFromList();
182178
Val = V;
183179
if (V) V->addUse(*this);
184180
}

0 commit comments

Comments
 (0)