ADDED   tools/clang/include/clang/AST/FunctionCache.h
Index: tools/clang/include/clang/AST/FunctionCache.h
==================================================================
--- tools/clang/include/clang/AST/FunctionCache.h
+++ tools/clang/include/clang/AST/FunctionCache.h
@@ -0,0 +1,206 @@
+//===----- FunctionCache.h - constexpr function call caching ----*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This provides a conservative cache for compile-time evaluated calls to
+// C++11 constexpr functions so that subsequent calls can pull the result
+// out of the cache rather than require a costly re-evaluation.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_FUNCTIONCACHE_H
+#define LLVM_CLANG_AST_FUNCTIONCACHE_H
+
+#include "clang/AST/APValue.h"
+#include "clang/AST/Decl.h"
+#include "clang/Basic/Diagnostic.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Compiler.h"
+
+namespace clang {
+class Expr;
+class Stmt;
+
+typedef SmallVector<APValue, 8> ArgVector;
+
+class FunctionCache {
+  /// \brief Key structure for cache DenseMap.
+  struct CacheKey {
+    private:
+    const FunctionDecl *Fn;
+    ArgVector Args;
+    unsigned Hash;
+
+    public:
+    CacheKey()
+      : Fn(0), Hash(0) { }
+
+    CacheKey(const FunctionDecl *Fn, const ArgVector &Args, unsigned Hash)
+      : Fn(Fn), Args(Args), Hash(Hash) { }
+
+    CacheKey(const CacheKey &RHS)
+      : Fn(RHS.Fn), Args(RHS.Args), Hash(RHS.Hash) { }
+
+    const CacheKey &operator=(const CacheKey &RHS) {
+      Fn = RHS.Fn; Args = RHS.Args; Hash = RHS.Hash;
+      return *this;
+    }
+
+#if LLVM_USE_RVALUE_REFERENCES
+    CacheKey(CacheKey &&RHS)
+      : Fn(RHS.Fn), Args(std::move(RHS.Args)), Hash(RHS.Hash) { }
+
+    const CacheKey &operator=(CacheKey &&RHS) {
+      Fn = RHS.Fn; Args = std::move(RHS.Args); Hash = RHS.Hash;
+      return *this;
+    }
+#endif
+
+    /// \brief Get an "empty marker" for use with DenseMap.
+    static CacheKey getEmptyKey() {
+      return CacheKey();
+    }
+
+    /// \brief Get a "tombstone marker" for use with DenseMap.
+    static CacheKey getTombstoneKey() {
+      return CacheKey((const FunctionDecl*)-1, ArgVector(), 0);
+    }
+
+    /// \brief Returns the hash value.
+    static unsigned getHashValue(const CacheKey &K) {
+      return K.Hash;
+    }
+
+    /// \brief Compares two FunctionCacheKey objects.
+    static bool isEqual(const CacheKey &A, const CacheKey &B);
+
+    size_t getArgsMemorySize() const {
+      size_t Total = Args.capacity_in_bytes() - Args.size_in_bytes();
+      for (unsigned I = 0, N = Args.size(); I != N; ++I)
+        Total += Args[I].getMemorySize();
+      return Total;
+    }
+
+    /// \brief Dump this entry, optionally with Result.
+    void dump(ASTContext &Ctx, ArrayRef<const Expr*> OrigArgs,
+              const APValue *Result) const;
+  };
+
+public:
+  struct CacheTable : llvm::DenseMap<CacheKey, APValue, CacheKey> {
+    private:
+    size_t StatsMem;
+
+    public:
+    CacheTable() : StatsMem(0) { }
+
+    void updateMemoryStats(const CacheKey &Key, const APValue &Val) {
+      StatsMem += Key.getArgsMemorySize();
+      // base size of APValue included in getMemoryStats already.
+      StatsMem += (Val.getMemorySize() - sizeof(APValue));
+    }
+
+    size_t getMemoryStats() const {
+      return sizeof(CacheTable) + getMemorySize() + StatsMem;
+    }
+  };
+
+private:
+  typedef std::pair<CacheKey, APValue> CacheLine;
+
+  typedef enum {
+    Invalid,          /// Invalid / unsupported cache entry.
+    OldEntry,         /// Previously saved entry found in cache.
+    NewEntry,         /// Newly created entry.
+    NewEntrySaved,    /// Newly created entry saved in cache.
+    NewEntryDiscarded /// Newly created entry discarded from cache.
+  } CacheLineState;
+
+  CacheLine CurrentEntry;
+  CacheLineState CurrentState;
+  CacheTable *CurrentCache_internal; // Use set/getCurrentCache(...) to access.
+
+  CacheTable *getCurrentCache(CacheTable *LocalCache) {
+    assert((CurrentCache_internal == LocalCache ||
+            CurrentCache_internal == &GlobalCache) && "CurrentCache invalid!");
+    return CurrentCache_internal;
+  }
+
+  void setCurrentCache(CacheTable *Value) {
+    assert(!CurrentCache_internal && "CurrentCache already assigned!");
+    CurrentCache_internal = Value;
+  }
+
+  static CacheTable GlobalCache;
+  static unsigned StatsHits, StatsCached;
+  static size_t StatsLocalCacheMaxMem;
+
+public:
+  FunctionCache()
+      : CurrentState(Invalid), CurrentCache_internal(0) { }
+
+  FunctionCache(const FunctionCache& RHS)
+      : CurrentEntry(RHS.CurrentEntry), CurrentState(RHS.CurrentState),
+        CurrentCache_internal(RHS.CurrentCache_internal) { }
+
+  // Assign by swapping from a copy.
+  FunctionCache& operator=(FunctionCache RHS) {
+    CurrentState = RHS.CurrentState;
+    CurrentEntry = llvm_move(RHS.CurrentEntry);
+    CurrentCache_internal = RHS.CurrentCache_internal;
+    RHS.CurrentState = Invalid;
+    return *this;
+  }
+
+  ~FunctionCache() {
+    // Either call setResult(...) or discard(...) before destructor!
+    assert((CurrentState != NewEntry) && "Invalid state!");
+  }
+
+  /// \brief Lookup matching entry in cache returning Result if found,
+  /// returning true on success.
+  static FunctionCache Create(CacheTable &LocalCache, const FunctionDecl *Fn,
+                              const Stmt *Body, const ArgVector &Args);
+
+  /// \brief Return cached result, if one is present, returning true on
+  /// success.
+  bool hasResult(APValue &Result) const {
+    if (CurrentState == OldEntry || CurrentState == NewEntrySaved) {
+      Result = CurrentEntry.second;
+      return true;
+    }
+    return false;
+  }
+
+  /// \brief Store result in cache (if cacheable), returning true on success.
+  bool setResult(CacheTable &LocalCache, const APValue &Result);
+
+  /// \brief Store result in cache (if cacheable), automatically discarding
+  /// on failure.
+  void setResultOrDiscard(CacheTable &LocalCache, const APValue &Result) {
+    if (!setResult(LocalCache, Result))
+      discard(LocalCache);
+  }
+
+  /// \brief Discard FunctionCache object (must be done if an evaluated result
+  /// is not stored in the cache).
+  void discard(CacheTable &LocalCache);
+
+  /// \brief Dump this entry, optionally with Result.
+  void dump(ASTContext &Ctx, ArrayRef<const Expr*> OrigArgs,
+            const APValue *Result = 0) const {
+    CurrentEntry.first.dump(Ctx, OrigArgs, Result);
+  }
+};
+
+} // end namespace clang
+
+#endif /* LLVM_CLANG_AST_FUNCTIONCACHE_H */

