diff options
| -rw-r--r-- | llvm/lib/Transforms/Scalar/InstructionCombining.cpp | 66 | ||||
| -rw-r--r-- | llvm/test/Transforms/InstCombine/cast-store-gep.ll | 17 | 
2 files changed, 65 insertions, 18 deletions
diff --git a/llvm/lib/Transforms/Scalar/InstructionCombining.cpp b/llvm/lib/Transforms/Scalar/InstructionCombining.cpp index 8b20453a0e4..dd55d65e163 100644 --- a/llvm/lib/Transforms/Scalar/InstructionCombining.cpp +++ b/llvm/lib/Transforms/Scalar/InstructionCombining.cpp @@ -7700,12 +7700,12 @@ Instruction *InstCombiner::commonCastTransforms(CastInst &CI) {  /// FindElementAtOffset - Given a type and a constant offset, determine whether  /// or not there is a sequence of GEP indices into the type that will land us at -/// the specified offset.  If so, fill them into NewIndices and return true, -/// otherwise return false. -static bool FindElementAtOffset(const Type *Ty, int64_t Offset,  -                                SmallVectorImpl<Value*> &NewIndices, -                                const TargetData *TD) { -  if (!Ty->isSized()) return false; +/// the specified offset.  If so, fill them into NewIndices and return the +/// resultant element type, otherwise return null. +static const Type *FindElementAtOffset(const Type *Ty, int64_t Offset,  +                                       SmallVectorImpl<Value*> &NewIndices, +                                       const TargetData *TD) { +  if (!Ty->isSized()) return 0;    // Start with the index over the outer type.  Note that the type size    // might be zero (even if the offset isn't zero) if the indexed type @@ -7731,7 +7731,7 @@ static bool FindElementAtOffset(const Type *Ty, int64_t Offset,    while (Offset) {      // Indexing into tail padding between struct/array elements.      if (uint64_t(Offset*8) >= TD->getTypeSizeInBits(Ty)) -      return false; +      return 0;      if (const StructType *STy = dyn_cast<StructType>(Ty)) {        const StructLayout *SL = TD->getStructLayout(STy); @@ -7751,11 +7751,11 @@ static bool FindElementAtOffset(const Type *Ty, int64_t Offset,        Ty = AT->getElementType();      } else {        // Otherwise, we can't index into the middle of this atomic type, bail. -      return false; +      return 0;      }    } -  return true; +  return Ty;  }  /// @brief Implement the transforms for cast of pointer (bitcast/ptrtoint) @@ -11139,7 +11139,8 @@ Instruction *InstCombiner::visitLoadInst(LoadInst &LI) {  }  /// InstCombineStoreToCast - Fold store V, (cast P) -> store (cast V), P -/// when possible. +/// when possible.  This makes it generally easy to do alias analysis and/or +/// SROA/mem2reg of the memory object.  static Instruction *InstCombineStoreToCast(InstCombiner &IC, StoreInst &SI) {    User *CI = cast<User>(SI.getOperand(1));    Value *CastOp = CI->getOperand(0); @@ -11153,18 +11154,34 @@ static Instruction *InstCombineStoreToCast(InstCombiner &IC, StoreInst &SI) {    if (!DestPTy->isInteger() && !isa<PointerType>(DestPTy))      return 0; +  /// NewGEPIndices - If SrcPTy is an aggregate type, we can emit a "noop gep" +  /// to its first element.  This allows us to handle things like: +  ///   store i32 xxx, (bitcast {foo*, float}* %P to i32*) +  /// on 32-bit hosts. +  SmallVector<Value*, 4> NewGEPIndices; +      // If the source is an array, the code below will not succeed.  Check to    // see if a trivial 'gep P, 0, 0' will help matters.  Only do this for    // constants. -  if (const ArrayType *ASrcTy = dyn_cast<ArrayType>(SrcPTy)) -    if (Constant *CSrc = dyn_cast<Constant>(CastOp)) -      if (ASrcTy->getNumElements() != 0) { -        Value* Idxs[2]; -        Idxs[0] = Idxs[1] = Constant::getNullValue(Type::Int32Ty); -        CastOp = ConstantExpr::getGetElementPtr(CSrc, Idxs, 2); -        SrcTy = cast<PointerType>(CastOp->getType()); -        SrcPTy = SrcTy->getElementType(); +  if (isa<ArrayType>(SrcPTy) || isa<StructType>(SrcPTy)) { +    // Index through pointer. +    Constant *Zero = Constant::getNullValue(Type::Int32Ty); +    NewGEPIndices.push_back(Zero); +     +    while (1) { +      if (const StructType *STy = dyn_cast<StructType>(SrcPTy)) { +        NewGEPIndices.push_back(Zero); +        SrcPTy = STy->getElementType(0); +      } else if (const ArrayType *ATy = dyn_cast<ArrayType>(SrcPTy)) { +        NewGEPIndices.push_back(Zero); +        SrcPTy = ATy->getElementType(); +      } else { +        break;        } +    } +     +    SrcTy = PointerType::get(SrcPTy, SrcTy->getAddressSpace()); +  }    if (!SrcPTy->isInteger() && !isa<PointerType>(SrcPTy))      return 0; @@ -11192,6 +11209,19 @@ static Instruction *InstCombineStoreToCast(InstCombiner &IC, StoreInst &SI) {      if (isa<PointerType>(SIOp0->getType()))        opcode = Instruction::PtrToInt;    } +   +  // SIOp0 is a pointer to aggregate and this is a store to the first field, +  // emit a GEP to index into its first field. +  if (!NewGEPIndices.empty()) { +    if (Constant *C = dyn_cast<Constant>(CastOp)) +      CastOp = ConstantExpr::getGetElementPtr(C, &NewGEPIndices[0],  +                                              NewGEPIndices.size()); +    else +      CastOp = IC.InsertNewInstBefore( +              GetElementPtrInst::Create(CastOp, NewGEPIndices.begin(), +                                        NewGEPIndices.end()), SI); +  } +      if (Constant *C = dyn_cast<Constant>(SIOp0))      NewCast = ConstantExpr::getCast(opcode, C, CastDstTy);    else diff --git a/llvm/test/Transforms/InstCombine/cast-store-gep.ll b/llvm/test/Transforms/InstCombine/cast-store-gep.ll new file mode 100644 index 00000000000..95a069d60b7 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/cast-store-gep.ll @@ -0,0 +1,17 @@ +; RUN: llvm-as < %s | opt -instcombine | llvm-dis | grep inttoptr +; RUN: llvm-as < %s | opt -instcombine | llvm-dis | not grep alloca + +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" +	%T = type { i8*, i8 } + +define i8* @test(i8* %Val, i64 %V) nounwind { +entry: +	%A = alloca %T, align 8	 +	%mrv_gep = bitcast %T* %A to i64*		; <i64*> [#uses=1] +	%B = getelementptr %T* %A, i64 0, i32 0		; <i8**> [#uses=1] +         +      	store i64 %V, i64* %mrv_gep +	%C = load i8** %B, align 8		; <i8*> [#uses=1] +	ret i8* %C +}  | 

