The current code does not properly handle vector indices unless they are the first index. At the moment LangRef gives the impression that the vector index must be the one and only index (https://llvm.org/docs/LangRef.html#getelementptr-instruction). But vector indices can appear at any position and according to the verifier there may be multiple vector indices. If that's the case, the number of elements must match. This patch updates SimplifyGEPInst to properly handle those additional cases. Reviewed By: nikic Differential Revision: https://reviews.llvm.org/D99961
347 lines
12 KiB
LLVM
347 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 <8 x i64*> @undef_vec1() {
|
|
; CHECK-LABEL: @undef_vec1(
|
|
; CHECK-NEXT: ret <8 x i64*> undef
|
|
;
|
|
%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> undef, i64 1, i32 0), <vscale x 4 x i64> undef, <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.
|
|
|
|
; TODO: these should return poison
|
|
|
|
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
|
|
}
|