Index: tools/clang/lib/AST/CMakeLists.txt
==================================================================
--- tools/clang/lib/AST/CMakeLists.txt
+++ tools/clang/lib/AST/CMakeLists.txt
@@ -28,10 +28,11 @@
   Expr.cpp
   ExprClassification.cpp
   ExprConstant.cpp
   ExprCXX.cpp
   ExternalASTSource.cpp
+  FunctionCache.cpp
   InheritViz.cpp
   ItaniumCXXABI.cpp
   ItaniumMangle.cpp
   LambdaMangleContext.cpp
   Mangle.cpp

ADDED   tools/clang/lib/AST/FunctionCache.cpp
Index: tools/clang/lib/AST/FunctionCache.cpp
==================================================================
--- tools/clang/lib/AST/FunctionCache.cpp
+++ tools/clang/lib/AST/FunctionCache.cpp
@@ -0,0 +1,566 @@
+//===---- FunctionCache.cpp - constexpr function call caching ---*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This provides a conservative cache for compile-time evaluated calls to
+// C++11 constexpr functions so that subsequent calls can pull the result
+// out of the cache rather than require a costly re-evaluation.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTDiagnostic.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/FunctionCache.h"
+
+using namespace clang;
+
+FunctionCache::CacheTable FunctionCache::GlobalCache;
+unsigned FunctionCache::StatsHits = 0;
+unsigned FunctionCache::StatsCached = 0;
+size_t FunctionCache::StatsLocalCacheMaxMem = 0;
+
+static inline unsigned GetPathLength(const APValue &Val) {
+  return Val.hasLValuePath() ? Val.getLValuePath().size() : 0;
+}
+
+enum SupportType {
+  Unsupported = 1,
+  Supported   = 2,
+  SupportedIfLocalCache = 4 | Supported
+};
+
+/// \brief Determine whether an APValue may be considered in a constexpr
+/// evaluation cache, which may depend on whether the APValue is an argument
+/// to a function or its returned value.
+static SupportType IsSupported(const APValue& Value, bool isArg) {
+  // Gauge support level depending on APValue kind: simple kinds return
+  // directly but composite kinds (e.g. arrays, structs) recursively call
+  // IsSupported on each sub-element, accumulating the support level,
+  // which is then decoded at the end.
+  int S = 0;
+  switch (Value.getKind()) {
+    case APValue::Uninitialized:
+      return Unsupported;
+
+    case APValue::Int:
+    case APValue::Float:
+    case APValue::ComplexInt:
+    case APValue::ComplexFloat:
+      return Supported;
+
+    case APValue::LValue:
+      if (!isArg)
+        return Unsupported;
+      if (Value.getLValueCallIndex() != 0)
+        return SupportedIfLocalCache;
+      return Supported;
+
+    case APValue::Vector:
+      for (unsigned I = 0, Len = Value.getVectorLength();
+             I != Len && !(S & Unsupported); ++I) {
+        S |= IsSupported(Value.getVectorElt(I), isArg);
+      }
+      break;
+
+    case APValue::Array:
+      if (Value.hasArrayFiller())
+        S |= IsSupported(Value.getArrayFiller(), isArg);
+      for (unsigned I = 0, Len = Value.getArrayInitializedElts();
+             I != Len && !(S & Unsupported); ++I) {
+        S |= IsSupported(Value.getArrayInitializedElt(I), isArg);
+      }
+      break;
+
+    case APValue::Struct:
+      for (unsigned I = 0, Len = Value.getStructNumBases();
+             I != Len && !(S & Unsupported); ++I) {
+        S |= IsSupported(Value.getStructBase(I), isArg);
+      }
+      for (unsigned I = 0, Len = Value.getStructNumFields();
+             I != Len && !(S & Unsupported); ++I) {
+        S |= IsSupported(Value.getStructField(I), isArg);
+      }
+      break;
+
+    default:
+      // FIXME: support more kinds?
+      return Unsupported;
+  }
+
+  // Decode the correct support level from the accumulated value.
+  switch (S) {
+    case 0:
+    case Supported:
+      return Supported;
+
+    case SupportedIfLocalCache:
+      return SupportedIfLocalCache;
+
+    default:
+      return Unsupported;
+  }
+}
+
+/// \brief Conservatively determine whether two APValues can be considered
+/// equal to each other.
+static bool IsAPValueEqual(const APValue &A, const APValue &B) {
+  if (A.getKind() != B.getKind())
+    return false;
+
+  switch (A.getKind()) {
+    case APValue::Uninitialized:
+      return true;
+
+    case APValue::Int:
+      return (A.getInt() == B.getInt());
+
+    case APValue::Float:
+      // Using the conservative 'bitwiseIsEqual' function so that 0 != -0.
+      return A.getFloat().bitwiseIsEqual(B.getFloat());
+
+    case APValue::ComplexInt:
+      return (A.getComplexIntReal() == B.getComplexIntReal()) &&
+             (A.getComplexIntImag() == B.getComplexIntImag());
+
+    case APValue::ComplexFloat:
+      return A.getComplexFloatReal().bitwiseIsEqual(B.getComplexFloatReal()) &&
+             A.getComplexFloatImag().bitwiseIsEqual(B.getComplexFloatImag());
+
+    case APValue::Vector: {
+      unsigned len = A.getVectorLength();
+      if (len != B.getVectorLength()) return false;
+      for (unsigned i = 0; i != len; ++i) {
+        if (!IsAPValueEqual(A.getVectorElt(i), B.getVectorElt(i)))
+          return false;
+      }
+      return true;
+    }
+
+    case APValue::Array: {
+      unsigned len = A.getArraySize();
+      if (len != B.getArraySize()) return false;
+
+      APValue FillerA, FillerB;
+      if (A.hasArrayFiller()) FillerA = A.getArrayFiller();
+      if (B.hasArrayFiller()) FillerB = B.getArrayFiller();
+
+      // Two arrays are equal if their initialised elements are equal,
+      // but also where one array is more initialised than another, where
+      // those additional initialised elements are equal to the filler
+      // of the other.  If they both contain uninitialised elements, the
+      // fillers must also match.
+      for (unsigned i = 0, a = A.getArrayInitializedElts(),
+                           b = B.getArrayInitializedElts(); i != len; ++i) {
+        if (!IsAPValueEqual(
+              (i < a) ? A.getArrayInitializedElt(i) : FillerA,
+              (i < b) ? B.getArrayInitializedElt(i) : FillerB))
+          return false;
+        // If all the initialised elements *and* the fillers have been
+        // compared, then its equal!
+        if (i >= a && i >= b)
+          break;
+      }
+      return true;
+    }
+
+    case APValue::Struct: {
+      unsigned bases = A.getStructNumBases();
+      if (bases != B.getStructNumBases())
+        return false;
+
+      unsigned fields = A.getStructNumFields();
+      if (fields != B.getStructNumFields())
+        return false;
+
+      for (unsigned i = 0; i != bases; ++i) {
+        if (!IsAPValueEqual(A.getStructBase(i), B.getStructBase(i)))
+          return false;
+      }
+
+      for (unsigned i = 0; i != fields; ++i) {
+        if (!IsAPValueEqual(A.getStructField(i), B.getStructField(i)))
+          return false;
+      }
+
+      return true;
+    }
+
+    case APValue::Union:
+      return (A.getUnionField() == B.getUnionField()) &&
+             (IsAPValueEqual(A.getUnionValue(), B.getUnionValue()));
+
+    case APValue::AddrLabelDiff:
+      return (A.getAddrLabelDiffLHS() == B.getAddrLabelDiffLHS()) &&
+             (A.getAddrLabelDiffRHS() == B.getAddrLabelDiffRHS());
+
+    case APValue::LValue: {
+      APValue::LValueBase BaseA = A.getLValueBase();
+      APValue::LValueBase BaseB = B.getLValueBase();
+
+      // Simple comparison checks.
+      if ((A.getLValueOffset()       != B.getLValueOffset())       ||
+          (A.isLValueOnePastTheEnd() != B.isLValueOnePastTheEnd()) ||
+          (A.getLValueCallIndex()    != B.getLValueCallIndex())    ||
+          (BaseA.isNull()            != BaseB.isNull()))
+        return false;
+
+      unsigned PathLength = GetPathLength(A);
+      if (PathLength != GetPathLength(B))
+        return false;
+
+      // Check whether A and B are equal rather than identical. This
+      // is only supported for a few common expression types where it
+      // is both *safe* and worthwhile to do so.
+      const Expr *ExprA = BaseA.dyn_cast<const Expr*>();
+      const Expr *ExprB = BaseB.dyn_cast<const Expr*>();
+
+      if (!ExprA || !ExprB) {
+        // One or more base is not an Expr.  It was not possible to check
+        // for equality, therefore check that both LValues are identical.
+        if (BaseA.getOpaqueValue() != BaseB.getOpaqueValue())
+          return false;
+      } else {
+        // Check the two bases have matching types.
+        if (ExprA->getStmtClass() != ExprB->getStmtClass())
+          return false;
+
+        // Check for equality.
+        switch (ExprA->getStmtClass()) {
+          case Expr::StringLiteralClass: {
+            assert(PathLength < 2 &&
+                     "Unexpected path length for StringLiteral");
+            const StringLiteral *SA = cast<StringLiteral>(ExprA);
+            const StringLiteral *SB = cast<StringLiteral>(ExprB);
+
+            if (SA->getLength()        != SB->getLength()        ||
+                SA->getCharByteWidth() != SB->getCharByteWidth() ||
+                SA->getBytes()         != SB->getBytes())
+              return false;
+            break;
+          }
+
+          case Expr::ObjCStringLiteralClass: {
+            assert(PathLength < 2 &&
+                     "Unexpected path length for ObjCStringLiteral");
+            const StringLiteral *SA =
+              cast<ObjCStringLiteral>(ExprA)->getString();
+            const StringLiteral *SB =
+              cast<ObjCStringLiteral>(ExprB)->getString();
+
+            if (SA->getLength()        != SB->getLength()        ||
+                SA->getCharByteWidth() != SB->getCharByteWidth() ||
+                SA->getBytes()         != SB->getBytes())
+              return false;
+            break;
+          }
+
+          default:
+            // It was not possible to check for equality, therefore
+            // check that both LValues are identical.
+            if (BaseA.getOpaqueValue() != BaseB.getOpaqueValue())
+              return false;
+            break;
+        }
+      }
+
+      if (PathLength > 0) {
+        ArrayRef<APValue::LValuePathEntry> PathA = A.getLValuePath();
+        ArrayRef<APValue::LValuePathEntry> PathB = B.getLValuePath();
+        for (unsigned I = 0; I != PathLength; ++I) {
+          if ((PathA[I].BaseOrMember != PathB[I].BaseOrMember) ||
+              (PathA[I].ArrayIndex   != PathB[I].ArrayIndex))
+            return false;
+        }
+      }
+
+      return true;
+    }
+
+    case APValue::MemberPointer:
+      llvm_unreachable("isAPValueEqual unimplemented for this APValue kind!");
+      return false;
+  }
+
+  llvm_unreachable("Unknown APValue kind!");
+  return false;
+}
+
+/// \brief Calculate a hash for an APValue.
+static llvm::hash_code CalculateHash(const APValue &Val) {
+  using namespace llvm;
+  hash_code ret = hash_value(Val.getKind());
+  switch (Val.getKind()) {
+    case APValue::Uninitialized:
+      return ret;
+
+    case APValue::Int:
+      return hash_combine(ret, Val.getInt());
+
+    case APValue::Float:
+      return hash_combine(ret, Val.getFloat());
+
+    case APValue::ComplexInt:
+      return hash_combine(ret, Val.getComplexIntReal(),
+                               Val.getComplexIntImag());
+
+    case APValue::ComplexFloat:
+      return hash_combine(ret, Val.getComplexFloatReal(),
+                               Val.getComplexFloatImag());
+
+    case APValue::Vector: {
+      unsigned len = Val.getVectorLength();
+      ret = hash_combine(ret, len);
+      for (unsigned i = 0; i != len; ++i)
+        ret = hash_combine(ret, CalculateHash(Val.getVectorElt(i)));
+      return ret;
+    }
+
+    case APValue::Array: {
+      unsigned len = Val.getArraySize();
+      ret = hash_combine(ret, len);
+      unsigned i = 0;
+      for (unsigned l = Val.getArrayInitializedElts(); i != l; ++i)
+        ret = hash_combine(ret, CalculateHash(Val.getArrayInitializedElt(i)));
+      if (Val.hasArrayFiller()) {
+        llvm::hash_code Filler = CalculateHash(Val.getArrayFiller());
+        for (; i != len; ++i)
+          ret = hash_combine(ret, Filler);
+      }
+      return ret;
+    }
+
+    case APValue::Struct: {
+      unsigned bases = Val.getStructNumBases();
+      unsigned fields = Val.getStructNumFields();
+      ret = hash_combine(ret, bases, fields);
+      for (unsigned i = 0; i != bases; ++i)
+        ret = hash_combine(ret, CalculateHash(Val.getStructBase(i)));
+      for (unsigned i = 0; i != fields; ++i)
+        ret = hash_combine(ret, CalculateHash(Val.getStructField(i)));
+      return ret;
+    }
+
+    case APValue::Union:
+      return hash_combine(ret, Val.getUnionField(),
+                          CalculateHash(Val.getUnionValue()));
+
+    case APValue::AddrLabelDiff:
+      return hash_combine(ret, Val.getAddrLabelDiffLHS(),
+                               Val.getAddrLabelDiffRHS());
+
+    case APValue::LValue: {
+      APValue::LValueBase Base = Val.getLValueBase();
+      ret = hash_combine(ret, Val.getLValueOffset().getQuantity(),
+                              Val.isLValueOnePastTheEnd(),
+                              Val.getLValueCallIndex());
+
+      unsigned PathLength = GetPathLength(Val);
+      if (const Expr *E = Base.dyn_cast<const Expr*>()) {
+        switch (E->getStmtClass()) {
+          case Expr::StringLiteralClass: {
+            assert(PathLength < 2 &&
+                     "Unexpected path length for StringLiteral");
+            ret = hash_combine(ret, cast<StringLiteral>(E)->getBytes());
+            break;
+          }
+
+          case Expr::ObjCStringLiteralClass: {
+            assert(PathLength < 2 &&
+                     "Unexpected path length for ObjCStringLiteral");
+            ret =
+              hash_combine(ret,
+                           cast<ObjCStringLiteral>(E)->getString()->getBytes());
+            break;
+          }
+
+          default:
+            ret = hash_combine(ret, Base.getOpaqueValue());
+            break;
+        }
+      } else {
+        ret = hash_combine(ret, Base.getOpaqueValue());
+      }
+
+      if (PathLength > 0) {
+        ArrayRef<APValue::LValuePathEntry> Path = Val.getLValuePath();
+        ret = hash_combine(ret, PathLength);
+        for (unsigned I = 0; I != PathLength; ++I)
+          ret = hash_combine(ret, Path[I].BaseOrMember, Path[I].ArrayIndex);
+      }
+      return ret;
+    }
+
+    case APValue::MemberPointer:
+      llvm_unreachable("hash_value unimplemented for this APValue kind!");
+      return 0;
+  }
+
+  llvm_unreachable("Unknown APValue kind!");
+  return 0;
+}
+
+bool FunctionCache::CacheKey::isEqual(const FunctionCache::CacheKey &A,
+                                      const FunctionCache::CacheKey &B) {
+  if (A.Hash != B.Hash || A.Fn != B.Fn || A.Args.size() != B.Args.size())
+    return false;
+  for (ArgVector::const_iterator I = A.Args.begin(),
+                                 J = B.Args.begin(),
+                               End = A.Args.end(); I != End; ++I, ++J) {
+    if (!IsAPValueEqual(*I, *J)) return false;
+  }
+  return true;
+}
+
+FunctionCache FunctionCache::Create(CacheTable &LocalCache,
+                                    const FunctionDecl *Fn,
+                                    const Stmt *Body,
+                                    const ArgVector &Args) {
+  assert(Fn && "Function declaration must be provided!");
+  assert(Fn->getBody() == Body && "Body doesn't match function declaration!");
+
+  FunctionCache Ret;
+
+  // Calculate hash value.
+  llvm::hash_code Hash = llvm::hash_value(Fn);
+  bool UseLocalCache = false;
+  for (ArgVector::const_iterator I = Args.begin(),
+                                 End = Args.end(); I != End; ++I) {
+    switch (IsSupported(*I, true)) {
+      case Unsupported:
+        Ret.CurrentState = Invalid;
+        return Ret;
+
+      case SupportedIfLocalCache:
+        UseLocalCache = true;
+        break;
+
+      case Supported:
+        break;
+    }
+    Hash = llvm::hash_combine(Hash, ::CalculateHash(*I));
+  }
+
+  CacheTable *CacheInUse = UseLocalCache ? &LocalCache : &GlobalCache;
+  Ret.CurrentEntry = std::make_pair(CacheKey(Fn, Args, Hash), APValue());
+  Ret.setCurrentCache(CacheInUse);
+
+  // Insert or find entry in cache.
+  bool Inserted;
+  CacheTable::iterator Item;
+  tie(Item, Inserted) = CacheInUse->insert(Ret.CurrentEntry);
+
+  if (Inserted) {
+    // Returns true on successful insert (i.e. key not found).
+    Ret.CurrentState = NewEntry;
+  } else {
+    // Otherwise, cached value already exists.
+    Ret.CurrentState = OldEntry;
+    Ret.CurrentEntry = llvm_move(*Item);
+
+    // An "Uninitialized" result occurs where a cyclic dependency exists,
+    // so don't update the hits counter.
+    if (Ret.CurrentEntry.second.getKind() != APValue::Uninitialized)
+      ++StatsHits;
+  }
+
+  return Ret;
+}
+
+bool FunctionCache::setResult(CacheTable &LocalCache, const APValue &Result) {
+  if (CurrentState == Invalid)
+    return false;
+
+  assert(CurrentState == NewEntry && "Invalid state!");
+
+  CacheTable *CacheInUse = getCurrentCache(&LocalCache);
+  bool IsUsingLocalCache = (CacheInUse == &LocalCache);
+
+  // Is it valid to cache this Result?
+  switch (IsSupported(Result, false)) {
+    case Unsupported:
+      return false;
+
+    case Supported:
+      break;
+
+    case SupportedIfLocalCache:
+      // FIXME: consider move from global to local cache rather than fail?
+      // At the moment, this possibility will not occur since LValues are
+      // only supported as arguments presently, so the correct cache will
+      // already be chosen.
+      if (!IsUsingLocalCache)
+        return false;
+      break;
+  }
+
+  // Find item in cache so that Result can be saved.
+  CacheTable::iterator Item = CacheInUse->find(CurrentEntry.first);
+  if (Item == CacheInUse->end()) {
+    llvm_unreachable("State invalid? Entry not created.");
+    return false;
+  }
+
+  APValue &CachedValue = Item->second;
+  if (CachedValue.getKind() != APValue::Uninitialized)
+    llvm_unreachable("State invalid? Already set.");
+
+  // Update memory statistics.
+  ++StatsCached;
+  CacheInUse->updateMemoryStats(CurrentEntry.first, Result);
+  if (IsUsingLocalCache) {
+    StatsLocalCacheMaxMem = std::max(StatsLocalCacheMaxMem,
+                                     CacheInUse->getMemoryStats());
+  }
+
+  CachedValue = Result;         // Store in cache.
+  CurrentEntry.second = Result; // Hold locally for HasResult(...).
+  CurrentState = NewEntrySaved;
+  return true;
+}
+
+void FunctionCache::discard(CacheTable &LocalCache) {
+  if (CurrentState != Invalid) {
+    assert(CurrentState == NewEntry && "Invalid state!");
+
+    getCurrentCache(&LocalCache)->erase(CurrentEntry.first);
+    CurrentState = NewEntryDiscarded;
+  }
+}
+
+void FunctionCache::CacheKey::dump(ASTContext &Ctx,
+                                   ArrayRef<const Expr*> OrigArgs,
+                                   const APValue *Result) const {
+  switch ((intptr_t)Fn) {
+    case 0:  llvm::errs() << "Empty\n"; return;
+    case -1: llvm::errs() << "Tombstone\n"; return;
+    default: break;
+  }
+
+  llvm::errs() << '[' << Hash << "] ";
+  Fn->dump();
+  if (Args.size() > 0) {
+    int i = 0;
+    for (ArgVector::const_iterator I = Args.begin(),
+                                 End = Args.end(); I != End; ++I, ++i) {
+      llvm::errs() << "[[arg " << (i+1) << "]] ";
+      I->dump();
+      llvm::errs() << "=> ";
+      I->printPretty(llvm::errs(), Ctx, OrigArgs[i]->getType());
+      llvm::errs() << " ::: ";
+      OrigArgs[i]->dumpPretty(Ctx);
+      llvm::errs() << '\n';
+    }
+  }
+  if (Result) {
+    llvm::errs() << "[[result]] ";
+    Result->dump();
+  }
+  llvm::errs() << '\n';
+}

