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,16 @@ /// 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 &Cache) { + // Check for previously generated folded size constant. + if (Cache.find(Ty) != Cache.end()) + return Cache[Ty]; + if (ArrayType *ATy = dyn_cast(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(Ty)) @@ -364,20 +369,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 +390,27 @@ // to an arbitrary pointee. if (PointerType *PTy = dyn_cast(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 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) +}