Index: llvm/include/llvm/Analysis/MemoryBuiltins.h =================================================================== --- llvm/include/llvm/Analysis/MemoryBuiltins.h +++ llvm/include/llvm/Analysis/MemoryBuiltins.h @@ -131,18 +131,15 @@ return const_cast(extractMallocCall((const Value *)I, GetTLI)); } -/// getMallocType - Returns the PointerType resulting from the malloc call. -/// The PointerType depends on the number of bitcast uses of the malloc call: -/// 0: PointerType is the malloc calls' return type. -/// 1: PointerType is the bitcast's result type. -/// >1: Unique PointerType cannot be determined, return NULL. +/// getMallocType - Returns the PointerType resulting from the malloc call. The +/// PointerType is the bitcast's result type of the call feeding into store. If +/// there is no bitcast feeding into store, the PointerType is the call's return +/// type. PointerType *getMallocType(const CallInst *CI, const TargetLibraryInfo *TLI); -/// getMallocAllocatedType - Returns the Type allocated by malloc call. -/// The Type depends on the number of bitcast uses of the malloc call: -/// 0: PointerType is the malloc calls' return type. -/// 1: PointerType is the bitcast's result type. -/// >1: Unique PointerType cannot be determined, return NULL. +/// getMallocAllocatedType - Returns the Type allocated by malloc call. The Type +/// is the bitcast's result type of the call feeding into store. If there is no +/// bitcast feeding into store, the Type is the call's return type. Type *getMallocAllocatedType(const CallInst *CI, const TargetLibraryInfo *TLI); /// getMallocArraySize - Returns the array size of a malloc call. If the Index: llvm/lib/Analysis/MemoryBuiltins.cpp =================================================================== --- llvm/lib/Analysis/MemoryBuiltins.cpp +++ llvm/lib/Analysis/MemoryBuiltins.cpp @@ -370,45 +370,43 @@ } /// getMallocType - Returns the PointerType resulting from the malloc call. -/// The PointerType depends on the number of bitcast uses of the malloc call: -/// 0: PointerType is the calls' return type. -/// 1: PointerType is the bitcast's result type. -/// >1: Unique PointerType cannot be determined, return NULL. +/// The PointerType is the bitcast's result type of the call feeding into store. +/// If there is no bitcast feeding into store, the PointerType is the call's +/// return type. PointerType *llvm::getMallocType(const CallInst *CI, const TargetLibraryInfo *TLI) { assert(isMallocLikeFn(CI, TLI) && "getMallocType and not malloc call"); - PointerType *MallocType = nullptr; - unsigned NumOfBitCastUses = 0; - - // Determine if CallInst has a bitcast use. - for (const User *U : CI->users()) - if (const BitCastInst *BCI = dyn_cast(U)) { - MallocType = cast(BCI->getDestTy()); - NumOfBitCastUses++; - } - - // Malloc call has 1 bitcast use, so type is the bitcast's destination type. - if (NumOfBitCastUses == 1) - return MallocType; + // Determine if CallInst has a bitcast feeding into store, either with value + // or pointer operand. The store is the only store for the malloc call. + for (const User *U : CI->users()) { + if (const BitCastInst *BCI = dyn_cast(U)) + if (any_of(BCI->uses(), [&](const Use &U) { + return isa(U.getUser()) && U.getOperandNo() == 0; + })) + return cast(BCI->getDestTy()); + + if (auto *ST = dyn_cast(U)) + if (ST->getValueOperand() == CI) + if (auto *BCO = dyn_cast(ST->getPointerOperand())) + if (auto *PTy = dyn_cast( + cast(BCO->getOperand(0)->getType()) + ->getElementType())) + return PTy; + } // Malloc call was not bitcast, so type is the malloc function's return type. - if (NumOfBitCastUses == 0) - return cast(CI->getType()); - - // Type could not be determined. - return nullptr; + return cast(CI->getType()); } -/// getMallocAllocatedType - Returns the Type allocated by malloc call. -/// The Type depends on the number of bitcast uses of the malloc call: -/// 0: PointerType is the malloc calls' return type. -/// 1: PointerType is the bitcast's result type. -/// >1: Unique PointerType cannot be determined, return NULL. +/// getMallocAllocatedType - Returns the Type allocated by malloc call. The Type +/// is the bitcast's result type of the call feeding into store. If there is no +/// bitcast feeding into store, the Type is the call's return type. Type *llvm::getMallocAllocatedType(const CallInst *CI, const TargetLibraryInfo *TLI) { PointerType *PT = getMallocType(CI, TLI); - return PT ? PT->getElementType() : nullptr; + assert(PT && "Expect non-null pointer type"); + return PT->getElementType(); } /// getMallocArraySize - Returns the array size of a malloc call. If the Index: llvm/lib/Transforms/IPO/GlobalOpt.cpp =================================================================== --- llvm/lib/Transforms/IPO/GlobalOpt.cpp +++ llvm/lib/Transforms/IPO/GlobalOpt.cpp @@ -1175,8 +1175,8 @@ } else if (CallInst *CI = extractMallocCall(StoredOnceVal, GetTLI)) { auto *TLI = &GetTLI(*CI->getFunction()); Type *MallocType = getMallocAllocatedType(CI, TLI); - if (MallocType && tryToOptimizeStoreOfMallocToGlobal(GV, CI, MallocType, - Ordering, DL, TLI)) + if (tryToOptimizeStoreOfMallocToGlobal(GV, CI, MallocType, Ordering, DL, + TLI)) return true; } } Index: llvm/test/Transforms/GlobalOpt/malloc-promote-5.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/GlobalOpt/malloc-promote-5.ll @@ -0,0 +1,38 @@ +; RUN: opt -globalopt -S < %s | FileCheck %s +; RUN: opt -passes=globalopt -S < %s | FileCheck %s + +@g = internal global i32* null, align 8 +; CHECK: [[G_BODY:@.*]] = internal unnamed_addr global i32 undef + +define signext i32 @f() { +; CHECK-LABEL: @f( +; CHECK-NEXT: entry: +; CHECK-NEXT: store i32 1, i32* [[G_BODY]], align 4 +; CHECK-NEXT: store i8 2, i8* bitcast (i32* [[G_BODY]] to i8*), align 4 +; CHECK-NEXT: ret i32 1 +; +entry: + %call = call i8* @malloc(i64 4) + store i8* %call, i8** bitcast (i32** @g to i8**), align 8 + %0 = load i32*, i32** @g, align 8 + store i32 1, i32* %0, align 4 + %1 = load i8*, i8** bitcast (i32** @g to i8**), align 8 + store i8 2, i8* %1, align 4 + ret i32 1 +} + +define signext i32 @main() { +; CHECK-LABEL: @main( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CALL:%.*]] = call signext i32 @f() +; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[G_BODY]], align 4 +; CHECK-NEXT: ret i32 [[TMP0]] +; +entry: + %call = call signext i32 @f() + %0 = load i32*, i32** @g, align 8 + %1 = load i32, i32* %0, align 4 + ret i32 %1 +} + +declare noalias align 16 i8* @malloc(i64)