13771902e922796f506dfda5955d7d80b61104696Ted Kremenek//==--- ImmutableList.h - Immutable (functional) list interface --*- C++ -*-==//
23771902e922796f506dfda5955d7d80b61104696Ted Kremenek//
33771902e922796f506dfda5955d7d80b61104696Ted Kremenek//                     The LLVM Compiler Infrastructure
43771902e922796f506dfda5955d7d80b61104696Ted Kremenek//
53771902e922796f506dfda5955d7d80b61104696Ted Kremenek// This file is distributed under the University of Illinois Open Source
63771902e922796f506dfda5955d7d80b61104696Ted Kremenek// License. See LICENSE.TXT for details.
73771902e922796f506dfda5955d7d80b61104696Ted Kremenek//
83771902e922796f506dfda5955d7d80b61104696Ted Kremenek//===----------------------------------------------------------------------===//
93771902e922796f506dfda5955d7d80b61104696Ted Kremenek//
103771902e922796f506dfda5955d7d80b61104696Ted Kremenek// This file defines the ImmutableList class.
113771902e922796f506dfda5955d7d80b61104696Ted Kremenek//
123771902e922796f506dfda5955d7d80b61104696Ted Kremenek//===----------------------------------------------------------------------===//
133771902e922796f506dfda5955d7d80b61104696Ted Kremenek
143771902e922796f506dfda5955d7d80b61104696Ted Kremenek#ifndef LLVM_ADT_IMLIST_H
153771902e922796f506dfda5955d7d80b61104696Ted Kremenek#define LLVM_ADT_IMLIST_H
163771902e922796f506dfda5955d7d80b61104696Ted Kremenek
173771902e922796f506dfda5955d7d80b61104696Ted Kremenek#include "llvm/Support/Allocator.h"
183771902e922796f506dfda5955d7d80b61104696Ted Kremenek#include "llvm/ADT/FoldingSet.h"
191f6efa3996dd1929fbc129203ce5009b620e6969Michael J. Spencer#include "llvm/Support/DataTypes.h"
203771902e922796f506dfda5955d7d80b61104696Ted Kremenek#include <cassert>
213771902e922796f506dfda5955d7d80b61104696Ted Kremenek
223771902e922796f506dfda5955d7d80b61104696Ted Kremeneknamespace llvm {
233771902e922796f506dfda5955d7d80b61104696Ted Kremenek
243771902e922796f506dfda5955d7d80b61104696Ted Kremenektemplate <typename T> class ImmutableListFactory;
253a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
263771902e922796f506dfda5955d7d80b61104696Ted Kremenektemplate <typename T>
273771902e922796f506dfda5955d7d80b61104696Ted Kremenekclass ImmutableListImpl : public FoldingSetNode {
283771902e922796f506dfda5955d7d80b61104696Ted Kremenek  T Head;
29e06e91122fefcadd252ddd2f2591e181683fc2f1Ted Kremenek  const ImmutableListImpl* Tail;
303771902e922796f506dfda5955d7d80b61104696Ted Kremenek
31e06e91122fefcadd252ddd2f2591e181683fc2f1Ted Kremenek  ImmutableListImpl(const T& head, const ImmutableListImpl* tail = 0)
323771902e922796f506dfda5955d7d80b61104696Ted Kremenek    : Head(head), Tail(tail) {}
333a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
343771902e922796f506dfda5955d7d80b61104696Ted Kremenek  friend class ImmutableListFactory<T>;
353a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
363771902e922796f506dfda5955d7d80b61104696Ted Kremenek  // Do not implement.
373771902e922796f506dfda5955d7d80b61104696Ted Kremenek  void operator=(const ImmutableListImpl&);
383771902e922796f506dfda5955d7d80b61104696Ted Kremenek  ImmutableListImpl(const ImmutableListImpl&);
393a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
403771902e922796f506dfda5955d7d80b61104696Ted Kremenekpublic:
413771902e922796f506dfda5955d7d80b61104696Ted Kremenek  const T& getHead() const { return Head; }
42e06e91122fefcadd252ddd2f2591e181683fc2f1Ted Kremenek  const ImmutableListImpl* getTail() const { return Tail; }
433a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
443771902e922796f506dfda5955d7d80b61104696Ted Kremenek  static inline void Profile(FoldingSetNodeID& ID, const T& H,
45e06e91122fefcadd252ddd2f2591e181683fc2f1Ted Kremenek                             const ImmutableListImpl* L){
463771902e922796f506dfda5955d7d80b61104696Ted Kremenek    ID.AddPointer(L);
473771902e922796f506dfda5955d7d80b61104696Ted Kremenek    ID.Add(H);
483771902e922796f506dfda5955d7d80b61104696Ted Kremenek  }
493a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
503771902e922796f506dfda5955d7d80b61104696Ted Kremenek  void Profile(FoldingSetNodeID& ID) {
513771902e922796f506dfda5955d7d80b61104696Ted Kremenek    Profile(ID, Head, Tail);
523771902e922796f506dfda5955d7d80b61104696Ted Kremenek  }
533771902e922796f506dfda5955d7d80b61104696Ted Kremenek};
543a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
553771902e922796f506dfda5955d7d80b61104696Ted Kremenek/// ImmutableList - This class represents an immutable (functional) list.
563771902e922796f506dfda5955d7d80b61104696Ted Kremenek///  It is implemented as a smart pointer (wraps ImmutableListImpl), so it
573771902e922796f506dfda5955d7d80b61104696Ted Kremenek///  it is intended to always be copied by value as if it were a pointer.
583771902e922796f506dfda5955d7d80b61104696Ted Kremenek///  This interface matches ImmutableSet and ImmutableMap.  ImmutableList
593771902e922796f506dfda5955d7d80b61104696Ted Kremenek///  objects should almost never be created directly, and instead should
603771902e922796f506dfda5955d7d80b61104696Ted Kremenek///  be created by ImmutableListFactory objects that manage the lifetime
613771902e922796f506dfda5955d7d80b61104696Ted Kremenek///  of a group of lists.  When the factory object is reclaimed, all lists
623771902e922796f506dfda5955d7d80b61104696Ted Kremenek///  created by that factory are released as well.
633771902e922796f506dfda5955d7d80b61104696Ted Kremenektemplate <typename T>
643771902e922796f506dfda5955d7d80b61104696Ted Kremenekclass ImmutableList {
653771902e922796f506dfda5955d7d80b61104696Ted Kremenekpublic:
663771902e922796f506dfda5955d7d80b61104696Ted Kremenek  typedef T value_type;
673771902e922796f506dfda5955d7d80b61104696Ted Kremenek  typedef ImmutableListFactory<T> Factory;
683771902e922796f506dfda5955d7d80b61104696Ted Kremenek
693771902e922796f506dfda5955d7d80b61104696Ted Kremenekprivate:
70e06e91122fefcadd252ddd2f2591e181683fc2f1Ted Kremenek  const ImmutableListImpl<T>* X;
713771902e922796f506dfda5955d7d80b61104696Ted Kremenek
723771902e922796f506dfda5955d7d80b61104696Ted Kremenekpublic:
733771902e922796f506dfda5955d7d80b61104696Ted Kremenek  // This constructor should normally only be called by ImmutableListFactory<T>.
743771902e922796f506dfda5955d7d80b61104696Ted Kremenek  // There may be cases, however, when one needs to extract the internal pointer
753771902e922796f506dfda5955d7d80b61104696Ted Kremenek  // and reconstruct a list object from that pointer.
76e06e91122fefcadd252ddd2f2591e181683fc2f1Ted Kremenek  ImmutableList(const ImmutableListImpl<T>* x = 0) : X(x) {}
773771902e922796f506dfda5955d7d80b61104696Ted Kremenek
78e06e91122fefcadd252ddd2f2591e181683fc2f1Ted Kremenek  const ImmutableListImpl<T>* getInternalPointer() const {
793771902e922796f506dfda5955d7d80b61104696Ted Kremenek    return X;
803771902e922796f506dfda5955d7d80b61104696Ted Kremenek  }
813a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
823771902e922796f506dfda5955d7d80b61104696Ted Kremenek  class iterator {
83e06e91122fefcadd252ddd2f2591e181683fc2f1Ted Kremenek    const ImmutableListImpl<T>* L;
843771902e922796f506dfda5955d7d80b61104696Ted Kremenek  public:
853771902e922796f506dfda5955d7d80b61104696Ted Kremenek    iterator() : L(0) {}
863771902e922796f506dfda5955d7d80b61104696Ted Kremenek    iterator(ImmutableList l) : L(l.getInternalPointer()) {}
873a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
88445723bfb0d3c4cb7ecebb60710c669cf3dd2c8dTed Kremenek    iterator& operator++() { L = L->getTail(); return *this; }
893771902e922796f506dfda5955d7d80b61104696Ted Kremenek    bool operator==(const iterator& I) const { return L == I.L; }
90445723bfb0d3c4cb7ecebb60710c669cf3dd2c8dTed Kremenek    bool operator!=(const iterator& I) const { return L != I.L; }
913a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman    const value_type& operator*() const { return L->getHead(); }
923a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman    ImmutableList getList() const { return L; }
933771902e922796f506dfda5955d7d80b61104696Ted Kremenek  };
943771902e922796f506dfda5955d7d80b61104696Ted Kremenek
9530389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek  /// begin - Returns an iterator referring to the head of the list, or
9630389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek  ///  an iterator denoting the end of the list if the list is empty.
973771902e922796f506dfda5955d7d80b61104696Ted Kremenek  iterator begin() const { return iterator(X); }
983a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
9930389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek  /// end - Returns an iterator denoting the end of the list.  This iterator
10030389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek  ///  does not refer to a valid list element.
1013771902e922796f506dfda5955d7d80b61104696Ted Kremenek  iterator end() const { return iterator(); }
1023771902e922796f506dfda5955d7d80b61104696Ted Kremenek
10330389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek  /// isEmpty - Returns true if the list is empty.
1043771902e922796f506dfda5955d7d80b61104696Ted Kremenek  bool isEmpty() const { return !X; }
1053a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
106298bc9a1a5161a5f6e5a0f35e8372d008ef6e812Nick Lewycky  bool contains(const T& V) const {
107298bc9a1a5161a5f6e5a0f35e8372d008ef6e812Nick Lewycky    for (iterator I = begin(), E = end(); I != E; ++I) {
108298bc9a1a5161a5f6e5a0f35e8372d008ef6e812Nick Lewycky      if (*I == V)
109298bc9a1a5161a5f6e5a0f35e8372d008ef6e812Nick Lewycky        return true;
110298bc9a1a5161a5f6e5a0f35e8372d008ef6e812Nick Lewycky    }
111298bc9a1a5161a5f6e5a0f35e8372d008ef6e812Nick Lewycky    return false;
112298bc9a1a5161a5f6e5a0f35e8372d008ef6e812Nick Lewycky  }
113298bc9a1a5161a5f6e5a0f35e8372d008ef6e812Nick Lewycky
11430389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek  /// isEqual - Returns true if two lists are equal.  Because all lists created
11530389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek  ///  from the same ImmutableListFactory are uniqued, this has O(1) complexity
11630389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek  ///  because it the contents of the list do not need to be compared.  Note
11730389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek  ///  that you should only compare two lists created from the same
11830389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek  ///  ImmutableListFactory.
1193a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman  bool isEqual(const ImmutableList& L) const { return X == L.X; }
12030389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek
1213771902e922796f506dfda5955d7d80b61104696Ted Kremenek  bool operator==(const ImmutableList& L) const { return isEqual(L); }
1223771902e922796f506dfda5955d7d80b61104696Ted Kremenek
12330389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek  /// getHead - Returns the head of the list.
1243771902e922796f506dfda5955d7d80b61104696Ted Kremenek  const T& getHead() {
1253771902e922796f506dfda5955d7d80b61104696Ted Kremenek    assert (!isEmpty() && "Cannot get the head of an empty list.");
1263771902e922796f506dfda5955d7d80b61104696Ted Kremenek    return X->getHead();
1273771902e922796f506dfda5955d7d80b61104696Ted Kremenek  }
1283a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
12930389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek  /// getTail - Returns the tail of the list, which is another (possibly empty)
13030389141c9c7270b4733ec0b9bc5ad58541f39daTed Kremenek  ///  ImmutableList.
1313771902e922796f506dfda5955d7d80b61104696Ted Kremenek  ImmutableList getTail() {
1323771902e922796f506dfda5955d7d80b61104696Ted Kremenek    return X ? X->getTail() : 0;
1333a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman  }
1342ef5d4cd6ab2e8f57bba88cc6ef0e3132e784e63Zhongxing Xu
1352ef5d4cd6ab2e8f57bba88cc6ef0e3132e784e63Zhongxing Xu  void Profile(FoldingSetNodeID& ID) const {
1362ef5d4cd6ab2e8f57bba88cc6ef0e3132e784e63Zhongxing Xu    ID.AddPointer(X);
1372ef5d4cd6ab2e8f57bba88cc6ef0e3132e784e63Zhongxing Xu  }
1383771902e922796f506dfda5955d7d80b61104696Ted Kremenek};
1393a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
1403771902e922796f506dfda5955d7d80b61104696Ted Kremenektemplate <typename T>
1413771902e922796f506dfda5955d7d80b61104696Ted Kremenekclass ImmutableListFactory {
1423a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman  typedef ImmutableListImpl<T> ListTy;
1433771902e922796f506dfda5955d7d80b61104696Ted Kremenek  typedef FoldingSet<ListTy>   CacheTy;
1443a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
1453771902e922796f506dfda5955d7d80b61104696Ted Kremenek  CacheTy Cache;
1463771902e922796f506dfda5955d7d80b61104696Ted Kremenek  uintptr_t Allocator;
1473a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
1483771902e922796f506dfda5955d7d80b61104696Ted Kremenek  bool ownsAllocator() const {
1493771902e922796f506dfda5955d7d80b61104696Ted Kremenek    return Allocator & 0x1 ? false : true;
1503771902e922796f506dfda5955d7d80b61104696Ted Kremenek  }
1513a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
1523a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman  BumpPtrAllocator& getAllocator() const {
1533771902e922796f506dfda5955d7d80b61104696Ted Kremenek    return *reinterpret_cast<BumpPtrAllocator*>(Allocator & ~0x1);
1543a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman  }
1553771902e922796f506dfda5955d7d80b61104696Ted Kremenek
1563771902e922796f506dfda5955d7d80b61104696Ted Kremenekpublic:
1573771902e922796f506dfda5955d7d80b61104696Ted Kremenek  ImmutableListFactory()
1583771902e922796f506dfda5955d7d80b61104696Ted Kremenek    : Allocator(reinterpret_cast<uintptr_t>(new BumpPtrAllocator())) {}
1593a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
1603771902e922796f506dfda5955d7d80b61104696Ted Kremenek  ImmutableListFactory(BumpPtrAllocator& Alloc)
1613771902e922796f506dfda5955d7d80b61104696Ted Kremenek  : Allocator(reinterpret_cast<uintptr_t>(&Alloc) | 0x1) {}
1623a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
1633771902e922796f506dfda5955d7d80b61104696Ted Kremenek  ~ImmutableListFactory() {
1643771902e922796f506dfda5955d7d80b61104696Ted Kremenek    if (ownsAllocator()) delete &getAllocator();
1653771902e922796f506dfda5955d7d80b61104696Ted Kremenek  }
1663a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
1679c336fabd59fbdbe9129d76fbbee32261ac7c8f0Ted Kremenek  ImmutableList<T> concat(const T& Head, ImmutableList<T> Tail) {
1683771902e922796f506dfda5955d7d80b61104696Ted Kremenek    // Profile the new list to see if it already exists in our cache.
1693771902e922796f506dfda5955d7d80b61104696Ted Kremenek    FoldingSetNodeID ID;
1703771902e922796f506dfda5955d7d80b61104696Ted Kremenek    void* InsertPos;
1713a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
172e06e91122fefcadd252ddd2f2591e181683fc2f1Ted Kremenek    const ListTy* TailImpl = Tail.getInternalPointer();
1733771902e922796f506dfda5955d7d80b61104696Ted Kremenek    ListTy::Profile(ID, Head, TailImpl);
1743771902e922796f506dfda5955d7d80b61104696Ted Kremenek    ListTy* L = Cache.FindNodeOrInsertPos(ID, InsertPos);
1753a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
1763771902e922796f506dfda5955d7d80b61104696Ted Kremenek    if (!L) {
1773771902e922796f506dfda5955d7d80b61104696Ted Kremenek      // The list does not exist in our cache.  Create it.
1783771902e922796f506dfda5955d7d80b61104696Ted Kremenek      BumpPtrAllocator& A = getAllocator();
1793771902e922796f506dfda5955d7d80b61104696Ted Kremenek      L = (ListTy*) A.Allocate<ListTy>();
1803771902e922796f506dfda5955d7d80b61104696Ted Kremenek      new (L) ListTy(Head, TailImpl);
1813a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
1823771902e922796f506dfda5955d7d80b61104696Ted Kremenek      // Insert the new list into the cache.
1833771902e922796f506dfda5955d7d80b61104696Ted Kremenek      Cache.InsertNode(L, InsertPos);
1843771902e922796f506dfda5955d7d80b61104696Ted Kremenek    }
1853a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
1863771902e922796f506dfda5955d7d80b61104696Ted Kremenek    return L;
1873771902e922796f506dfda5955d7d80b61104696Ted Kremenek  }
1883a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
1899c336fabd59fbdbe9129d76fbbee32261ac7c8f0Ted Kremenek  ImmutableList<T> add(const T& D, ImmutableList<T> L) {
1909c336fabd59fbdbe9129d76fbbee32261ac7c8f0Ted Kremenek    return concat(D, L);
1913771902e922796f506dfda5955d7d80b61104696Ted Kremenek  }
1923a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
1939c336fabd59fbdbe9129d76fbbee32261ac7c8f0Ted Kremenek  ImmutableList<T> getEmptyList() const {
1943771902e922796f506dfda5955d7d80b61104696Ted Kremenek    return ImmutableList<T>(0);
1953771902e922796f506dfda5955d7d80b61104696Ted Kremenek  }
1963a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
1979c336fabd59fbdbe9129d76fbbee32261ac7c8f0Ted Kremenek  ImmutableList<T> create(const T& X) {
1989c336fabd59fbdbe9129d76fbbee32261ac7c8f0Ted Kremenek    return Concat(X, getEmptyList());
1993771902e922796f506dfda5955d7d80b61104696Ted Kremenek  }
2003771902e922796f506dfda5955d7d80b61104696Ted Kremenek};
2013a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
2022c228834fc226619c25a678394bab73dd1b1f85dZhongxing Xu//===----------------------------------------------------------------------===//
203eca64f0980e3f686a36007c53272780119635337Ted Kremenek// Partially-specialized Traits.
2042c228834fc226619c25a678394bab73dd1b1f85dZhongxing Xu//===----------------------------------------------------------------------===//
2052c228834fc226619c25a678394bab73dd1b1f85dZhongxing Xu
206eca64f0980e3f686a36007c53272780119635337Ted Kremenektemplate<typename T> struct DenseMapInfo;
207eca64f0980e3f686a36007c53272780119635337Ted Kremenektemplate<typename T> struct DenseMapInfo<ImmutableList<T> > {
208eca64f0980e3f686a36007c53272780119635337Ted Kremenek  static inline ImmutableList<T> getEmptyKey() {
209eca64f0980e3f686a36007c53272780119635337Ted Kremenek    return reinterpret_cast<ImmutableListImpl<T>*>(-1);
210eca64f0980e3f686a36007c53272780119635337Ted Kremenek  }
211eca64f0980e3f686a36007c53272780119635337Ted Kremenek  static inline ImmutableList<T> getTombstoneKey() {
212eca64f0980e3f686a36007c53272780119635337Ted Kremenek    return reinterpret_cast<ImmutableListImpl<T>*>(-2);
213eca64f0980e3f686a36007c53272780119635337Ted Kremenek  }
214eca64f0980e3f686a36007c53272780119635337Ted Kremenek  static unsigned getHashValue(ImmutableList<T> X) {
215eca64f0980e3f686a36007c53272780119635337Ted Kremenek    uintptr_t PtrVal = reinterpret_cast<uintptr_t>(X.getInternalPointer());
2163a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman    return (unsigned((uintptr_t)PtrVal) >> 4) ^
217eca64f0980e3f686a36007c53272780119635337Ted Kremenek           (unsigned((uintptr_t)PtrVal) >> 9);
218eca64f0980e3f686a36007c53272780119635337Ted Kremenek  }
219eca64f0980e3f686a36007c53272780119635337Ted Kremenek  static bool isEqual(ImmutableList<T> X1, ImmutableList<T> X2) {
220eca64f0980e3f686a36007c53272780119635337Ted Kremenek    return X1 == X2;
221eca64f0980e3f686a36007c53272780119635337Ted Kremenek  }
222eca64f0980e3f686a36007c53272780119635337Ted Kremenek};
2233a54b3dc87a581c203b18050b4f787b4ca28a12cMisha Brukman
2244bbf4ee1491637c247e195e19e3e4a8ee5ad72faChris Lattnertemplate <typename T> struct isPodLike;
2254bbf4ee1491637c247e195e19e3e4a8ee5ad72faChris Lattnertemplate <typename T>
2264bbf4ee1491637c247e195e19e3e4a8ee5ad72faChris Lattnerstruct isPodLike<ImmutableList<T> > { static const bool value = true; };
2274bbf4ee1491637c247e195e19e3e4a8ee5ad72faChris Lattner
2283771902e922796f506dfda5955d7d80b61104696Ted Kremenek} // end llvm namespace
2293771902e922796f506dfda5955d7d80b61104696Ted Kremenek
2303771902e922796f506dfda5955d7d80b61104696Ted Kremenek#endif
231