diff --git a/include/llvm/ADT/alist.h b/include/llvm/ADT/alist.h new file mode 100644 index 00000000000..f5924843129 --- /dev/null +++ b/include/llvm/ADT/alist.h @@ -0,0 +1,292 @@ +//==- llvm/ADT/alist.h - Linked lists with hooks -----------------*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the alist class template, and related infrastructure. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_ALIST_H +#define LLVM_ADT_ALIST_H + +#include +#include "llvm/ADT/alist_node.h" +#include "llvm/ADT/STLExtras.h" + +namespace llvm { + +/// alist_iterator - An iterator class for alist. +/// +template > > +class alist_iterator : public bidirectional_iterator { + typedef bidirectional_iterator super; + typedef alist_node NodeTy; + + /// NodeIter - The underlying iplist iterator that is being wrapped. + NodeIterT NodeIter; + +public: + typedef size_t size_type; + typedef typename super::pointer pointer; + typedef typename super::reference reference; + + alist_iterator(NodeIterT NI) : NodeIter(NI) {} + alist_iterator(pointer EP) : NodeIter(NodeTy::getNode(EP)) {} + alist_iterator() : NodeIter() {} + + // This is templated so that we can allow constructing a const iterator from + // a nonconst iterator... + template + alist_iterator(const alist_iterator &RHS) + : NodeIter(RHS.getNodeIterUnchecked()) {} + + // This is templated so that we can allow assigning to a const iterator from + // a nonconst iterator... + template + const alist_iterator &operator=(const alist_iterator &RHS) { + NodeIter = RHS.getNodeIterUnchecked(); + return *this; + } + + operator pointer() const { return NodeIter->getElement((T*)0); } + + reference operator*() const { return *NodeIter->getElement((T*)0); } + pointer operator->() const { return &operator*(); } + + bool operator==(const alist_iterator &RHS) const { + return NodeIter == RHS.NodeIter; + } + bool operator!=(const alist_iterator &RHS) const { + return NodeIter != RHS.NodeIter; + } + + alist_iterator &operator--() { + --NodeIter; + return *this; + } + alist_iterator &operator++() { + ++NodeIter; + return *this; + } + alist_iterator operator--(int) { + alist_iterator tmp = *this; + --*this; + return tmp; + } + alist_iterator operator++(int) { + alist_iterator tmp = *this; + ++*this; + return tmp; + } + + NodeIterT getNodeIterUnchecked() const { return NodeIter; } +}; + +// do not implement. this is to catch errors when people try to use +// them as random access iterators +template +void operator-(int, alist_iterator); +template +void operator-(alist_iterator,int); + +template +void operator+(int, alist_iterator); +template +void operator+(alist_iterator,int); + +// operator!=/operator== - Allow mixed comparisons without dereferencing +// the iterator, which could very likely be pointing to end(). +template +bool operator!=(T* LHS, const alist_iterator &RHS) { + return LHS != RHS.getNodeIterUnchecked().getNodePtrUnchecked() + ->getElement((T*)0); +} +template +bool operator==(T* LHS, const alist_iterator &RHS) { + return LHS == RHS.getNodeIterUnchecked().getNodePtrUnchecked() + ->getElement((T*)0); +} + +// Allow alist_iterators to convert into pointers to a node automatically when +// used by the dyn_cast, cast, isa mechanisms... + +template struct simplify_type; + +template +struct simplify_type > { + typedef alist_node NodeTy; + typedef NodeTy* SimpleType; + + static SimpleType + getSimplifiedValue(const alist_iterator &Node) { + return &*Node; + } +}; +template +struct simplify_type > { + typedef alist_node NodeTy; + typedef NodeTy* SimpleType; + + static SimpleType + getSimplifiedValue(const alist_iterator &Node) { + return &*Node; + } +}; + +/// Template traits for alist. By specializing this template class, you +/// can register custom actions to be run when a node is added to or removed +/// from an alist. A common use of this is to update parent pointers. +/// +template +class alist_traits { + typedef alist_iterator iterator; + +public: + void addNodeToList(T *) {} + void removeNodeFromList(T *) {} + void transferNodesFromList(alist_traits &, iterator, iterator) {} + void deleteNode(T *E) { delete alist_node::getNode(E); } +}; + +/// alist - This class is an ilist-style container that automatically +/// adds the next/prev pointers. It is designed to work in cooperation +/// with . +/// +template +class alist { + typedef alist_node NodeTy; + +public: + typedef typename ilist::size_type size_type; + +private: + /// NodeListTraits - ilist traits for NodeList. + /// + struct NodeListTraits : ilist_traits > { + alist_traits UserTraits; + + void addNodeToList(NodeTy *N) { + UserTraits.addNodeToList(N->getElement((T*)0)); + } + void removeNodeFromList(NodeTy *N) { + UserTraits.removeNodeFromList(N->getElement((T*)0)); + } + void transferNodesFromList(iplist &L2, + ilist_iterator first, + ilist_iterator last) { + UserTraits.transferNodesFromList(L2.UserTraits, + iterator(first), + iterator(last)); + } + }; + + /// NodeList - Doubly-linked list of nodes that have constructed + /// contents and may be in active use. + /// + iplist NodeList; + +public: + ~alist() { clear(); } + + typedef alist_iterator > + iterator; + typedef alist_iterator > + const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + iterator begin() { return iterator(NodeList.begin()); } + iterator end() { return iterator(NodeList.end()); } + const_iterator begin() const { return const_iterator(NodeList.begin()); } + const_iterator end() const { return const_iterator(NodeList.end()); } + reverse_iterator rbegin() { return reverse_iterator(NodeList.rbegin()); } + reverse_iterator rend() { return reverse_iterator(NodeList.rend()); } + const_reverse_iterator rbegin() const { + return const_reverse_iterator(NodeList.rbegin()); + } + const_reverse_iterator rend() const { + return const_reverse_iterator(NodeList.rend()); + } + + typedef T& reference; + typedef const T& const_reference; + reference front() { return *NodeList.front().getElement((T*)0); } + reference back() { return *NodeList.back().getElement((T*)0); } + const_reference front() const { return *NodeList.front().getElement((T*)0); } + const_reference back() const { return *NodeList.back().getElement((T*)0); } + + bool empty() const { return NodeList.empty(); } + size_type size() const { return NodeList.size(); } + + void push_front(T *E) { + NodeTy *N = alist_node::getNode(E); + assert(N->getPrev() == 0); + assert(N->getNext() == 0); + NodeList.push_front(N); + } + void push_back(T *E) { + NodeTy *N = alist_node::getNode(E); + assert(N->getPrev() == 0); + assert(N->getNext() == 0); + NodeList.push_back(N); + } + iterator insert(iterator I, T *E) { + NodeTy *N = alist_node::getNode(E); + assert(N->getPrev() == 0); + assert(N->getNext() == 0); + return iterator(NodeList.insert(I.getNodeIterUnchecked(), N)); + } + void splice(iterator where, alist &Other) { + NodeList.splice(where.getNodeIterUnchecked(), Other.NodeList); + } + void splice(iterator where, alist &Other, iterator From) { + NodeList.splice(where.getNodeIterUnchecked(), Other.NodeList, + From.getNodeIterUnchecked()); + } + void splice(iterator where, alist &Other, iterator From, + iterator To) { + NodeList.splice(where.getNodeIterUnchecked(), Other.NodeList, + From.getNodeIterUnchecked(), To.getNodeIterUnchecked()); + } + + void pop_front() { + erase(NodeList.begin()); + } + void pop_back() { + erase(prior(NodeList.end())); + } + iterator erase(iterator I) { + iterator Next = next(I); + NodeTy *N = NodeList.remove(I.getNodeIterUnchecked()); + NodeList.UserTraits.deleteNode(N->getElement((T*)0)); + return Next; + } + iterator erase(iterator first, iterator last) { + while (first != last) + first = erase(first); + return last; + } + + T *remove(T *E) { + NodeTy *N = alist_node::getNode(E); + return NodeList.remove(N)->getElement((T*)0); + } + + void clear() { + while (!empty()) pop_front(); + } + + alist_traits &getTraits() { + return NodeList.UserTraits; + } +}; + +} + +#endif diff --git a/include/llvm/ADT/alist_node.h b/include/llvm/ADT/alist_node.h new file mode 100644 index 00000000000..a1f18c0bcb5 --- /dev/null +++ b/include/llvm/ADT/alist_node.h @@ -0,0 +1,126 @@ +//==- llvm/ADT/alist_node.h - Next/Prev helper class for alist ---*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the alist_node class template, which is used by the alist +// class template to provide next/prev pointers for arbitrary objects. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_ALIST_NODE_H +#define LLVM_ADT_ALIST_NODE_H + +#include +#include "llvm/ADT/ilist.h" +#include "llvm/Support/AlignOf.h" +#include "llvm/Support/DataTypes.h" + +namespace llvm { + +/// alist_node - This is a utility class used by alist. It holds prev and next +/// pointers for use with ilists, as well as storage for objects as large as +/// LargestT, that are in T's inheritance tree. +/// +template +class alist_node { + alist_node *Prev, *Next; + +public: + alist_node() : Prev(0), Next(0) {} + + alist_node *getPrev() const { return Prev; } + alist_node *getNext() const { return Next; } + void setPrev(alist_node *N) { Prev = N; } + void setNext(alist_node *N) { Next = N; } + + union { + char Bytes[sizeof(LargestT)]; + long long L; + void *P; + } Storage; + + template + SubClass *getElement(SubClass *) { + assert(sizeof(SubClass) <= sizeof(LargestT)); + assert(unsigned(AlignOf::Alignment) <= + unsigned(AlignOf::Alignment)); + return reinterpret_cast(&Storage.Bytes); + } + + template + const SubClass *getElement(SubClass *) const { + assert(sizeof(SubClass) <= sizeof(LargestT)); + assert(unsigned(AlignOf::Alignment) <= + unsigned(AlignOf::Alignment)); + return reinterpret_cast(&Storage.Bytes); + } + + // This code essentially does offsetof, but actual offsetof hits an ICE in + // GCC 4.0 relating to offsetof being used inside a template. + static alist_node* getNode(T *D) { + return reinterpret_cast(reinterpret_cast(D) - + (uintptr_t)&getNull()->Storage); + } + static const alist_node* getNode(const T *D) { + return reinterpret_cast(reinterpret_cast(D) - + (uintptr_t)&getNull()->Storage); + } +private: + static alist_node* getNull() { return 0; } +}; + +// A specialization of ilist_traits for alist_nodes. +template +class ilist_traits > { + typedef alist_node NodeTy; + +protected: + // Allocate a sentinel inside the traits class. This works + // because iplist carries an instance of the traits class. + NodeTy Sentinel; + +public: + static NodeTy *getPrev(NodeTy *N) { return N->getPrev(); } + static NodeTy *getNext(NodeTy *N) { return N->getNext(); } + static const NodeTy *getPrev(const NodeTy *N) { return N->getPrev(); } + static const NodeTy *getNext(const NodeTy *N) { return N->getNext(); } + + static void setPrev(NodeTy *N, NodeTy *Prev) { N->setPrev(Prev); } + static void setNext(NodeTy *N, NodeTy *Next) { N->setNext(Next); } + + NodeTy *createSentinel() const { + assert(Sentinel.getPrev() == 0); + assert(Sentinel.getNext() == 0); + return const_cast(&Sentinel); + } + + void destroySentinel(NodeTy *N) { + assert(N == &Sentinel); + Sentinel.setPrev(0); + Sentinel.setNext(0); + } + + void addNodeToList(NodeTy *N) {} + void removeNodeFromList(NodeTy *N) {} + void transferNodesFromList(iplist &L2, + ilist_iterator first, + ilist_iterator last) {} + + // Ideally we wouldn't implement this, but ilist's clear calls it, + // which is called from ilist's destructor. We won't ever call + // either of those with a non-empty list, but statically this + // method needs to exist. + void deleteNode(NodeTy *N) { assert(0); } + +private: + static NodeTy *createNode(const NodeTy &V); // do not implement +}; + +} + +#endif diff --git a/include/llvm/ADT/ilist.h b/include/llvm/ADT/ilist.h index 9700b60f240..e66ee2f40bc 100644 --- a/include/llvm/ADT/ilist.h +++ b/include/llvm/ADT/ilist.h @@ -60,6 +60,7 @@ struct ilist_traits { static void setNext(NodeTy *N, NodeTy *Next) { N->setNext(Next); } static NodeTy *createNode(const NodeTy &V) { return new NodeTy(V); } + static void deleteNode(NodeTy *V) { delete V; } static NodeTy *createSentinel() { return new NodeTy(); } static void destroySentinel(NodeTy *N) { delete N; } @@ -121,8 +122,7 @@ public: assert(Traits::getNext(NodePtr) != 0 && "Dereferencing end()!"); return *NodePtr; } - pointer operator->() { return &operator*(); } - const pointer operator->() const { return &operator*(); } + pointer operator->() const { return &operator*(); } // Comparison operators bool operator==(const ilist_iterator &RHS) const { @@ -380,7 +380,7 @@ public: // erase - remove a node from the controlled sequence... and delete it. iterator erase(iterator where) { - delete remove(where); + deleteNode(remove(where)); return where; } diff --git a/include/llvm/Support/Recycler.h b/include/llvm/Support/Recycler.h new file mode 100644 index 00000000000..3b514dd6a82 --- /dev/null +++ b/include/llvm/Support/Recycler.h @@ -0,0 +1,97 @@ +//==- llvm/Support/Recycler.h - Recycling Allocator --------------*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Recycler class template. See the doxygen comment for +// Recycler for more details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_RECYCLER_H +#define LLVM_SUPPORT_RECYCLER_H + +#include +#include "llvm/ADT/alist_node.h" + +namespace llvm { + +/// PrintRecyclingAllocatorStats - Helper for RecyclingAllocator for +/// printing statistics. +/// +void PrintRecyclerStats(size_t LargestTypeSize, size_t FreeListSize); + +/// Recycler - This class manages a linked-list of deallocated nodes +/// and facilitates reusing deallocated memory in place of allocating +/// new memory. The objects it allocates are stored in alist_node +/// containers, so they may be used in alists. +/// +template +class Recycler { + typedef alist_node NodeTy; + + /// FreeListTraits - ilist traits for FreeList. + /// + struct FreeListTraits : ilist_traits > { + NodeTy &getSentinel() { return this->Sentinel; } + }; + + /// FreeList - Doubly-linked list of nodes that have deleted contents and + /// are not in active use. + /// + iplist FreeList; + + /// CreateNewNode - Allocate a new node object and initialize its + /// prev and next pointers to 0. + /// + template + NodeTy *CreateNewNode(AllocatorType &Allocator) { + // Note that we're calling new on the *node*, to initialize its + // Next/Prev pointers, not new on the end-user object. + return new (Allocator.Allocate()) NodeTy(); + } + +public: + ~Recycler() { assert(FreeList.empty()); } + + template + void clear(AllocatorType &Allocator) { + while (!FreeList.empty()) + Allocator.Deallocate(FreeList.remove(FreeList.begin())); + } + + template + SubClass *Allocate(AllocatorType &Allocator) { + NodeTy *N = !FreeList.empty() ? + FreeList.remove(FreeList.front()) : + CreateNewNode(Allocator); + assert(N->getPrev() == 0); + assert(N->getNext() == 0); + return N->getElement((SubClass*)0); + } + + template + T *Allocate(AllocatorType &Allocator) { + return Allocate(Allocator); + } + + template + void Deallocate(AllocatorType &Allocator, SubClass* Element) { + NodeTy *N = NodeTy::getNode(Element); + assert(N->getPrev() == 0); + assert(N->getNext() == 0); + FreeList.push_front(N); + } + + void PrintStats() { + PrintRecyclerStats(sizeof(LargestT), FreeList.size()); + } +}; + +} + +#endif diff --git a/include/llvm/Support/RecyclingAllocator.h b/include/llvm/Support/RecyclingAllocator.h new file mode 100644 index 00000000000..a338c0eb639 --- /dev/null +++ b/include/llvm/Support/RecyclingAllocator.h @@ -0,0 +1,60 @@ +//==- llvm/Support/RecyclingAllocator.h - Recycling Allocator ----*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the RecyclingAllocator class. See the doxygen comment for +// RecyclingAllocator for more details on the implementation. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_RECYCLINGALLOCATOR_H +#define LLVM_SUPPORT_RECYCLINGALLOCATOR_H + +#include +#include "llvm/Support/Recycler.h" +#include "llvm/ADT/STLExtras.h" + +namespace llvm { + +/// RecyclingAllocator - This class wraps an Allocator, adding the +/// functionality of recycling deleted objects. +/// +template +class RecyclingAllocator { +private: + /// Base - Implementation details. + /// + Recycler Base; + + /// Allocator - The wrapped allocator. + /// + AllocatorType Allocator; + +public: + ~RecyclingAllocator() { Base.clear(Allocator); } + + /// Allocate - Return a pointer to storage for an object of type + /// SubClass. The storage may be either newly allocated or recycled. + /// + template + SubClass *Allocate() { return Base.Allocate(Allocator); } + + T *Allocate() { return Base.Allocate(Allocator); } + + /// Deallocate - Release storage for the pointed-to object. The + /// storage will be kept track of and may be recycled. + /// + template + void Deallocate(SubClass* E) { return Base.Deallocate(Allocator, E); } + + void PrintStats() { Base.PrintStats(); } +}; + +} + +#endif diff --git a/include/llvm/SymbolTableListTraits.h b/include/llvm/SymbolTableListTraits.h index 8166a4eee24..7d747d4c5e8 100644 --- a/include/llvm/SymbolTableListTraits.h +++ b/include/llvm/SymbolTableListTraits.h @@ -57,6 +57,10 @@ public: return V->getNext(); } + void deleteNode(ValueSubClass *V) { + delete V; + } + static void setPrev(ValueSubClass *V, ValueSubClass *P) { V->setPrev(P); } static void setNext(ValueSubClass *V, ValueSubClass *N) { V->setNext(N); } diff --git a/lib/Support/Allocator.cpp b/lib/Support/Allocator.cpp index ba6a393c81f..584ca125b73 100644 --- a/lib/Support/Allocator.cpp +++ b/lib/Support/Allocator.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Allocator.h" +#include "llvm/Support/Recycler.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/Streams.h" #include @@ -130,3 +131,9 @@ void BumpPtrAllocator::PrintStats() const { cerr << "\nNumber of memory regions: " << NumRegions << "\n"; cerr << "Bytes allocated: " << BytesUsed << "\n"; } + +void llvm::PrintRecyclerStats(size_t LargestTypeSize, + size_t FreeListSize) { + cerr << "Recycler element size: " << LargestTypeSize << '\n'; + cerr << "Number of elements free for recycling: " << FreeListSize << '\n'; +}