diff --git a/lib/IR/ConstantFold.cpp b/lib/IR/ConstantFold.cpp index a5a9d9f3a7c..bf93d4f9566 100644 --- a/lib/IR/ConstantFold.cpp +++ b/lib/IR/ConstantFold.cpp @@ -1971,21 +1971,30 @@ static Constant *ConstantFoldGetElementPtrImpl(Constant *C, } } - // Implement folding of: - // i32* getelementptr ([2 x i32]* bitcast ([3 x i32]* %X to [2 x i32]*), - // i64 0, i64 0) - // To: i32* getelementptr ([3 x i32]* %X, i64 0, i64 0) + // Attempt to fold casts to the same type away. For example, folding: // + // i32* getelementptr ([2 x i32]* bitcast ([3 x i32]* %X to [2 x i32]*), + // i64 0, i64 0) + // into: + // + // i32* getelementptr ([3 x i32]* %X, i64 0, i64 0) + // + // Don't fold if the cast is changing address spaces. if (CE->isCast() && Idxs.size() > 1 && Idx0->isNullValue()) { - if (PointerType *SPT = - dyn_cast(CE->getOperand(0)->getType())) - if (ArrayType *SAT = dyn_cast(SPT->getElementType())) - if (ArrayType *CAT = - dyn_cast(cast(C->getType())->getElementType())) - if (CAT->getElementType() == SAT->getElementType()) - return - ConstantExpr::getGetElementPtr((Constant*)CE->getOperand(0), - Idxs, inBounds); + PointerType *SrcPtrTy = + dyn_cast(CE->getOperand(0)->getType()); + PointerType *DstPtrTy = dyn_cast(CE->getType()); + if (SrcPtrTy && DstPtrTy) { + ArrayType *SrcArrayTy = + dyn_cast(SrcPtrTy->getElementType()); + ArrayType *DstArrayTy = + dyn_cast(DstPtrTy->getElementType()); + if (SrcArrayTy && DstArrayTy + && SrcArrayTy->getElementType() == DstArrayTy->getElementType() + && SrcPtrTy->getAddressSpace() == DstPtrTy->getAddressSpace()) + return ConstantExpr::getGetElementPtr((Constant*)CE->getOperand(0), + Idxs, inBounds); + } } } diff --git a/test/Other/constant-fold-gep.ll b/test/Other/constant-fold-gep.ll index 0224e9f984c..44b66284dd7 100644 --- a/test/Other/constant-fold-gep.ll +++ b/test/Other/constant-fold-gep.ll @@ -447,4 +447,24 @@ define i32* @fZ() nounwind { ret i32* %t } +; PR15262 - Check GEP folding with casts between address spaces. + +@p0 = global [4 x i8] zeroinitializer, align 1 +@p12 = addrspace(12) global [4 x i8] zeroinitializer, align 1 + +define i8* @different_addrspace() nounwind noinline { +; OPT: different_addrspace + %p = getelementptr inbounds i8* bitcast ([4 x i8] addrspace(12)* @p12 to i8*), + i32 2 + ret i8* %p +; OPT: ret i8* getelementptr (i8* bitcast ([4 x i8] addrspace(12)* @p12 to i8*), i32 2) +} + +define i8* @same_addrspace() nounwind noinline { +; OPT: same_addrspace + %p = getelementptr inbounds i8* bitcast ([4 x i8] * @p0 to i8*), i32 2 + ret i8* %p +; OPT: ret i8* getelementptr inbounds ([4 x i8]* @p0, i32 0, i32 2) +} + ; CHECK: attributes #0 = { nounwind }