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 @@ -348,14 +348,22 @@ } } +/// Wrapper around getFoldedSizeOfImpl() that adds caching. +static Constant *getFoldedSizeOf(Type *Ty, Type *DestTy, bool Folded, + DenseMap &Cache); + /// Return a ConstantExpr with type DestTy for sizeof on Ty, with any known /// 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 *getFoldedSizeOfImpl(Type *Ty, Type *DestTy, bool Folded, + DenseMap &Cache) { + // This is the actual implementation of getFoldedSizeOf(). To get the caching + // behavior, we need to call getFoldedSizeOf() when we recurse. + if (ArrayType *ATy = dyn_cast(Ty)) { Constant *N = ConstantInt::get(DestTy, ATy->getNumElements()); - Constant *E = getFoldedSizeOf(ATy->getElementType(), DestTy, true); + Constant *E = getFoldedSizeOf(ATy->getElementType(), DestTy, true, Cache); return ConstantExpr::getNUWMul(E, N); } @@ -367,11 +375,11 @@ return 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; } @@ -385,10 +393,10 @@ // 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 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. @@ -403,6 +411,20 @@ return C; } +static Constant *getFoldedSizeOf(Type *Ty, Type *DestTy, bool Folded, + DenseMap &Cache) { + // Check for previously generated folded size constant. + auto It = Cache.find(Ty); + if (It != Cache.end()) + return It->second; + return Cache[Ty] = getFoldedSizeOfImpl(Ty, DestTy, Folded, Cache); +} + +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 /// factors factored out. If Folded is false, return null if no factoring was /// possible, to avoid endlessly bouncing an unfoldable expression back into the 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) +}