[ConstantFold] Fold zero-index GEPs with opaque pointers

With opaque pointers, we can eliminate zero-index GEPs even if
they have multiple indices, as this no longer impacts the result
type of the GEP.

This optimization is already done for instructions in InstSimplify,
but we were missing the corresponding constant expression handling.

The constexpr transform is a bit more powerful, because it can
produce a vector splat constant and also handles undef values --
it is an extension of an existing single-index transform.
This commit is contained in:
Nikita Popov 2022-04-04 12:59:17 +02:00
parent d092df42f3
commit 3c9f3f76f1
3 changed files with 22 additions and 11 deletions

View File

@ -2036,8 +2036,18 @@ Constant *llvm::ConstantFoldGetElementPtr(Type *PointeeTy, Constant *C,
// If inbounds, we can choose an out-of-bounds pointer as a base pointer.
return InBounds ? PoisonValue::get(GEPTy) : UndefValue::get(GEPTy);
Constant *Idx0 = cast<Constant>(Idxs[0]);
if (Idxs.size() == 1 && (Idx0->isNullValue() || isa<UndefValue>(Idx0)))
auto IsNoOp = [&]() {
// For non-opaque pointers having multiple indices will change the result
// type of the GEP.
if (!C->getType()->getScalarType()->isOpaquePointerTy() && Idxs.size() != 1)
return false;
return all_of(Idxs, [](Value *Idx) {
Constant *IdxC = cast<Constant>(Idx);
return IdxC->isNullValue() || isa<UndefValue>(IdxC);
});
};
if (IsNoOp())
return GEPTy->isVectorTy() && !C->getType()->isVectorTy()
? ConstantVector::getSplat(
cast<VectorType>(GEPTy)->getElementCount(), C)
@ -2090,6 +2100,7 @@ Constant *llvm::ConstantFoldGetElementPtr(Type *PointeeTy, Constant *C,
// i32* getelementptr ([3 x i32]* %X, i64 0, i64 0)
//
// Don't fold if the cast is changing address spaces.
Constant *Idx0 = cast<Constant>(Idxs[0]);
if (CE->isCast() && Idxs.size() > 1 && Idx0->isNullValue()) {
PointerType *SrcPtrTy =
dyn_cast<PointerType>(CE->getOperand(0)->getType());

View File

@ -11,7 +11,7 @@ define void @test_zext(ptr %a) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[P_0:%.*]] = phi ptr [ getelementptr inbounds ([240 x i8], ptr @data, i64 0, i64 0), [[ENTRY:%.*]] ], [ [[T3:%.*]], [[LOOP]] ]
; CHECK-NEXT: [[P_0:%.*]] = phi ptr [ @data, [[ENTRY:%.*]] ], [ [[T3:%.*]], [[LOOP]] ]
; CHECK-NEXT: [[DOT0:%.*]] = phi ptr [ [[A:%.*]], [[ENTRY]] ], [ [[T:%.*]], [[LOOP]] ]
; CHECK-NEXT: [[T]] = getelementptr inbounds i8, ptr [[DOT0]], i64 1
; CHECK-NEXT: [[T2:%.*]] = load i8, ptr [[DOT0]], align 1

View File

@ -56,56 +56,56 @@ define <2 x ptr> @vector_base_scalar_index(<2 x ptr> %p) {
define ptr @constexpr_zero_gep_scalar_base_scalar_index() {
; CHECK-LABEL: @constexpr_zero_gep_scalar_base_scalar_index(
; CHECK-NEXT: ret ptr getelementptr inbounds ([2 x i32], ptr @g, i64 0, i64 0)
; CHECK-NEXT: ret ptr @g
;
ret ptr getelementptr ([2 x i32], ptr @g, i64 0, i64 0)
}
define <2 x ptr> @constexpr_zero_gep_vector_base_scalar_index() {
; CHECK-LABEL: @constexpr_zero_gep_vector_base_scalar_index(
; CHECK-NEXT: ret <2 x ptr> getelementptr ([2 x i32], <2 x ptr> <ptr @g, ptr @g>, <2 x i64> zeroinitializer, <2 x i64> zeroinitializer)
; CHECK-NEXT: ret <2 x ptr> <ptr @g, ptr @g>
;
ret <2 x ptr> getelementptr ([2 x i32], <2 x ptr> <ptr @g, ptr @g>, i64 0, i64 0)
}
define <2 x ptr> @constexpr_zero_gep_scalar_base_vector_index() {
; CHECK-LABEL: @constexpr_zero_gep_scalar_base_vector_index(
; CHECK-NEXT: ret <2 x ptr> getelementptr ([2 x i32], ptr @g, <2 x i64> zeroinitializer, <2 x i64> zeroinitializer)
; CHECK-NEXT: ret <2 x ptr> <ptr @g, ptr @g>
;
ret <2 x ptr> getelementptr ([2 x i32], ptr @g, <2 x i64> zeroinitializer, i64 0)
}
define <2 x ptr> @constexpr_zero_gep_vector_base_vector_index() {
; CHECK-LABEL: @constexpr_zero_gep_vector_base_vector_index(
; CHECK-NEXT: ret <2 x ptr> getelementptr ([2 x i32], <2 x ptr> <ptr @g, ptr @g>, <2 x i64> zeroinitializer, <2 x i64> zeroinitializer)
; CHECK-NEXT: ret <2 x ptr> <ptr @g, ptr @g>
;
ret <2 x ptr> getelementptr ([2 x i32], <2 x ptr> <ptr @g, ptr @g>, <2 x i64> zeroinitializer, i64 0)
}
define ptr @constexpr_undef_gep_scalar_base_scalar_index() {
; CHECK-LABEL: @constexpr_undef_gep_scalar_base_scalar_index(
; CHECK-NEXT: ret ptr getelementptr ([2 x i32], ptr @g, i64 0, i64 undef)
; CHECK-NEXT: ret ptr @g
;
ret ptr getelementptr ([2 x i32], ptr @g, i64 0, i64 undef)
}
define <2 x ptr> @constexpr_undef_gep_vector_base_scalar_index() {
; CHECK-LABEL: @constexpr_undef_gep_vector_base_scalar_index(
; CHECK-NEXT: ret <2 x ptr> getelementptr ([2 x i32], <2 x ptr> <ptr @g, ptr @g>, <2 x i64> undef, <2 x i64> undef)
; CHECK-NEXT: ret <2 x ptr> <ptr @g, ptr @g>
;
ret <2 x ptr> getelementptr ([2 x i32], <2 x ptr> <ptr @g, ptr @g>, i64 undef, i64 undef)
}
define <2 x ptr> @constexpr_undef_gep_scalar_base_vector_index() {
; CHECK-LABEL: @constexpr_undef_gep_scalar_base_vector_index(
; CHECK-NEXT: ret <2 x ptr> getelementptr ([2 x i32], ptr @g, <2 x i64> undef, <2 x i64> zeroinitializer)
; CHECK-NEXT: ret <2 x ptr> <ptr @g, ptr @g>
;
ret <2 x ptr> getelementptr ([2 x i32], ptr @g, <2 x i64> undef, i64 0)
}
define <2 x ptr> @constexpr_undef_gep_vector_base_vector_index() {
; CHECK-LABEL: @constexpr_undef_gep_vector_base_vector_index(
; CHECK-NEXT: ret <2 x ptr> getelementptr ([2 x i32], <2 x ptr> <ptr @g, ptr @g>, <2 x i64> undef, <2 x i64> zeroinitializer)
; CHECK-NEXT: ret <2 x ptr> <ptr @g, ptr @g>
;
ret <2 x ptr> getelementptr ([2 x i32], <2 x ptr> <ptr @g, ptr @g>, <2 x i64> undef, i64 0)
}