Files
clang-p2996/llvm/test/Transforms/InstSimplify/gep.ll
Florian Hahn 8a469e2050 [InstSimplify] Fold inbounds GEP to poison if base is undef.
D92270 updated constant expression folding to fold inbounds GEP to
poison if the base is undef. Apply the same logic to SimplifyGEPInst.

The justification is that we can choose an out-of-bounds pointer as base
pointer.

Reviewed By: nikic, lebedev.ri

Differential Revision: https://reviews.llvm.org/D117015
2022-01-11 16:11:22 +00:00

361 lines
12 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -instsimplify < %s | FileCheck %s
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
%struct.A = type { [7 x i8] }
define %struct.A* @test1(%struct.A* %b, %struct.A* %e) {
; CHECK-LABEL: @test1(
; CHECK-NEXT: [[E_PTR:%.*]] = ptrtoint %struct.A* [[E:%.*]] to i64
; CHECK-NEXT: [[B_PTR:%.*]] = ptrtoint %struct.A* [[B:%.*]] to i64
; CHECK-NEXT: [[SUB:%.*]] = sub i64 [[E_PTR]], [[B_PTR]]
; CHECK-NEXT: [[SDIV:%.*]] = sdiv exact i64 [[SUB]], 7
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [[STRUCT_A:%.*]], %struct.A* [[B]], i64 [[SDIV]]
; CHECK-NEXT: ret %struct.A* [[GEP]]
;
%e_ptr = ptrtoint %struct.A* %e to i64
%b_ptr = ptrtoint %struct.A* %b to i64
%sub = sub i64 %e_ptr, %b_ptr
%sdiv = sdiv exact i64 %sub, 7
%gep = getelementptr inbounds %struct.A, %struct.A* %b, i64 %sdiv
ret %struct.A* %gep
}
define i8* @test2(i8* %b, i8* %e) {
; CHECK-LABEL: @test2(
; CHECK-NEXT: [[E_PTR:%.*]] = ptrtoint i8* [[E:%.*]] to i64
; CHECK-NEXT: [[B_PTR:%.*]] = ptrtoint i8* [[B:%.*]] to i64
; CHECK-NEXT: [[SUB:%.*]] = sub i64 [[E_PTR]], [[B_PTR]]
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, i8* [[B]], i64 [[SUB]]
; CHECK-NEXT: ret i8* [[GEP]]
;
%e_ptr = ptrtoint i8* %e to i64
%b_ptr = ptrtoint i8* %b to i64
%sub = sub i64 %e_ptr, %b_ptr
%gep = getelementptr inbounds i8, i8* %b, i64 %sub
ret i8* %gep
}
define i64* @test3(i64* %b, i64* %e) {
; CHECK-LABEL: @test3(
; CHECK-NEXT: [[E_PTR:%.*]] = ptrtoint i64* [[E:%.*]] to i64
; CHECK-NEXT: [[B_PTR:%.*]] = ptrtoint i64* [[B:%.*]] to i64
; CHECK-NEXT: [[SUB:%.*]] = sub i64 [[E_PTR]], [[B_PTR]]
; CHECK-NEXT: [[ASHR:%.*]] = ashr exact i64 [[SUB]], 3
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i64, i64* [[B]], i64 [[ASHR]]
; CHECK-NEXT: ret i64* [[GEP]]
;
%e_ptr = ptrtoint i64* %e to i64
%b_ptr = ptrtoint i64* %b to i64
%sub = sub i64 %e_ptr, %b_ptr
%ashr = ashr exact i64 %sub, 3
%gep = getelementptr inbounds i64, i64* %b, i64 %ashr
ret i64* %gep
}
; The following tests should not be folded to null, because this would
; lose provenance of the base pointer %b.
define %struct.A* @test4(%struct.A* %b) {
; CHECK-LABEL: @test4(
; CHECK-NEXT: [[B_PTR:%.*]] = ptrtoint %struct.A* [[B:%.*]] to i64
; CHECK-NEXT: [[SUB:%.*]] = sub i64 0, [[B_PTR]]
; CHECK-NEXT: [[SDIV:%.*]] = sdiv exact i64 [[SUB]], 7
; CHECK-NEXT: [[GEP:%.*]] = getelementptr [[STRUCT_A:%.*]], %struct.A* [[B]], i64 [[SDIV]]
; CHECK-NEXT: ret %struct.A* [[GEP]]
;
%b_ptr = ptrtoint %struct.A* %b to i64
%sub = sub i64 0, %b_ptr
%sdiv = sdiv exact i64 %sub, 7
%gep = getelementptr %struct.A, %struct.A* %b, i64 %sdiv
ret %struct.A* %gep
}
define %struct.A* @test4_inbounds(%struct.A* %b) {
; CHECK-LABEL: @test4_inbounds(
; CHECK-NEXT: [[B_PTR:%.*]] = ptrtoint %struct.A* [[B:%.*]] to i64
; CHECK-NEXT: [[SUB:%.*]] = sub i64 0, [[B_PTR]]
; CHECK-NEXT: [[SDIV:%.*]] = sdiv exact i64 [[SUB]], 7
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [[STRUCT_A:%.*]], %struct.A* [[B]], i64 [[SDIV]]
; CHECK-NEXT: ret %struct.A* [[GEP]]
;
%b_ptr = ptrtoint %struct.A* %b to i64
%sub = sub i64 0, %b_ptr
%sdiv = sdiv exact i64 %sub, 7
%gep = getelementptr inbounds %struct.A, %struct.A* %b, i64 %sdiv
ret %struct.A* %gep
}
define i8* @test5(i8* %b) {
; CHECK-LABEL: @test5(
; CHECK-NEXT: [[B_PTR:%.*]] = ptrtoint i8* [[B:%.*]] to i64
; CHECK-NEXT: [[SUB:%.*]] = sub i64 0, [[B_PTR]]
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, i8* [[B]], i64 [[SUB]]
; CHECK-NEXT: ret i8* [[GEP]]
;
%b_ptr = ptrtoint i8* %b to i64
%sub = sub i64 0, %b_ptr
%gep = getelementptr i8, i8* %b, i64 %sub
ret i8* %gep
}
define i8* @test5_inbounds(i8* %b) {
; CHECK-LABEL: @test5_inbounds(
; CHECK-NEXT: [[B_PTR:%.*]] = ptrtoint i8* [[B:%.*]] to i64
; CHECK-NEXT: [[SUB:%.*]] = sub i64 0, [[B_PTR]]
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, i8* [[B]], i64 [[SUB]]
; CHECK-NEXT: ret i8* [[GEP]]
;
%b_ptr = ptrtoint i8* %b to i64
%sub = sub i64 0, %b_ptr
%gep = getelementptr inbounds i8, i8* %b, i64 %sub
ret i8* %gep
}
define i64* @test6(i64* %b) {
; CHECK-LABEL: @test6(
; CHECK-NEXT: [[B_PTR:%.*]] = ptrtoint i64* [[B:%.*]] to i64
; CHECK-NEXT: [[SUB:%.*]] = sub i64 0, [[B_PTR]]
; CHECK-NEXT: [[ASHR:%.*]] = ashr exact i64 [[SUB]], 3
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i64, i64* [[B]], i64 [[ASHR]]
; CHECK-NEXT: ret i64* [[GEP]]
;
%b_ptr = ptrtoint i64* %b to i64
%sub = sub i64 0, %b_ptr
%ashr = ashr exact i64 %sub, 3
%gep = getelementptr i64, i64* %b, i64 %ashr
ret i64* %gep
}
define i64* @test6_inbounds(i64* %b) {
; CHECK-LABEL: @test6_inbounds(
; CHECK-NEXT: [[B_PTR:%.*]] = ptrtoint i64* [[B:%.*]] to i64
; CHECK-NEXT: [[SUB:%.*]] = sub i64 0, [[B_PTR]]
; CHECK-NEXT: [[ASHR:%.*]] = ashr exact i64 [[SUB]], 3
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i64, i64* [[B]], i64 [[ASHR]]
; CHECK-NEXT: ret i64* [[GEP]]
;
%b_ptr = ptrtoint i64* %b to i64
%sub = sub i64 0, %b_ptr
%ashr = ashr exact i64 %sub, 3
%gep = getelementptr inbounds i64, i64* %b, i64 %ashr
ret i64* %gep
}
define i8* @test7(i8* %b, i8** %e) {
; CHECK-LABEL: @test7(
; CHECK-NEXT: [[E_PTR:%.*]] = ptrtoint i8** [[E:%.*]] to i64
; CHECK-NEXT: [[B_PTR:%.*]] = ptrtoint i8* [[B:%.*]] to i64
; CHECK-NEXT: [[SUB:%.*]] = sub i64 [[E_PTR]], [[B_PTR]]
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, i8* [[B]], i64 [[SUB]]
; CHECK-NEXT: ret i8* [[GEP]]
;
%e_ptr = ptrtoint i8** %e to i64
%b_ptr = ptrtoint i8* %b to i64
%sub = sub i64 %e_ptr, %b_ptr
%gep = getelementptr inbounds i8, i8* %b, i64 %sub
ret i8* %gep
}
define i64* @undef_inbounds_var_idx(i64 %idx) {
; CHECK-LABEL: @undef_inbounds_var_idx(
; CHECK-NEXT: ret i64* poison
;
%el = getelementptr inbounds i64, i64* undef, i64 %idx
ret i64* %el
}
define i64* @undef_no_inbounds_var_idx(i64 %idx) {
; CHECK-LABEL: @undef_no_inbounds_var_idx(
; CHECK-NEXT: ret i64* undef
;
%el = getelementptr i64, i64* undef, i64 %idx
ret i64* %el
}
define <8 x i64*> @undef_vec1() {
; CHECK-LABEL: @undef_vec1(
; CHECK-NEXT: ret <8 x i64*> poison
;
%el = getelementptr inbounds i64, i64* undef, <8 x i64> undef
ret <8 x i64*> %el
}
define <8 x i64*> @undef_vec2() {
; CHECK-LABEL: @undef_vec2(
; CHECK-NEXT: ret <8 x i64*> undef
;
%el = getelementptr i64, <8 x i64*> undef, <8 x i64> undef
ret <8 x i64*> %el
}
; Check ConstantExpr::getGetElementPtr() using ElementCount for size queries - begin.
; Constant ptr
define i32* @ptr_idx_scalar() {
; CHECK-LABEL: @ptr_idx_scalar(
; CHECK-NEXT: ret i32* inttoptr (i64 4 to i32*)
;
%gep = getelementptr <4 x i32>, <4 x i32>* null, i64 0, i64 1
ret i32* %gep
}
define <2 x i32*> @ptr_idx_vector() {
; CHECK-LABEL: @ptr_idx_vector(
; CHECK-NEXT: ret <2 x i32*> getelementptr (i32, i32* null, <2 x i64> <i64 1, i64 1>)
;
%gep = getelementptr i32, i32* null, <2 x i64> <i64 1, i64 1>
ret <2 x i32*> %gep
}
define <4 x i32*> @ptr_idx_mix_scalar_vector(){
; CHECK-LABEL: @ptr_idx_mix_scalar_vector(
; CHECK-NEXT: ret <4 x i32*> getelementptr ([42 x [3 x i32]], [42 x [3 x i32]]* null, <4 x i64> zeroinitializer, <4 x i64> <i64 0, i64 1, i64 2, i64 3>, <4 x i64> zeroinitializer)
;
%gep = getelementptr [42 x [3 x i32]], [42 x [3 x i32]]* null, i64 0, <4 x i64> <i64 0, i64 1, i64 2, i64 3>, i64 0
ret <4 x i32*> %gep
}
; Constant vector
define <4 x i32*> @vector_idx_scalar() {
; CHECK-LABEL: @vector_idx_scalar(
; CHECK-NEXT: ret <4 x i32*> getelementptr (i32, <4 x i32*> zeroinitializer, <4 x i64> <i64 1, i64 1, i64 1, i64 1>)
;
%gep = getelementptr i32, <4 x i32*> zeroinitializer, i64 1
ret <4 x i32*> %gep
}
define <4 x i32*> @vector_idx_vector() {
; CHECK-LABEL: @vector_idx_vector(
; CHECK-NEXT: ret <4 x i32*> getelementptr (i32, <4 x i32*> zeroinitializer, <4 x i64> <i64 1, i64 1, i64 1, i64 1>)
;
%gep = getelementptr i32, <4 x i32*> zeroinitializer, <4 x i64> <i64 1, i64 1, i64 1, i64 1>
ret <4 x i32*> %gep
}
%struct = type { double, float }
define <4 x float*> @vector_idx_mix_scalar_vector() {
; CHECK-LABEL: @vector_idx_mix_scalar_vector(
; CHECK-NEXT: ret <4 x float*> getelementptr ([[STRUCT:%.*]], <4 x %struct*> zeroinitializer, <4 x i64> zeroinitializer, i32 1)
;
%gep = getelementptr %struct, <4 x %struct*> zeroinitializer, i32 0, <4 x i32> <i32 1, i32 1, i32 1, i32 1>
ret <4 x float*> %gep
}
; Constant scalable
define <vscale x 4 x i32*> @scalable_idx_scalar() {
; CHECK-LABEL: @scalable_idx_scalar(
; CHECK-NEXT: ret <vscale x 4 x i32*> getelementptr (i32, <vscale x 4 x i32*> zeroinitializer, <vscale x 4 x i64> shufflevector (<vscale x 4 x i64> insertelement (<vscale x 4 x i64> poison, i64 1, i32 0), <vscale x 4 x i64> poison, <vscale x 4 x i32> zeroinitializer))
;
%gep = getelementptr i32, <vscale x 4 x i32*> zeroinitializer, i64 1
ret <vscale x 4 x i32*> %gep
}
define <vscale x 4 x float*> @scalable_vector_idx_mix_scalar_vector() {
; CHECK-LABEL: @scalable_vector_idx_mix_scalar_vector(
; CHECK-NEXT: ret <vscale x 4 x float*> getelementptr ([[STRUCT:%.*]], <vscale x 4 x %struct*> zeroinitializer, <vscale x 4 x i64> zeroinitializer, i32 1)
;
%gep = getelementptr %struct, <vscale x 4 x %struct*> zeroinitializer, i32 0, i32 1
ret <vscale x 4 x float*> %gep
}
define <vscale x 2 x i64*> @ptr_idx_mix_scalar_scalable_vector() {
; CHECK-LABEL: @ptr_idx_mix_scalar_scalable_vector(
; CHECK-NEXT: ret <vscale x 2 x i64*> zeroinitializer
;
%v = getelementptr [2 x i64], [2 x i64]* null, i64 0, <vscale x 2 x i64> zeroinitializer
ret <vscale x 2 x i64*> %v
}
; Check ConstantExpr::getGetElementPtr() using ElementCount for size queries - end.
define i8* @poison() {
; CHECK-LABEL: @poison(
; CHECK-NEXT: ret i8* poison
;
%v = getelementptr i8, i8* poison, i64 1
ret i8* %v
}
define i8* @poison2(i8* %baseptr) {
; CHECK-LABEL: @poison2(
; CHECK-NEXT: ret i8* poison
;
%v = getelementptr i8, i8* %baseptr, i64 poison
ret i8* %v
}
define i8* @D98611_1(i8* %c1, i64 %offset) {
; CHECK-LABEL: @D98611_1(
; CHECK-NEXT: [[C2:%.*]] = getelementptr inbounds i8, i8* [[C1:%.*]], i64 [[OFFSET:%.*]]
; CHECK-NEXT: ret i8* [[C2]]
;
%c2 = getelementptr inbounds i8, i8* %c1, i64 %offset
%ptrtoint1 = ptrtoint i8* %c1 to i64
%ptrtoint2 = ptrtoint i8* %c2 to i64
%sub = sub i64 %ptrtoint2, %ptrtoint1
%gep = getelementptr inbounds i8, i8* %c1, i64 %sub
ret i8* %gep
}
define %struct.A* @D98611_2(%struct.A* %c1, i64 %offset) {
; CHECK-LABEL: @D98611_2(
; CHECK-NEXT: [[C2:%.*]] = getelementptr inbounds [[STRUCT_A:%.*]], %struct.A* [[C1:%.*]], i64 [[OFFSET:%.*]]
; CHECK-NEXT: ret %struct.A* [[C2]]
;
%c2 = getelementptr inbounds %struct.A, %struct.A* %c1, i64 %offset
%ptrtoint1 = ptrtoint %struct.A* %c1 to i64
%ptrtoint2 = ptrtoint %struct.A* %c2 to i64
%sub = sub i64 %ptrtoint2, %ptrtoint1
%sdiv = sdiv exact i64 %sub, 7
%gep = getelementptr inbounds %struct.A, %struct.A* %c1, i64 %sdiv
ret %struct.A* %gep
}
define i32* @D98611_3(i32* %c1, i64 %offset) {
; CHECK-LABEL: @D98611_3(
; CHECK-NEXT: [[C2:%.*]] = getelementptr inbounds i32, i32* [[C1:%.*]], i64 [[OFFSET:%.*]]
; CHECK-NEXT: ret i32* [[C2]]
;
%c2 = getelementptr inbounds i32, i32* %c1, i64 %offset
%ptrtoint1 = ptrtoint i32* %c1 to i64
%ptrtoint2 = ptrtoint i32* %c2 to i64
%sub = sub i64 %ptrtoint2, %ptrtoint1
%ashr = ashr exact i64 %sub, 2
%gep = getelementptr inbounds i32, i32* %c1, i64 %ashr
ret i32* %gep
}
define <8 x i32*> @gep_vector_index_op2_poison([144 x i32]* %ptr) {
; CHECK-LABEL: @gep_vector_index_op2_poison(
; CHECK-NEXT: ret <8 x i32*> poison
;
%res = getelementptr inbounds [144 x i32], [144 x i32]* %ptr, i64 0, <8 x i64> poison
ret <8 x i32*> %res
}
%t.1 = type { i32, [144 x i32] }
define <8 x i32*> @gep_vector_index_op3_poison(%t.1* %ptr) {
; CHECK-LABEL: @gep_vector_index_op3_poison(
; CHECK-NEXT: ret <8 x i32*> poison
;
%res = getelementptr inbounds %t.1, %t.1* %ptr, i64 0, i32 1, <8 x i64> poison
ret <8 x i32*> %res
}
%t.2 = type { i32, i32 }
%t.3 = type { i32, [144 x %t.2 ] }
define <8 x i32*> @gep_vector_index_op3_poison_constant_index_afterwards(%t.3* %ptr) {
; CHECK-LABEL: @gep_vector_index_op3_poison_constant_index_afterwards(
; CHECK-NEXT: ret <8 x i32*> poison
;
%res = getelementptr inbounds %t.3, %t.3* %ptr, i64 0, i32 1, <8 x i64> poison, i32 1
ret <8 x i32*> %res
}