31bbba9e78ba991cd023d2e92faddc18c579f9f7
[oota-llvm.git] / include / llvm / ADT / DenseMap.h
1 //===- llvm/ADT/DenseMap.h - Dense probed hash table ------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines the DenseMap class.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #ifndef LLVM_ADT_DENSEMAP_H
15 #define LLVM_ADT_DENSEMAP_H
16
17 #include "llvm/Support/Compiler.h"
18 #include "llvm/Support/MathExtras.h"
19 #include "llvm/Support/PointerLikeTypeTraits.h"
20 #include "llvm/Support/type_traits.h"
21 #include "llvm/ADT/DenseMapInfo.h"
22 #include <algorithm>
23 #include <iterator>
24 #include <new>
25 #include <utility>
26 #include <cassert>
27 #include <cstddef>
28 #include <cstring>
29
30 namespace llvm {
31
32 template<typename KeyT, typename ValueT,
33          typename KeyInfoT = DenseMapInfo<KeyT>,
34          bool IsConst = false>
35 class DenseMapIterator;
36
37 template<typename DerivedT,
38          typename KeyT, typename ValueT, typename KeyInfoT>
39 class DenseMapBase {
40 protected:
41   typedef std::pair<KeyT, ValueT> BucketT;
42   unsigned NumEntries;
43   unsigned NumTombstones;
44
45 public:
46   typedef KeyT key_type;
47   typedef ValueT mapped_type;
48   typedef BucketT value_type;
49
50   typedef DenseMapIterator<KeyT, ValueT, KeyInfoT> iterator;
51   typedef DenseMapIterator<KeyT, ValueT,
52                            KeyInfoT, true> const_iterator;
53   inline iterator begin() {
54     // When the map is empty, avoid the overhead of AdvancePastEmptyBuckets().
55     return empty() ? end() : iterator(getBuckets(), getBucketsEnd());
56   }
57   inline iterator end() {
58     return iterator(getBucketsEnd(), getBucketsEnd(), true);
59   }
60   inline const_iterator begin() const {
61     return empty() ? end() : const_iterator(getBuckets(), getBucketsEnd());
62   }
63   inline const_iterator end() const {
64     return const_iterator(getBucketsEnd(), getBucketsEnd(), true);
65   }
66
67   bool empty() const { return NumEntries == 0; }
68   unsigned size() const { return NumEntries; }
69
70   /// Grow the densemap so that it has at least Size buckets. Does not shrink
71   void resize(size_t Size) {
72     if (Size > getNumBuckets())
73       grow(Size);
74   }
75
76   void clear() {
77     if (NumEntries == 0 && NumTombstones == 0) return;
78     
79     // If the capacity of the array is huge, and the # elements used is small,
80     // shrink the array.
81     if (NumEntries * 4 < getNumBuckets() && getNumBuckets() > 64) {
82       shrink_and_clear();
83       return;
84     }
85
86     const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey();
87     for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) {
88       if (!KeyInfoT::isEqual(P->first, EmptyKey)) {
89         if (!KeyInfoT::isEqual(P->first, TombstoneKey)) {
90           P->second.~ValueT();
91           --NumEntries;
92         }
93         P->first = EmptyKey;
94       }
95     }
96     assert(NumEntries == 0 && "Node count imbalance!");
97     NumTombstones = 0;
98   }
99
100   /// count - Return true if the specified key is in the map.
101   bool count(const KeyT &Val) const {
102     BucketT *TheBucket;
103     return LookupBucketFor(Val, TheBucket);
104   }
105
106   iterator find(const KeyT &Val) {
107     BucketT *TheBucket;
108     if (LookupBucketFor(Val, TheBucket))
109       return iterator(TheBucket, getBucketsEnd(), true);
110     return end();
111   }
112   const_iterator find(const KeyT &Val) const {
113     BucketT *TheBucket;
114     if (LookupBucketFor(Val, TheBucket))
115       return const_iterator(TheBucket, getBucketsEnd(), true);
116     return end();
117   }
118
119   /// Alternate version of find() which allows a different, and possibly
120   /// less expensive, key type.
121   /// The DenseMapInfo is responsible for supplying methods
122   /// getHashValue(LookupKeyT) and isEqual(LookupKeyT, KeyT) for each key
123   /// type used.
124   template<class LookupKeyT>
125   iterator find_as(const LookupKeyT &Val) {
126     BucketT *TheBucket;
127     if (LookupBucketFor(Val, TheBucket))
128       return iterator(TheBucket, getBucketsEnd(), true);
129     return end();
130   }
131   template<class LookupKeyT>
132   const_iterator find_as(const LookupKeyT &Val) const {
133     BucketT *TheBucket;
134     if (LookupBucketFor(Val, TheBucket))
135       return const_iterator(TheBucket, getBucketsEnd(), true);
136     return end();
137   }
138
139   /// lookup - Return the entry for the specified key, or a default
140   /// constructed value if no such entry exists.
141   ValueT lookup(const KeyT &Val) const {
142     BucketT *TheBucket;
143     if (LookupBucketFor(Val, TheBucket))
144       return TheBucket->second;
145     return ValueT();
146   }
147
148   // Inserts key,value pair into the map if the key isn't already in the map.
149   // If the key is already in the map, it returns false and doesn't update the
150   // value.
151   std::pair<iterator, bool> insert(const std::pair<KeyT, ValueT> &KV) {
152     BucketT *TheBucket;
153     if (LookupBucketFor(KV.first, TheBucket))
154       return std::make_pair(iterator(TheBucket, getBucketsEnd(), true),
155                             false); // Already in map.
156
157     // Otherwise, insert the new element.
158     TheBucket = InsertIntoBucket(KV.first, KV.second, TheBucket);
159     return std::make_pair(iterator(TheBucket, getBucketsEnd(), true), true);
160   }
161
162   /// insert - Range insertion of pairs.
163   template<typename InputIt>
164   void insert(InputIt I, InputIt E) {
165     for (; I != E; ++I)
166       insert(*I);
167   }
168
169
170   bool erase(const KeyT &Val) {
171     BucketT *TheBucket;
172     if (!LookupBucketFor(Val, TheBucket))
173       return false; // not in map.
174
175     TheBucket->second.~ValueT();
176     TheBucket->first = getTombstoneKey();
177     --NumEntries;
178     ++NumTombstones;
179     return true;
180   }
181   void erase(iterator I) {
182     BucketT *TheBucket = &*I;
183     TheBucket->second.~ValueT();
184     TheBucket->first = getTombstoneKey();
185     --NumEntries;
186     ++NumTombstones;
187   }
188
189   value_type& FindAndConstruct(const KeyT &Key) {
190     BucketT *TheBucket;
191     if (LookupBucketFor(Key, TheBucket))
192       return *TheBucket;
193
194     return *InsertIntoBucket(Key, ValueT(), TheBucket);
195   }
196
197   ValueT &operator[](const KeyT &Key) {
198     return FindAndConstruct(Key).second;
199   }
200
201 #if LLVM_USE_RVALUE_REFERENCES
202   value_type& FindAndConstruct(KeyT &&Key) {
203     BucketT *TheBucket;
204     if (LookupBucketFor(Key, TheBucket))
205       return *TheBucket;
206
207     return *InsertIntoBucket(Key, ValueT(), TheBucket);
208   }
209
210   ValueT &operator[](KeyT &&Key) {
211     return FindAndConstruct(Key).second;
212   }
213 #endif
214
215   /// isPointerIntoBucketsArray - Return true if the specified pointer points
216   /// somewhere into the DenseMap's array of buckets (i.e. either to a key or
217   /// value in the DenseMap).
218   bool isPointerIntoBucketsArray(const void *Ptr) const {
219     return Ptr >= getBuckets() && Ptr < getBucketsEnd();
220   }
221
222   /// getPointerIntoBucketsArray() - Return an opaque pointer into the buckets
223   /// array.  In conjunction with the previous method, this can be used to
224   /// determine whether an insertion caused the DenseMap to reallocate.
225   const void *getPointerIntoBucketsArray() const { return getBuckets(); }
226
227 protected:
228   DenseMapBase() : NumEntries(), NumTombstones() {}
229
230   void destroyAll() {
231     if (getNumBuckets() == 0) // Nothing to do.
232       return;
233
234     const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey();
235     for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) {
236       if (!KeyInfoT::isEqual(P->first, EmptyKey) &&
237           !KeyInfoT::isEqual(P->first, TombstoneKey))
238         P->second.~ValueT();
239       P->first.~KeyT();
240     }
241
242 #ifndef NDEBUG
243     memset((void*)getBuckets(), 0x5a, sizeof(BucketT)*getNumBuckets());
244 #endif
245   }
246
247   void initEmpty() {
248     NumEntries = 0;
249     NumTombstones = 0;
250
251     assert((getNumBuckets() & (getNumBuckets()-1)) == 0 &&
252            "# initial buckets must be a power of two!");
253     const KeyT EmptyKey = getEmptyKey();
254     for (BucketT *B = getBuckets(), *E = getBucketsEnd(); B != E; ++B)
255       new (&B->first) KeyT(EmptyKey);
256   }
257
258   void moveFromOldBuckets(BucketT *OldBucketsBegin, BucketT *OldBucketsEnd) {
259     initEmpty();
260
261     // Insert all the old elements.
262     const KeyT EmptyKey = getEmptyKey();
263     const KeyT TombstoneKey = getTombstoneKey();
264     for (BucketT *B = OldBucketsBegin, *E = OldBucketsEnd; B != E; ++B) {
265       if (!KeyInfoT::isEqual(B->first, EmptyKey) &&
266           !KeyInfoT::isEqual(B->first, TombstoneKey)) {
267         // Insert the key/value into the new table.
268         BucketT *DestBucket;
269         bool FoundVal = LookupBucketFor(B->first, DestBucket);
270         (void)FoundVal; // silence warning.
271         assert(!FoundVal && "Key already in new map?");
272         DestBucket->first = llvm_move(B->first);
273         new (&DestBucket->second) ValueT(llvm_move(B->second));
274         ++NumEntries;
275
276         // Free the value.
277         B->second.~ValueT();
278       }
279       B->first.~KeyT();
280     }
281
282 #ifndef NDEBUG
283     if (OldBucketsBegin != OldBucketsEnd)
284       memset((void*)OldBucketsBegin, 0x5a,
285              sizeof(BucketT) * (OldBucketsEnd - OldBucketsBegin));
286 #endif
287   }
288
289   template <typename OtherBaseT>
290   void copyFrom(const DenseMapBase<OtherBaseT, KeyT, ValueT, KeyInfoT>& other) {
291     assert(getNumBuckets() == other.getNumBuckets());
292
293     NumEntries = other.NumEntries;
294     NumTombstones = other.NumTombstones;
295
296     if (isPodLike<KeyT>::value && isPodLike<ValueT>::value)
297       memcpy(getBuckets(), other.getBuckets(),
298              getNumBuckets() * sizeof(BucketT));
299     else
300       for (size_t i = 0; i < getNumBuckets(); ++i) {
301         new (&getBuckets()[i].first) KeyT(other.getBuckets()[i].first);
302         if (!KeyInfoT::isEqual(getBuckets()[i].first, getEmptyKey()) &&
303             !KeyInfoT::isEqual(getBuckets()[i].first, getTombstoneKey()))
304           new (&getBuckets()[i].second) ValueT(other.getBuckets()[i].second);
305       }
306   }
307
308   void swap(DenseMapBase& RHS) {
309     std::swap(NumEntries, RHS.NumEntries);
310     std::swap(NumTombstones, RHS.NumTombstones);
311   }
312
313 private:
314   static unsigned getHashValue(const KeyT &Val) {
315     return KeyInfoT::getHashValue(Val);
316   }
317   template<typename LookupKeyT>
318   static unsigned getHashValue(const LookupKeyT &Val) {
319     return KeyInfoT::getHashValue(Val);
320   }
321   static const KeyT getEmptyKey() {
322     return KeyInfoT::getEmptyKey();
323   }
324   static const KeyT getTombstoneKey() {
325     return KeyInfoT::getTombstoneKey();
326   }
327
328   BucketT *getBuckets() const {
329     return static_cast<const DerivedT *>(this)->getBuckets();
330   }
331
332   unsigned getNumBuckets() const {
333     return static_cast<const DerivedT *>(this)->getNumBuckets();
334   }
335
336   BucketT *getBucketsEnd() const {
337     return getBuckets() + getNumBuckets();
338   }
339
340   void grow(unsigned AtLeast) {
341     static_cast<DerivedT *>(this)->grow(AtLeast);
342   }
343
344   void shrink_and_clear() {
345     static_cast<DerivedT *>(this)->shrink_and_clear();
346     NumTombstones = 0;
347     NumEntries = 0;
348   }
349
350
351   BucketT *InsertIntoBucket(const KeyT &Key, const ValueT &Value,
352                             BucketT *TheBucket) {
353     TheBucket = InsertIntoBucketImpl(Key, TheBucket);
354
355     TheBucket->first = Key;
356     new (&TheBucket->second) ValueT(Value);
357     return TheBucket;
358   }
359
360 #if LLVM_USE_RVALUE_REFERENCES
361   BucketT *InsertIntoBucket(const KeyT &Key, ValueT &&Value,
362                             BucketT *TheBucket) {
363     TheBucket = InsertIntoBucketImpl(Key, TheBucket);
364
365     TheBucket->first = Key;
366     new (&TheBucket->second) ValueT(std::move(Value));
367     return TheBucket;
368   }
369
370   BucketT *InsertIntoBucket(KeyT &&Key, ValueT &&Value, BucketT *TheBucket) {
371     TheBucket = InsertIntoBucketImpl(Key, TheBucket);
372
373     TheBucket->first = std::move(Key);
374     new (&TheBucket->second) ValueT(std::move(Value));
375     return TheBucket;
376   }
377 #endif
378
379   BucketT *InsertIntoBucketImpl(const KeyT &Key, BucketT *TheBucket) {
380     // If the load of the hash table is more than 3/4, or if fewer than 1/8 of
381     // the buckets are empty (meaning that many are filled with tombstones),
382     // grow the table.
383     //
384     // The later case is tricky.  For example, if we had one empty bucket with
385     // tons of tombstones, failing lookups (e.g. for insertion) would have to
386     // probe almost the entire table until it found the empty bucket.  If the
387     // table completely filled with tombstones, no lookup would ever succeed,
388     // causing infinite loops in lookup.
389     unsigned NewNumEntries = NumEntries + 1;
390     if (NewNumEntries*4 >= getNumBuckets()*3) {
391       this->grow(getNumBuckets() * 2);
392       LookupBucketFor(Key, TheBucket);
393     }
394     if (getNumBuckets()-(NewNumEntries+NumTombstones) < getNumBuckets()/8) {
395       this->grow(getNumBuckets());
396       LookupBucketFor(Key, TheBucket);
397     }
398
399     // Only update the state after we've grown our bucket space appropriately
400     // so that when growing buckets we have self-consistent entry count.
401     ++NumEntries;
402
403     // If we are writing over a tombstone, remember this.
404     if (!KeyInfoT::isEqual(TheBucket->first, getEmptyKey()))
405       --NumTombstones;
406
407     return TheBucket;
408   }
409
410   /// LookupBucketFor - Lookup the appropriate bucket for Val, returning it in
411   /// FoundBucket.  If the bucket contains the key and a value, this returns
412   /// true, otherwise it returns a bucket with an empty marker or tombstone and
413   /// returns false.
414   template<typename LookupKeyT>
415   bool LookupBucketFor(const LookupKeyT &Val, BucketT *&FoundBucket) const {
416     unsigned BucketNo = getHashValue(Val);
417     unsigned ProbeAmt = 1;
418     BucketT *BucketsPtr = getBuckets();
419
420     if (getNumBuckets() == 0) {
421       FoundBucket = 0;
422       return false;
423     }
424
425     // FoundTombstone - Keep track of whether we find a tombstone while probing.
426     BucketT *FoundTombstone = 0;
427     const KeyT EmptyKey = getEmptyKey();
428     const KeyT TombstoneKey = getTombstoneKey();
429     assert(!KeyInfoT::isEqual(Val, EmptyKey) &&
430            !KeyInfoT::isEqual(Val, TombstoneKey) &&
431            "Empty/Tombstone value shouldn't be inserted into map!");
432
433     while (1) {
434       BucketT *ThisBucket = BucketsPtr + (BucketNo & (getNumBuckets()-1));
435       // Found Val's bucket?  If so, return it.
436       if (KeyInfoT::isEqual(Val, ThisBucket->first)) {
437         FoundBucket = ThisBucket;
438         return true;
439       }
440
441       // If we found an empty bucket, the key doesn't exist in the set.
442       // Insert it and return the default value.
443       if (KeyInfoT::isEqual(ThisBucket->first, EmptyKey)) {
444         // If we've already seen a tombstone while probing, fill it in instead
445         // of the empty bucket we eventually probed to.
446         if (FoundTombstone) ThisBucket = FoundTombstone;
447         FoundBucket = FoundTombstone ? FoundTombstone : ThisBucket;
448         return false;
449       }
450
451       // If this is a tombstone, remember it.  If Val ends up not in the map, we
452       // prefer to return it than something that would require more probing.
453       if (KeyInfoT::isEqual(ThisBucket->first, TombstoneKey) && !FoundTombstone)
454         FoundTombstone = ThisBucket;  // Remember the first tombstone found.
455
456       // Otherwise, it's a hash collision or a tombstone, continue quadratic
457       // probing.
458       BucketNo += ProbeAmt++;
459     }
460   }
461
462 public:
463   /// Return the approximate size (in bytes) of the actual map.
464   /// This is just the raw memory used by DenseMap.
465   /// If entries are pointers to objects, the size of the referenced objects
466   /// are not included.
467   size_t getMemorySize() const {
468     return getNumBuckets() * sizeof(BucketT);
469   }
470 };
471
472 template<typename KeyT, typename ValueT,
473          typename KeyInfoT = DenseMapInfo<KeyT> >
474 class DenseMap
475     : public DenseMapBase<DenseMap<KeyT, ValueT, KeyInfoT>,
476                           KeyT, ValueT, KeyInfoT> {
477   // Lift some types from the dependent base class into this class for
478   // simplicity of referring to them.
479   typedef DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT> BaseT;
480   typedef typename BaseT::BucketT BucketT;
481   friend class DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT>;
482
483   BucketT *Buckets;
484   unsigned NumBuckets;
485
486 public:
487   explicit DenseMap(unsigned NumInitBuckets = 0) {
488     init(NumInitBuckets);
489   }
490
491   DenseMap(const DenseMap &other) {
492     init(0);
493     copyFrom(other);
494   }
495
496 #if LLVM_USE_RVALUE_REFERENCES
497   DenseMap(DenseMap &&other) {
498     init(0);
499     swap(other);
500   }
501 #endif
502
503   template<typename InputIt>
504   DenseMap(const InputIt &I, const InputIt &E) {
505     init(NextPowerOf2(std::distance(I, E)));
506     this->insert(I, E);
507   }
508
509   ~DenseMap() {
510     this->destroyAll();
511     operator delete(Buckets);
512   }
513
514   void swap(DenseMap& RHS) {
515     std::swap(NumBuckets, RHS.NumBuckets);
516     std::swap(Buckets, RHS.Buckets);
517
518     this->BaseT::swap(RHS);
519   }
520
521   DenseMap& operator=(const DenseMap& other) {
522     copyFrom(other);
523     return *this;
524   }
525
526 #if LLVM_USE_RVALUE_REFERENCES
527   DenseMap& operator=(DenseMap &&other) {
528     this->destroyAll();
529     operator delete(Buckets);
530     init(0);
531     swap(other);
532     return *this;
533   }
534 #endif
535
536   void copyFrom(const DenseMap& other) {
537     this->destroyAll();
538     operator delete(Buckets);
539
540     if (allocateBuckets(other.NumBuckets))
541       this->BaseT::copyFrom(other);
542   }
543
544   void init(unsigned InitBuckets) {
545     if (allocateBuckets(InitBuckets))
546       this->BaseT::initEmpty();
547   }
548
549   void grow(unsigned AtLeast) {
550     unsigned OldNumBuckets = NumBuckets;
551     BucketT *OldBuckets = Buckets;
552
553     allocateBuckets(std::max<unsigned>(64, NextPowerOf2(AtLeast)));
554     assert(Buckets);
555     if (!OldBuckets) {
556       this->BaseT::initEmpty();
557       return;
558     }
559
560     this->moveFromOldBuckets(OldBuckets, OldBuckets+OldNumBuckets);
561
562     // Free the old table.
563     operator delete(OldBuckets);
564   }
565
566   void shrink_and_clear() {
567     unsigned OldSize = this->size();
568     this->destroyAll();
569
570     // Reduce the number of buckets.
571     unsigned NewNumBuckets
572       = std::max(64, 1 << (Log2_32_Ceil(OldSize) + 1));
573     if (NewNumBuckets == NumBuckets) {
574       this->BaseT::initEmpty();
575       return;
576     }
577
578     operator delete(Buckets);
579     init(NewNumBuckets);
580   }
581
582 private:
583   BucketT *getBuckets() const {
584     return Buckets;
585   }
586
587   unsigned getNumBuckets() const {
588     return NumBuckets;
589   }
590
591   bool allocateBuckets(unsigned Num) {
592     NumBuckets = Num;
593     if (NumBuckets == 0) {
594       Buckets = 0;
595       return false;
596     }
597
598     Buckets = static_cast<BucketT*>(operator new(sizeof(BucketT) * NumBuckets));
599     return true;
600   }
601 };
602
603 template<typename KeyT, typename ValueT,
604          typename KeyInfoT, bool IsConst>
605 class DenseMapIterator {
606   typedef std::pair<KeyT, ValueT> Bucket;
607   typedef DenseMapIterator<KeyT, ValueT,
608                            KeyInfoT, true> ConstIterator;
609   friend class DenseMapIterator<KeyT, ValueT, KeyInfoT, true>;
610 public:
611   typedef ptrdiff_t difference_type;
612   typedef typename conditional<IsConst, const Bucket, Bucket>::type value_type;
613   typedef value_type *pointer;
614   typedef value_type &reference;
615   typedef std::forward_iterator_tag iterator_category;
616 private:
617   pointer Ptr, End;
618 public:
619   DenseMapIterator() : Ptr(0), End(0) {}
620
621   DenseMapIterator(pointer Pos, pointer E, bool NoAdvance = false)
622     : Ptr(Pos), End(E) {
623     if (!NoAdvance) AdvancePastEmptyBuckets();
624   }
625
626   // If IsConst is true this is a converting constructor from iterator to
627   // const_iterator and the default copy constructor is used.
628   // Otherwise this is a copy constructor for iterator.
629   DenseMapIterator(const DenseMapIterator<KeyT, ValueT,
630                                           KeyInfoT, false>& I)
631     : Ptr(I.Ptr), End(I.End) {}
632
633   reference operator*() const {
634     return *Ptr;
635   }
636   pointer operator->() const {
637     return Ptr;
638   }
639
640   bool operator==(const ConstIterator &RHS) const {
641     return Ptr == RHS.operator->();
642   }
643   bool operator!=(const ConstIterator &RHS) const {
644     return Ptr != RHS.operator->();
645   }
646
647   inline DenseMapIterator& operator++() {  // Preincrement
648     ++Ptr;
649     AdvancePastEmptyBuckets();
650     return *this;
651   }
652   DenseMapIterator operator++(int) {  // Postincrement
653     DenseMapIterator tmp = *this; ++*this; return tmp;
654   }
655
656 private:
657   void AdvancePastEmptyBuckets() {
658     const KeyT Empty = KeyInfoT::getEmptyKey();
659     const KeyT Tombstone = KeyInfoT::getTombstoneKey();
660
661     while (Ptr != End &&
662            (KeyInfoT::isEqual(Ptr->first, Empty) ||
663             KeyInfoT::isEqual(Ptr->first, Tombstone)))
664       ++Ptr;
665   }
666 };
667   
668 template<typename KeyT, typename ValueT, typename KeyInfoT>
669 static inline size_t
670 capacity_in_bytes(const DenseMap<KeyT, ValueT, KeyInfoT> &X) {
671   return X.getMemorySize();
672 }
673
674 } // end namespace llvm
675
676 #endif