diff --git a/llvm/lib/IR/ConstantFold.cpp b/llvm/lib/IR/ConstantFold.cpp
--- a/llvm/lib/IR/ConstantFold.cpp
+++ b/llvm/lib/IR/ConstantFold.cpp
@@ -352,11 +352,17 @@
 /// factors factored out. If Folded is false, return null if no factoring was
 /// possible, to avoid endlessly bouncing an unfoldable expression back into the
 /// top-level folder.
-static Constant *getFoldedSizeOf(Type *Ty, Type *DestTy, bool Folded) {
+static Constant *getFoldedSizeOf(Type *Ty, Type *DestTy, bool Folded,
+                                 DenseMap<Type *, Constant *> &Cache) {
+  // Check for previously generated folded size constant.
+  auto CacheIter = Cache.find(Ty);
+  if (CacheIter != Cache.end())
+    return CacheIter->second;
+
   if (ArrayType *ATy = dyn_cast<ArrayType>(Ty)) {
     Constant *N = ConstantInt::get(DestTy, ATy->getNumElements());
-    Constant *E = getFoldedSizeOf(ATy->getElementType(), DestTy, true);
-    return ConstantExpr::getNUWMul(E, N);
+    Constant *E = getFoldedSizeOf(ATy->getElementType(), DestTy, true, Cache);
+    return Cache[Ty] = ConstantExpr::getNUWMul(E, N);
   }
 
   if (StructType *STy = dyn_cast<StructType>(Ty))
@@ -364,20 +370,20 @@
       unsigned NumElems = STy->getNumElements();
       // An empty struct has size zero.
       if (NumElems == 0)
-        return ConstantExpr::getNullValue(DestTy);
+        return Cache[Ty] = ConstantExpr::getNullValue(DestTy);
       // Check for a struct with all members having the same size.
       Constant *MemberSize =
-        getFoldedSizeOf(STy->getElementType(0), DestTy, true);
+          getFoldedSizeOf(STy->getElementType(0), DestTy, true, Cache);
       bool AllSame = true;
       for (unsigned i = 1; i != NumElems; ++i)
         if (MemberSize !=
-            getFoldedSizeOf(STy->getElementType(i), DestTy, true)) {
+            getFoldedSizeOf(STy->getElementType(i), DestTy, true, Cache)) {
           AllSame = false;
           break;
         }
       if (AllSame) {
         Constant *N = ConstantInt::get(DestTy, NumElems);
-        return ConstantExpr::getNUWMul(MemberSize, N);
+        return Cache[Ty] = ConstantExpr::getNUWMul(MemberSize, N);
       }
     }
 
@@ -385,22 +391,27 @@
   // to an arbitrary pointee.
   if (PointerType *PTy = dyn_cast<PointerType>(Ty))
     if (!PTy->getElementType()->isIntegerTy(1))
-      return
-        getFoldedSizeOf(PointerType::get(IntegerType::get(PTy->getContext(), 1),
-                                         PTy->getAddressSpace()),
-                        DestTy, true);
+      return Cache[Ty] = getFoldedSizeOf(
+                 PointerType::get(IntegerType::get(PTy->getContext(), 1),
+                                  PTy->getAddressSpace()),
+                 DestTy, true, Cache);
 
   // If there's no interesting folding happening, bail so that we don't create
   // a constant that looks like it needs folding but really doesn't.
   if (!Folded)
-    return nullptr;
+    return Cache[Ty] = nullptr;
 
   // Base case: Get a regular sizeof expression.
   Constant *C = ConstantExpr::getSizeOf(Ty);
   C = ConstantExpr::getCast(CastInst::getCastOpcode(C, false,
                                                     DestTy, false),
                             C, DestTy);
-  return C;
+  return Cache[Ty] = C;
+}
+
+static Constant *getFoldedSizeOf(Type *Ty, Type *DestTy, bool Folded) {
+  DenseMap<Type *, Constant *> Cache;
+  return getFoldedSizeOf(Ty, DestTy, Folded, Cache);
 }
 
 /// Return a ConstantExpr with type DestTy for alignof on Ty, with any known
diff --git a/llvm/test/tools/llvm-as/slow-ptrtoint.ll b/llvm/test/tools/llvm-as/slow-ptrtoint.ll
new file mode 100644
--- /dev/null
+++ b/llvm/test/tools/llvm-as/slow-ptrtoint.ll
@@ -0,0 +1,30 @@
+; RUN: llvm-as %s -o - | llvm-dis -o - | FileCheck %s
+
+%0 = type { %1, %1, %1, %1, %1, %1, %1, %1 }
+%1 = type { %2, %2, %2, %2, %2, %2, %2, %2 }
+%2 = type { %3, %3, %3, %3, %3, %3, %3, %3 }
+%3 = type { %4, %4, %4, %4, %4, %4, %4, %4 }
+%4 = type { %5, %5, %5, %5, %5, %5, %5, %5 }
+%5 = type { %6, %6, %6, %6, %6, %6, %6, %6 }
+%6 = type { %7, %7, %7, %7, %7, %7, %7, %7 }
+%7 = type { %8, %8, %8, %8, %8, %8, %8, %8 }
+%8 = type { %9, %9, %9, %9, %9, %9, %9, %9 }
+%9 = type { %10, %10, %10, %10, %10, %10, %10, %10 }
+%10 = type { %11, %11, %11, %11, %11, %11, %11, %11 }
+%11 = type { %12, %12, %12, %12, %12, %12, %12, %12 }
+%12 = type { %13, %13, %13, %13, %13, %13, %13, %13 }
+%13 = type { i32, i32 }
+
+; it would take a naive recursive implementation ~4 days
+; to constant fold the size of %0
+define i64 @f_i64() {
+; CHECK-LABEL: @f_i64
+; CHECK:         ret i64 mul (i64 ptrtoint (i32* getelementptr (i32, i32* null, i32 1) to i64), i64 1099511627776)
+  ret i64 ptrtoint (%0* getelementptr (%0, %0* null, i32 1) to i64)
+}
+
+define i32 @f_i32() {
+; CHECK-LABEL: @f_i32
+; CHECK:         ret i32 mul (i32 ptrtoint (i32* getelementptr (i32, i32* null, i32 1) to i32), i32 -2147483648)
+  ret i32 ptrtoint (%3* getelementptr (%3, %3* null, i32 1) to i32)
+}