From 264da3274e9e20eb3c6e04bc33c07f87e85b2156 Mon Sep 17 00:00:00 2001 From: Victor Hernandez Date: Fri, 16 Oct 2009 23:12:25 +0000 Subject: [PATCH] HeapAllocSRoA also needs to check if malloc array size can be computed. llvm-svn: 84288 --- llvm/lib/Transforms/IPO/GlobalOpt.cpp | 70 ++++++++++--------- .../2009-11-16-BrokenPerformHeapAllocSRoA.ll | 26 +++++++ 2 files changed, 63 insertions(+), 33 deletions(-) create mode 100644 llvm/test/Transforms/GlobalOpt/2009-11-16-BrokenPerformHeapAllocSRoA.ll diff --git a/llvm/lib/Transforms/IPO/GlobalOpt.cpp b/llvm/lib/Transforms/IPO/GlobalOpt.cpp index 0d9818fdfa73..3d10649c95bd 100644 --- a/llvm/lib/Transforms/IPO/GlobalOpt.cpp +++ b/llvm/lib/Transforms/IPO/GlobalOpt.cpp @@ -1586,6 +1586,8 @@ static GlobalVariable *PerformHeapAllocSRoA(GlobalVariable *GV, << " BITCAST = " << *BCI << '\n'); const Type* MAT = getMallocAllocatedType(CI); const StructType *STy = cast(MAT); + Value* ArraySize = getMallocArraySize(CI, Context, TD); + assert(ArraySize && "not a malloc whose array size can be determined"); // There is guaranteed to be at least one use of the malloc (storing // it into GV). If there are other uses, change them to be uses of @@ -1610,8 +1612,8 @@ static GlobalVariable *PerformHeapAllocSRoA(GlobalVariable *GV, GV->isThreadLocal()); FieldGlobals.push_back(NGV); - Value *NMI = CallInst::CreateMalloc(CI, TD->getIntPtrType(Context), FieldTy, - getMallocArraySize(CI, Context, TD), + Value *NMI = CallInst::CreateMalloc(CI, TD->getIntPtrType(Context), + FieldTy, ArraySize, BCI->getName() + ".f" + Twine(FieldNo)); FieldMallocs.push_back(NMI); new StoreInst(NMI, NGV, BCI); @@ -1892,6 +1894,7 @@ static bool TryToOptimizeStoreOfMallocToGlobal(GlobalVariable *GV, // This eliminates dynamic allocation, avoids an indirection accessing the // data, and exposes the resultant global to further GlobalOpt. Value *NElems = getMallocArraySize(CI, Context, TD); + // We cannot optimize the malloc if we cannot determine malloc array size. if (NElems) { if (ConstantInt *NElements = dyn_cast(NElems)) // Restrict this transformation to only working on small allocations @@ -1902,42 +1905,43 @@ static bool TryToOptimizeStoreOfMallocToGlobal(GlobalVariable *GV, GVI = OptimizeGlobalAddressOfMalloc(GV, CI, BCI, Context, TD); return true; } - } - // If the allocation is an array of structures, consider transforming this - // into multiple malloc'd arrays, one for each field. This is basically - // SRoA for malloc'd memory. + // If the allocation is an array of structures, consider transforming this + // into multiple malloc'd arrays, one for each field. This is basically + // SRoA for malloc'd memory. - // If this is an allocation of a fixed size array of structs, analyze as a - // variable size array. malloc [100 x struct],1 -> malloc struct, 100 - if (!isArrayMalloc(CI, Context, TD)) - if (const ArrayType *AT = dyn_cast(AllocTy)) - AllocTy = AT->getElementType(); + // If this is an allocation of a fixed size array of structs, analyze as a + // variable size array. malloc [100 x struct],1 -> malloc struct, 100 + if (!isArrayMalloc(CI, Context, TD)) + if (const ArrayType *AT = dyn_cast(AllocTy)) + AllocTy = AT->getElementType(); - if (const StructType *AllocSTy = dyn_cast(AllocTy)) { - // This the structure has an unreasonable number of fields, leave it - // alone. - if (AllocSTy->getNumElements() <= 16 && AllocSTy->getNumElements() != 0 && - AllGlobalLoadUsesSimpleEnoughForHeapSRA(GV, BCI)) { + if (const StructType *AllocSTy = dyn_cast(AllocTy)) { + // This the structure has an unreasonable number of fields, leave it + // alone. + if (AllocSTy->getNumElements() <= 16 && AllocSTy->getNumElements() != 0 && + AllGlobalLoadUsesSimpleEnoughForHeapSRA(GV, BCI)) { - // If this is a fixed size array, transform the Malloc to be an alloc of - // structs. malloc [100 x struct],1 -> malloc struct, 100 - if (const ArrayType *AT = dyn_cast(getMallocAllocatedType(CI))) { - Value* NumElements = ConstantInt::get(Type::getInt32Ty(Context), - AT->getNumElements()); - Value* NewMI = CallInst::CreateMalloc(CI, TD->getIntPtrType(Context), - AllocSTy, NumElements, - BCI->getName()); - Value *Cast = new BitCastInst(NewMI, getMallocType(CI), "tmp", CI); - BCI->replaceAllUsesWith(Cast); - BCI->eraseFromParent(); - CI->eraseFromParent(); - BCI = cast(NewMI); - CI = extractMallocCallFromBitCast(NewMI); - } + // If this is a fixed size array, transform the Malloc to be an alloc of + // structs. malloc [100 x struct],1 -> malloc struct, 100 + if (const ArrayType *AT = + dyn_cast(getMallocAllocatedType(CI))) { + Value* NumElements = ConstantInt::get(Type::getInt32Ty(Context), + AT->getNumElements()); + Value* NewMI = CallInst::CreateMalloc(CI, TD->getIntPtrType(Context), + AllocSTy, NumElements, + BCI->getName()); + Value *Cast = new BitCastInst(NewMI, getMallocType(CI), "tmp", CI); + BCI->replaceAllUsesWith(Cast); + BCI->eraseFromParent(); + CI->eraseFromParent(); + BCI = cast(NewMI); + CI = extractMallocCallFromBitCast(NewMI); + } - GVI = PerformHeapAllocSRoA(GV, CI, BCI, Context, TD); - return true; + GVI = PerformHeapAllocSRoA(GV, CI, BCI, Context, TD); + return true; + } } } diff --git a/llvm/test/Transforms/GlobalOpt/2009-11-16-BrokenPerformHeapAllocSRoA.ll b/llvm/test/Transforms/GlobalOpt/2009-11-16-BrokenPerformHeapAllocSRoA.ll new file mode 100644 index 000000000000..54e8f9097906 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/2009-11-16-BrokenPerformHeapAllocSRoA.ll @@ -0,0 +1,26 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" +target triple = "x86_64-apple-darwin10.0" + +%struct.hashheader = type { i16, i16, i16, i16, i16, i16, i32, i32, i32, i32, i32, i32, i32, i32, i32, [5 x i8], [13 x i8], i8, i8, i8, [228 x i16], [228 x i8], [228 x i8], [228 x i8], [228 x i8], [228 x i8], [228 x i8], [128 x i8], [100 x [11 x i8]], [100 x i32], [100 x i32], i16 } +%struct.strchartype = type { i8*, i8*, i8* } + +@hashheader = internal global %struct.hashheader zeroinitializer, align 32 ; <%struct.hashheader*> [#uses=1] +@chartypes = internal global %struct.strchartype* null ; <%struct.strchartype**> [#uses=1] +; CHECK-NOT: @hashheader +; CHECK-NOT: @chartypes + +; based on linit in office-ispell +define void @test() nounwind ssp { + %1 = load i32* getelementptr inbounds (%struct.hashheader* @hashheader, i64 0, i32 13), align 8 ; [#uses=1] + %2 = sext i32 %1 to i64 ; [#uses=1] + %3 = mul i64 %2, ptrtoint (%struct.strchartype* getelementptr (%struct.strchartype* null, i64 1) to i64) ; [#uses=1] + %4 = tail call i8* @malloc(i64 %3) ; [#uses=1] +; CHECK: call i8* @malloc(i64 + %5 = bitcast i8* %4 to %struct.strchartype* ; <%struct.strchartype*> [#uses=1] + store %struct.strchartype* %5, %struct.strchartype** @chartypes, align 8 + ret void +} + +declare noalias i8* @malloc(i64)