Skip to content

Commit

Permalink
IR: Don't constant fold GEP bitcasts between different address spaces
Browse files Browse the repository at this point in the history
PR15262 reported a bug where the following instruction:

  i8 getelementptr inbounds i8* bitcast ([4 x i8] addrspace(12)* @buf to i8*),
                                i32 2

was getting folded into:

  addrspace(12)* getelementptr inbounds ([4 x i8] addrspace(12)* @buf, i32 0,
                                        i32 2)

This caused instcombine to crash because the original instruction and
the folded instruction have different types.  The issue was fixed by
disallowing bitcasts between different address spaces to be folded away.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@176156 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
meadori committed Feb 27, 2013
1 parent 5e5974f commit 8df7c39
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 13 deletions.
35 changes: 22 additions & 13 deletions lib/IR/ConstantFold.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<PointerType>(CE->getOperand(0)->getType()))
if (ArrayType *SAT = dyn_cast<ArrayType>(SPT->getElementType()))
if (ArrayType *CAT =
dyn_cast<ArrayType>(cast<PointerType>(C->getType())->getElementType()))
if (CAT->getElementType() == SAT->getElementType())
return
ConstantExpr::getGetElementPtr((Constant*)CE->getOperand(0),
Idxs, inBounds);
PointerType *SrcPtrTy =
dyn_cast<PointerType>(CE->getOperand(0)->getType());
PointerType *DstPtrTy = dyn_cast<PointerType>(CE->getType());
if (SrcPtrTy && DstPtrTy) {
ArrayType *SrcArrayTy =
dyn_cast<ArrayType>(SrcPtrTy->getElementType());
ArrayType *DstArrayTy =
dyn_cast<ArrayType>(DstPtrTy->getElementType());
if (SrcArrayTy && DstArrayTy
&& SrcArrayTy->getElementType() == DstArrayTy->getElementType()
&& SrcPtrTy->getAddressSpace() == DstPtrTy->getAddressSpace())
return ConstantExpr::getGetElementPtr((Constant*)CE->getOperand(0),
Idxs, inBounds);
}
}
}

Expand Down
20 changes: 20 additions & 0 deletions test/Other/constant-fold-gep.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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 }

0 comments on commit 8df7c39

Please sign in to comment.