Files
clang-p2996/llvm/test/Transforms/InstCombine/getelementptr.ll
David Green 73af455f57 [InstCombine] Handle more scalable geps in EmitGEPOffset (#71699)
Following up on #71565, this makes scalable splats in EmitGEPOffset use
the ElementCount as opposed to assuming it is fixed width, and attempts
to handle scalable offsets with vector geps by splatting the vscale to
each vector lane.
2023-11-11 18:21:31 +00:00

1457 lines
48 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
target datalayout = "e-p:64:64-p1:16:16-p2:32:32:32-p3:64:64:64"
%intstruct = type { i32 }
%pair = type { i32, i32 }
%struct.B = type { double }
%struct.A = type { %struct.B, i32, i32 }
%struct.C = type { [7 x i8] }
@Global = external global [10 x i8]
@Global_as1 = external addrspace(1) global [10 x i8]
declare void @use(ptr)
; Test noop elimination
define ptr @test1(ptr %I) {
; CHECK-LABEL: @test1(
; CHECK-NEXT: ret ptr [[I:%.*]]
;
ret ptr %I
}
define ptr addrspace(1) @test1_as1(ptr addrspace(1) %I) {
; CHECK-LABEL: @test1_as1(
; CHECK-NEXT: ret ptr addrspace(1) [[I:%.*]]
;
ret ptr addrspace(1) %I
}
; Test noop elimination
define ptr @test2(ptr %I) {
; CHECK-LABEL: @test2(
; CHECK-NEXT: ret ptr [[I:%.*]]
;
%A = getelementptr i32, ptr %I
ret ptr %A
}
; Test that two array indexing geps fold
define ptr @test3(ptr %I) {
; CHECK-LABEL: @test3(
; CHECK-NEXT: [[B:%.*]] = getelementptr i32, ptr [[I:%.*]], i64 21
; CHECK-NEXT: ret ptr [[B]]
;
%A = getelementptr i32, ptr %I, i64 17
%B = getelementptr i32, ptr %A, i64 4
ret ptr %B
}
; Test that two getelementptr insts fold
define ptr @test4(ptr %I) {
; CHECK-LABEL: @test4(
; CHECK-NEXT: [[A:%.*]] = getelementptr { i32 }, ptr [[I:%.*]], i64 1
; CHECK-NEXT: ret ptr [[A]]
;
%A = getelementptr { i32 }, ptr %I, i64 1
ret ptr %A
}
define void @test5(i8 %B) {
; This should be turned into a constexpr instead of being an instruction
; CHECK-LABEL: @test5(
; CHECK-NEXT: store i8 [[B:%.*]], ptr getelementptr inbounds ([10 x i8], ptr @Global, i64 0, i64 4), align 1
; CHECK-NEXT: ret void
;
%A = getelementptr [10 x i8], ptr @Global, i64 0, i64 4
store i8 %B, ptr %A
ret void
}
define void @test5_as1(i8 %B) {
; This should be turned into a constexpr instead of being an instruction
; CHECK-LABEL: @test5_as1(
; CHECK-NEXT: store i8 [[B:%.*]], ptr addrspace(1) getelementptr inbounds ([10 x i8], ptr addrspace(1) @Global_as1, i16 0, i16 4), align 1
; CHECK-NEXT: ret void
;
%A = getelementptr [10 x i8], ptr addrspace(1) @Global_as1, i16 0, i16 4
store i8 %B, ptr addrspace(1) %A
ret void
}
%as1_ptr_struct = type { ptr addrspace(1) }
%as2_ptr_struct = type { ptr addrspace(2) }
@global_as2 = addrspace(2) global i32 zeroinitializer
@global_as1_as2_ptr = addrspace(1) global %as2_ptr_struct { ptr addrspace(2) @global_as2 }
; This should be turned into a constexpr instead of being an instruction
define void @test_evaluate_gep_nested_as_ptrs(ptr addrspace(2) %B) {
; CHECK-LABEL: @test_evaluate_gep_nested_as_ptrs(
; CHECK-NEXT: store ptr addrspace(2) [[B:%.*]], ptr addrspace(1) @global_as1_as2_ptr, align 4
; CHECK-NEXT: ret void
;
store ptr addrspace(2) %B, ptr addrspace(1) @global_as1_as2_ptr
ret void
}
@arst = addrspace(1) global [4 x ptr addrspace(2)] zeroinitializer
define void @test_evaluate_gep_as_ptrs_array(ptr addrspace(2) %B) {
; CHECK-LABEL: @test_evaluate_gep_as_ptrs_array(
; CHECK-NEXT: store ptr addrspace(2) [[B:%.*]], ptr addrspace(1) getelementptr inbounds ([4 x ptr addrspace(2)], ptr addrspace(1) @arst, i16 0, i16 2), align 4
; CHECK-NEXT: ret void
;
%A = getelementptr [4 x ptr addrspace(2)], ptr addrspace(1) @arst, i16 0, i16 2
store ptr addrspace(2) %B, ptr addrspace(1) %A
ret void
}
define ptr @test7(ptr %I, i64 %C, i64 %D) {
; CHECK-LABEL: @test7(
; CHECK-NEXT: [[A:%.*]] = getelementptr i32, ptr [[I:%.*]], i64 [[C:%.*]]
; CHECK-NEXT: [[B:%.*]] = getelementptr i32, ptr [[A]], i64 [[D:%.*]]
; CHECK-NEXT: ret ptr [[B]]
;
%A = getelementptr i32, ptr %I, i64 %C
%B = getelementptr i32, ptr %A, i64 %D
ret ptr %B
}
define ptr @test8(ptr %X) {
;; Fold into the cast.
; CHECK-LABEL: @test8(
; CHECK-NEXT: ret ptr [[X:%.*]]
;
ret ptr %X
}
define i32 @test9() {
; CHECK-LABEL: @test9(
; CHECK-NEXT: ret i32 8
;
%A = getelementptr { i32, double }, ptr null, i32 0, i32 1
%B = ptrtoint ptr %A to i32
ret i32 %B
}
define i1 @test10(ptr %x, ptr %y) {
; CHECK-LABEL: @test10(
; CHECK-NEXT: [[T4:%.*]] = icmp eq ptr [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret i1 [[T4]]
;
%t1 = getelementptr { i32, i32 }, ptr %x, i32 0, i32 1
%t3 = getelementptr { i32, i32 }, ptr %y, i32 0, i32 1
%t4 = icmp eq ptr %t1, %t3
ret i1 %t4
}
define i1 @test10_addrspacecast(ptr %x, ptr addrspace(3) %y) {
; CHECK-LABEL: @test10_addrspacecast(
; CHECK-NEXT: [[T1:%.*]] = getelementptr { i32, i32 }, ptr [[X:%.*]], i64 0, i32 1
; CHECK-NEXT: [[T3:%.*]] = getelementptr { i32, i32 }, ptr addrspace(3) [[Y:%.*]], i64 0, i32 1
; CHECK-NEXT: [[T3_C:%.*]] = addrspacecast ptr addrspace(3) [[T3]] to ptr
; CHECK-NEXT: [[T4:%.*]] = icmp eq ptr [[T1]], [[T3_C]]
; CHECK-NEXT: ret i1 [[T4]]
;
%t1 = getelementptr { i32, i32 }, ptr %x, i32 0, i32 1
%t3 = getelementptr { i32, i32 }, ptr addrspace(3) %y, i32 0, i32 1
%t3.c = addrspacecast ptr addrspace(3) %t3 to ptr
%t4 = icmp eq ptr %t1, %t3.c
ret i1 %t4
}
define i1 @test11(ptr %X) {
; CHECK-LABEL: @test11(
; CHECK-NEXT: [[Q:%.*]] = icmp eq ptr [[X:%.*]], null
; CHECK-NEXT: ret i1 [[Q]]
;
%P = getelementptr { i32, i32 }, ptr %X, i32 0, i32 0
%Q = icmp eq ptr %P, null
ret i1 %Q
}
; PR4748
define i32 @test12(ptr %a) {
; CHECK-LABEL: @test12(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[G3:%.*]] = getelementptr [[STRUCT_A:%.*]], ptr [[A:%.*]], i64 0, i32 1
; CHECK-NEXT: store i32 10, ptr [[G3]], align 4
; CHECK-NEXT: ret i32 10
;
entry:
%g3 = getelementptr %struct.A, ptr %a, i32 0, i32 1
store i32 10, ptr %g3, align 4
%g5 = getelementptr %struct.A, ptr %a, i32 0, i32 1
%a_a = load i32, ptr %g5, align 4
ret i32 %a_a
}
; PR2235
%S = type { i32, [ 100 x i32] }
define i1 @test13(i64 %X, ptr %P) {
; CHECK-LABEL: @test13(
; CHECK-NEXT: [[C:%.*]] = icmp eq i64 [[X:%.*]], -1
; CHECK-NEXT: ret i1 [[C]]
;
%A = getelementptr inbounds %S, ptr %P, i32 0, i32 1, i64 %X
%C = icmp eq ptr %A, %P
ret i1 %C
}
define <2 x i1> @test13_vector(<2 x i64> %X, <2 x ptr> %P) nounwind {
; CHECK-LABEL: @test13_vector(
; CHECK-NEXT: [[C:%.*]] = icmp eq <2 x i64> [[X:%.*]], <i64 -1, i64 -1>
; CHECK-NEXT: ret <2 x i1> [[C]]
;
%A = getelementptr inbounds %S, <2 x ptr> %P, <2 x i64> zeroinitializer, <2 x i32> <i32 1, i32 1>, <2 x i64> %X
%B = getelementptr inbounds %S, <2 x ptr> %P, <2 x i64> <i64 0, i64 0>, <2 x i32> <i32 0, i32 0>
%C = icmp eq <2 x ptr> %A, %B
ret <2 x i1> %C
}
define <2 x i1> @test13_vector2(i64 %X, <2 x ptr> %P) nounwind {
; CHECK-LABEL: @test13_vector2(
; CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement <2 x i64> poison, i64 [[X:%.*]], i64 0
; CHECK-NEXT: [[TMP1:%.*]] = shl <2 x i64> [[DOTSPLATINSERT]], <i64 2, i64 0>
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq <2 x i64> [[TMP1]], <i64 -4, i64 poison>
; CHECK-NEXT: [[C:%.*]] = shufflevector <2 x i1> [[TMP2]], <2 x i1> poison, <2 x i32> zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[C]]
;
%A = getelementptr inbounds %S, <2 x ptr> %P, <2 x i64> zeroinitializer, <2 x i32> <i32 1, i32 1>, i64 %X
%B = getelementptr inbounds %S, <2 x ptr> %P, <2 x i64> <i64 0, i64 0>, <2 x i32> <i32 0, i32 0>
%C = icmp eq <2 x ptr> %A, %B
ret <2 x i1> %C
}
define <2 x i1> @test13_fixed_fixed(i64 %X, ptr %P, <2 x i64> %y) nounwind {
; CHECK-LABEL: @test13_fixed_fixed(
; CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement <2 x i64> poison, i64 [[X:%.*]], i64 0
; CHECK-NEXT: [[TMP1:%.*]] = shl <2 x i64> [[DOTSPLATINSERT]], <i64 3, i64 0>
; CHECK-NEXT: [[A_IDX:%.*]] = shufflevector <2 x i64> [[TMP1]], <2 x i64> poison, <2 x i32> zeroinitializer
; CHECK-NEXT: [[B_IDX:%.*]] = shl nsw <2 x i64> [[Y:%.*]], <i64 4, i64 4>
; CHECK-NEXT: [[C:%.*]] = icmp eq <2 x i64> [[A_IDX]], [[B_IDX]]
; CHECK-NEXT: ret <2 x i1> [[C]]
;
%A = getelementptr inbounds <2 x i64>, ptr %P, <2 x i64> zeroinitializer, i64 %X
%B = getelementptr inbounds <2 x i64>, ptr %P, <2 x i64> %y
%C = icmp eq <2 x ptr> %A, %B
ret <2 x i1> %C
}
define <2 x i1> @test13_fixed_scalable(i64 %X, ptr %P, <2 x i64> %y) nounwind {
; CHECK-LABEL: @test13_fixed_scalable(
; CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement <2 x i64> poison, i64 [[X:%.*]], i64 0
; CHECK-NEXT: [[TMP1:%.*]] = shl <2 x i64> [[DOTSPLATINSERT]], <i64 3, i64 0>
; CHECK-NEXT: [[A_IDX:%.*]] = shufflevector <2 x i64> [[TMP1]], <2 x i64> poison, <2 x i32> zeroinitializer
; CHECK-NEXT: [[TMP2:%.*]] = call i64 @llvm.vscale.i64()
; CHECK-NEXT: [[TMP3:%.*]] = shl i64 [[TMP2]], 4
; CHECK-NEXT: [[DOTSPLATINSERT1:%.*]] = insertelement <2 x i64> poison, i64 [[TMP3]], i64 0
; CHECK-NEXT: [[DOTSPLAT2:%.*]] = shufflevector <2 x i64> [[DOTSPLATINSERT1]], <2 x i64> poison, <2 x i32> zeroinitializer
; CHECK-NEXT: [[B_IDX:%.*]] = mul nsw <2 x i64> [[DOTSPLAT2]], [[Y:%.*]]
; CHECK-NEXT: [[C:%.*]] = icmp eq <2 x i64> [[A_IDX]], [[B_IDX]]
; CHECK-NEXT: ret <2 x i1> [[C]]
;
%A = getelementptr inbounds <vscale x 2 x i64>, ptr %P, <2 x i64> zeroinitializer, i64 %X
%B = getelementptr inbounds <vscale x 2 x i64>, ptr %P, <2 x i64> %y
%C = icmp eq <2 x ptr> %A, %B
ret <2 x i1> %C
}
define <vscale x 2 x i1> @test13_scalable_scalable(i64 %X, ptr %P, <vscale x 2 x i64> %y) nounwind {
; CHECK-LABEL: @test13_scalable_scalable(
; CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement <vscale x 2 x i64> poison, i64 [[X:%.*]], i64 0
; CHECK-NEXT: [[DOTSPLAT:%.*]] = shufflevector <vscale x 2 x i64> [[DOTSPLATINSERT]], <vscale x 2 x i64> poison, <vscale x 2 x i32> zeroinitializer
; CHECK-NEXT: [[A_IDX:%.*]] = shl nsw <vscale x 2 x i64> [[DOTSPLAT]], shufflevector (<vscale x 2 x i64> insertelement (<vscale x 2 x i64> poison, i64 3, i64 0), <vscale x 2 x i64> poison, <vscale x 2 x i32> zeroinitializer)
; CHECK-NEXT: [[TMP1:%.*]] = call i64 @llvm.vscale.i64()
; CHECK-NEXT: [[TMP2:%.*]] = shl i64 [[TMP1]], 4
; CHECK-NEXT: [[DOTSPLATINSERT1:%.*]] = insertelement <vscale x 2 x i64> poison, i64 [[TMP2]], i64 0
; CHECK-NEXT: [[DOTSPLAT2:%.*]] = shufflevector <vscale x 2 x i64> [[DOTSPLATINSERT1]], <vscale x 2 x i64> poison, <vscale x 2 x i32> zeroinitializer
; CHECK-NEXT: [[B_IDX:%.*]] = mul nsw <vscale x 2 x i64> [[DOTSPLAT2]], [[Y:%.*]]
; CHECK-NEXT: [[C:%.*]] = icmp eq <vscale x 2 x i64> [[A_IDX]], [[B_IDX]]
; CHECK-NEXT: ret <vscale x 2 x i1> [[C]]
;
%A = getelementptr inbounds <vscale x 2 x i64>, ptr %P, <vscale x 2 x i64> zeroinitializer, i64 %X
%B = getelementptr inbounds <vscale x 2 x i64>, ptr %P, <vscale x 2 x i64> %y
%C = icmp eq <vscale x 2 x ptr> %A, %B
ret <vscale x 2 x i1> %C
}
; This is a test of icmp + shl nuw in disguise - 4611... is 0x3fff...
define <2 x i1> @test13_vector3(i64 %X, <2 x ptr> %P) nounwind {
; CHECK-LABEL: @test13_vector3(
; CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement <2 x i64> poison, i64 [[X:%.*]], i64 0
; CHECK-NEXT: [[TMP1:%.*]] = shl <2 x i64> [[DOTSPLATINSERT]], <i64 2, i64 0>
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq <2 x i64> [[TMP1]], <i64 4, i64 poison>
; CHECK-NEXT: [[C:%.*]] = shufflevector <2 x i1> [[TMP2]], <2 x i1> poison, <2 x i32> zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[C]]
;
%A = getelementptr inbounds %S, <2 x ptr> %P, <2 x i64> zeroinitializer, <2 x i32> <i32 1, i32 1>, i64 %X
%B = getelementptr inbounds %S, <2 x ptr> %P, <2 x i64> <i64 0, i64 0>, <2 x i32> <i32 1, i32 1>, i64 1
%C = icmp eq <2 x ptr> %A, %B
ret <2 x i1> %C
}
define i1 @test13_as1(i16 %X, ptr addrspace(1) %P) {
; CHECK-LABEL: @test13_as1(
; CHECK-NEXT: [[C:%.*]] = icmp eq i16 [[X:%.*]], -1
; CHECK-NEXT: ret i1 [[C]]
;
%A = getelementptr inbounds %S, ptr addrspace(1) %P, i16 0, i32 1, i16 %X
%C = icmp eq ptr addrspace(1) %A, %P
ret i1 %C
}
define <2 x i1> @test13_vector_as1(<2 x i16> %X, <2 x ptr addrspace(1)> %P) {
; CHECK-LABEL: @test13_vector_as1(
; CHECK-NEXT: [[C:%.*]] = icmp eq <2 x i16> [[X:%.*]], <i16 -1, i16 -1>
; CHECK-NEXT: ret <2 x i1> [[C]]
;
%A = getelementptr inbounds %S, <2 x ptr addrspace(1)> %P, <2 x i16> <i16 0, i16 0>, <2 x i32> <i32 1, i32 1>, <2 x i16> %X
%B = getelementptr inbounds %S, <2 x ptr addrspace(1)> %P, <2 x i16> <i16 0, i16 0>, <2 x i32> <i32 0, i32 0>
%C = icmp eq <2 x ptr addrspace(1)> %A, %B
ret <2 x i1> %C
}
define i1 @test13_i32(i32 %X, ptr %P) {
; CHECK-LABEL: @test13_i32(
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[X:%.*]], -1
; CHECK-NEXT: ret i1 [[C]]
;
%A = getelementptr inbounds %S, ptr %P, i32 0, i32 1, i32 %X
%C = icmp eq ptr %A, %P
ret i1 %C
}
define i1 @test13_i16(i16 %X, ptr %P) {
; CHECK-LABEL: @test13_i16(
; CHECK-NEXT: [[C:%.*]] = icmp eq i16 [[X:%.*]], -1
; CHECK-NEXT: ret i1 [[C]]
;
%A = getelementptr inbounds %S, ptr %P, i16 0, i32 1, i16 %X
%C = icmp eq ptr %A, %P
ret i1 %C
}
define i1 @test13_i128(i128 %X, ptr %P) {
; CHECK-LABEL: @test13_i128(
; CHECK-NEXT: [[TMP1:%.*]] = trunc i128 [[X:%.*]] to i64
; CHECK-NEXT: [[C:%.*]] = icmp eq i64 [[TMP1]], -1
; CHECK-NEXT: ret i1 [[C]]
;
%A = getelementptr inbounds %S, ptr %P, i128 0, i32 1, i128 %X
%C = icmp eq ptr %A, %P
ret i1 %C
}
@G = external global [3 x i8]
define ptr @test14(i32 %idx) {
; CHECK-LABEL: @test14(
; CHECK-NEXT: [[ZEXT:%.*]] = zext i32 [[IDX:%.*]] to i64
; CHECK-NEXT: [[T:%.*]] = getelementptr i8, ptr @G, i64 [[ZEXT]]
; CHECK-NEXT: ret ptr [[T]]
;
%zext = zext i32 %idx to i64
%t = getelementptr i8, ptr @G, i64 %zext
ret ptr %t
}
; Test folding of constantexpr geps into normal geps.
@Array = external global [40 x i32]
define ptr @test15(i64 %X) {
; CHECK-LABEL: @test15(
; CHECK-NEXT: [[A:%.*]] = getelementptr i32, ptr @Array, i64 [[X:%.*]]
; CHECK-NEXT: ret ptr [[A]]
;
%A = getelementptr i32, ptr @Array, i64 %X
ret ptr %A
}
define ptr @test16(ptr %X, i32 %Idx) {
; CHECK-LABEL: @test16(
; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[IDX:%.*]] to i64
; CHECK-NEXT: [[R:%.*]] = getelementptr i32, ptr [[X:%.*]], i64 [[TMP1]]
; CHECK-NEXT: ret ptr [[R]]
;
%R = getelementptr i32, ptr %X, i32 %Idx
ret ptr %R
}
define i1 @test17(ptr %P, i32 %I, i32 %J) {
; CHECK-LABEL: @test17(
; CHECK-NEXT: [[C:%.*]] = icmp slt i32 [[I:%.*]], [[J:%.*]]
; CHECK-NEXT: ret i1 [[C]]
;
%X = getelementptr inbounds i16, ptr %P, i32 %I
%Y = getelementptr inbounds i16, ptr %P, i32 %J
%C = icmp ult ptr %X, %Y
ret i1 %C
}
define i1 @test18(ptr %P, i32 %I) {
; CHECK-LABEL: @test18(
; CHECK-NEXT: [[C:%.*]] = icmp slt i32 [[I:%.*]], 0
; CHECK-NEXT: ret i1 [[C]]
;
%X = getelementptr inbounds i16, ptr %P, i32 %I
%C = icmp ult ptr %X, %P
ret i1 %C
}
; Larger than the pointer size for a non-zero address space
define i1 @test18_as1(ptr addrspace(1) %P, i32 %I) {
; CHECK-LABEL: @test18_as1(
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[I:%.*]], 32768
; CHECK-NEXT: [[C:%.*]] = icmp ne i32 [[TMP1]], 0
; CHECK-NEXT: ret i1 [[C]]
;
%X = getelementptr inbounds i16, ptr addrspace(1) %P, i32 %I
%C = icmp ult ptr addrspace(1) %X, %P
ret i1 %C
}
; Smaller than the pointer size for a non-zero address space
define i1 @test18_as1_i32(ptr addrspace(1) %P, i32 %I) {
; CHECK-LABEL: @test18_as1_i32(
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[I:%.*]], 32768
; CHECK-NEXT: [[C:%.*]] = icmp ne i32 [[TMP1]], 0
; CHECK-NEXT: ret i1 [[C]]
;
%X = getelementptr inbounds i16, ptr addrspace(1) %P, i32 %I
%C = icmp ult ptr addrspace(1) %X, %P
ret i1 %C
}
; Smaller than pointer size
define i1 @test18_i16(ptr %P, i16 %I) {
; CHECK-LABEL: @test18_i16(
; CHECK-NEXT: [[C:%.*]] = icmp slt i16 [[I:%.*]], 0
; CHECK-NEXT: ret i1 [[C]]
;
%X = getelementptr inbounds i16, ptr %P, i16 %I
%C = icmp ult ptr %X, %P
ret i1 %C
}
; Same as pointer size
define i1 @test18_i64(ptr %P, i64 %I) {
; CHECK-LABEL: @test18_i64(
; CHECK-NEXT: [[C:%.*]] = icmp slt i64 [[I:%.*]], 0
; CHECK-NEXT: ret i1 [[C]]
;
%X = getelementptr inbounds i16, ptr %P, i64 %I
%C = icmp ult ptr %X, %P
ret i1 %C
}
; Larger than the pointer size
define i1 @test18_i128(ptr %P, i128 %I) {
; CHECK-LABEL: @test18_i128(
; CHECK-NEXT: [[TMP1:%.*]] = and i128 [[I:%.*]], 9223372036854775808
; CHECK-NEXT: [[C:%.*]] = icmp ne i128 [[TMP1]], 0
; CHECK-NEXT: ret i1 [[C]]
;
%X = getelementptr inbounds i16, ptr %P, i128 %I
%C = icmp ult ptr %X, %P
ret i1 %C
}
define i32 @test19(ptr %P, i32 %A, i32 %B) {
; CHECK-LABEL: @test19(
; CHECK-NEXT: [[T10:%.*]] = icmp eq i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[T11:%.*]] = zext i1 [[T10]] to i32
; CHECK-NEXT: ret i32 [[T11]]
;
%t4 = getelementptr inbounds i32, ptr %P, i32 %A
%t9 = getelementptr inbounds i32, ptr %P, i32 %B
%t10 = icmp eq ptr %t4, %t9
%t11 = zext i1 %t10 to i32
ret i32 %t11
}
define i32 @test20(ptr %P, i32 %A, i32 %B) {
; CHECK-LABEL: @test20(
; CHECK-NEXT: [[T6:%.*]] = icmp eq i32 [[A:%.*]], 0
; CHECK-NEXT: [[T7:%.*]] = zext i1 [[T6]] to i32
; CHECK-NEXT: ret i32 [[T7]]
;
%t4 = getelementptr inbounds i32, ptr %P, i32 %A
%t6 = icmp eq ptr %t4, %P
%t7 = zext i1 %t6 to i32
ret i32 %t7
}
define i32 @test20_as1(ptr addrspace(1) %P, i32 %A, i32 %B) {
; CHECK-LABEL: @test20_as1(
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[A:%.*]] to i16
; CHECK-NEXT: [[T6:%.*]] = icmp eq i16 [[TMP1]], 0
; CHECK-NEXT: [[T7:%.*]] = zext i1 [[T6]] to i32
; CHECK-NEXT: ret i32 [[T7]]
;
%t4 = getelementptr inbounds i32, ptr addrspace(1) %P, i32 %A
%t6 = icmp eq ptr addrspace(1) %t4, %P
%t7 = zext i1 %t6 to i32
ret i32 %t7
}
define i32 @test21() {
; CHECK-LABEL: @test21(
; CHECK-NEXT: [[PBOB1:%.*]] = alloca [[INTSTRUCT:%.*]], align 8
; CHECK-NEXT: [[RVAL:%.*]] = load i32, ptr [[PBOB1]], align 4
; CHECK-NEXT: ret i32 [[RVAL]]
;
%pbob1 = alloca %intstruct
%pbob2 = getelementptr %intstruct, ptr %pbob1
%rval = load i32, ptr %pbob2
ret i32 %rval
}
@A = global i32 1 ; <ptr> [#uses=1]
@B = global i32 2 ; <ptr> [#uses=1]
define i1 @test22() {
; CHECK-LABEL: @test22(
; CHECK-NEXT: ret i1 icmp ult (ptr getelementptr inbounds (i32, ptr @A, i64 1), ptr getelementptr (i32, ptr @B, i64 2))
;
%C = icmp ult ptr getelementptr (i32, ptr @A, i64 1),
getelementptr (i32, ptr @B, i64 2)
ret i1 %C
}
%X = type { [10 x i32], float }
define i1 @test23() {
; CHECK-LABEL: @test23(
; CHECK-NEXT: ret i1 false
;
%A = getelementptr %X, ptr null, i64 0, i32 0, i64 0 ; <ptr> [#uses=1]
%B = icmp ne ptr %A, null ; <i1> [#uses=1]
ret i1 %B
}
define void @test25() {
; CHECK-LABEL: @test25(
; CHECK-NEXT: entry:
; CHECK-NEXT: unreachable
;
entry:
%t = getelementptr { i64, i64, i64, i64 }, ptr null, i32 0, i32 3
%t.upgrd.1 = load i64, ptr %t
%t8.ui = load i64, ptr null
%t8 = bitcast i64 %t8.ui to i64
%t9 = and i64 %t8, %t.upgrd.1
%sext = trunc i64 %t9 to i32
%t27.i = sext i32 %sext to i64
tail call void @foo25( i32 0, i64 %t27.i )
unreachable
}
declare void @foo25(i32, i64)
; PR1637
define i1 @test26(ptr %arr) {
; CHECK-LABEL: @test26(
; CHECK-NEXT: ret i1 true
;
%X = getelementptr i8, ptr %arr, i32 1
%Y = getelementptr i8, ptr %arr, i32 1
%test = icmp uge ptr %X, %Y
ret i1 %test
}
%struct.__large_struct = type { [100 x i64] }
%struct.compat_siginfo = type { i32, i32, i32, { [29 x i32] } }
%struct.siginfo_t = type { i32, i32, i32, { { i32, i32, [0 x i8], %struct.sigval_t, i32 }, [88 x i8] } }
%struct.sigval_t = type { ptr }
define i32 @test27(ptr %to, ptr %from) {
; CHECK-LABEL: @test27(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[FROM_ADDR:%.*]] = alloca ptr, align 8
; CHECK-NEXT: [[T344:%.*]] = load ptr, ptr [[FROM_ADDR]], align 8
; CHECK-NEXT: [[T348:%.*]] = getelementptr [[STRUCT_SIGINFO_T:%.*]], ptr [[T344]], i64 0, i32 3, i32 0, i32 3
; CHECK-NEXT: [[T351:%.*]] = load i32, ptr [[T348]], align 8
; CHECK-NEXT: [[T360:%.*]] = call i32 asm sideeffect "...", "=r,ir,*m,i,0,~{dirflag},~{fpsr},~{flags}"(i32 [[T351]], ptr elementtype([[STRUCT___LARGE_STRUCT:%.*]]) null, i32 -14, i32 0) #[[ATTR0:[0-9]+]]
; CHECK-NEXT: unreachable
;
entry:
%from_addr = alloca ptr
%t344 = load ptr, ptr %from_addr, align 8
%t345 = getelementptr %struct.siginfo_t, ptr %t344, i32 0, i32 3
%t346 = getelementptr { { i32, i32, [0 x i8], %struct.sigval_t, i32 }, [88 x i8] }, ptr %t345, i32 0, i32 0
%t348 = getelementptr { i32, i32, %struct.sigval_t }, ptr %t346, i32 0, i32 2
%t351 = load i32, ptr %t348, align 8
%t360 = call i32 asm sideeffect "...",
"=r,ir,*m,i,0,~{dirflag},~{fpsr},~{flags}"( i32 %t351, ptr elementtype(%struct.__large_struct) null, i32 -14, i32 0 )
unreachable
}
; PR1978
%struct.x = type <{ i8 }>
@.str = internal constant [6 x i8] c"Main!\00"
@.str1 = internal constant [12 x i8] c"destroy %p\0A\00"
define i32 @test28() nounwind {
; CHECK-LABEL: @test28(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[ORIENTATIONS:%.*]] = alloca [1 x [1 x %struct.x]], align 8
; CHECK-NEXT: [[T3:%.*]] = call i32 @puts(ptr noundef nonnull dereferenceable(1) @.str) #[[ATTR0]]
; CHECK-NEXT: br label [[BB10:%.*]]
; CHECK: bb10:
; CHECK-NEXT: [[INDVAR:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INDVAR_NEXT:%.*]], [[BB10]] ]
; CHECK-NEXT: [[T12_REC:%.*]] = xor i32 [[INDVAR]], -1
; CHECK-NEXT: [[TMP0:%.*]] = sext i32 [[T12_REC]] to i64
; CHECK-NEXT: [[T12:%.*]] = getelementptr inbounds [1 x [1 x %struct.x]], ptr [[ORIENTATIONS]], i64 1, i64 0, i64 [[TMP0]]
; CHECK-NEXT: [[T16:%.*]] = call i32 (ptr, ...) @printf(ptr noundef nonnull dereferenceable(1) @.str1, ptr nonnull [[T12]]) #[[ATTR0]]
; CHECK-NEXT: [[T84:%.*]] = icmp eq i32 [[INDVAR]], 0
; CHECK-NEXT: [[INDVAR_NEXT]] = add i32 [[INDVAR]], 1
; CHECK-NEXT: br i1 [[T84]], label [[BB17:%.*]], label [[BB10]]
; CHECK: bb17:
; CHECK-NEXT: ret i32 0
;
entry:
%orientations = alloca [1 x [1 x %struct.x]]
%t3 = call i32 @puts( ptr @.str ) nounwind
%t45 = getelementptr inbounds [1 x [1 x %struct.x]], ptr %orientations, i32 1, i32 0, i32 0
br label %bb10
bb10:
%indvar = phi i32 [ 0, %entry ], [ %indvar.next, %bb10 ]
%t.0.reg2mem.0.rec = mul i32 %indvar, -1
%t12.rec = add i32 %t.0.reg2mem.0.rec, -1
%t12 = getelementptr inbounds %struct.x, ptr %t45, i32 %t12.rec
%t16 = call i32 (ptr, ...) @printf( ptr nonnull dereferenceable(1) @.str1, ptr %t12 ) nounwind
%t84 = icmp eq ptr %t12, %orientations
%indvar.next = add i32 %indvar, 1
br i1 %t84, label %bb17, label %bb10
bb17:
ret i32 0
}
declare i32 @puts(ptr)
declare i32 @printf(ptr, ...)
; rdar://6762290
%T = type <{ i64, i64, i64 }>
define i32 @test29(ptr %start, i32 %X) nounwind {
; CHECK-LABEL: @test29(
; CHECK-NEXT: entry:
; CHECK-NEXT: store i1 true, ptr poison, align 1
; CHECK-NEXT: br i1 poison, label [[IF_THEN216:%.*]], label [[IF_END363:%.*]]
; CHECK: if.then216:
; CHECK-NEXT: ret i32 1
; CHECK: if.end363:
; CHECK-NEXT: ret i32 0
;
entry:
%t3 = load i64, ptr null
%add.ptr = getelementptr i8, ptr %start, i64 %t3
%t158 = load i32, ptr null
%add.ptr159 = getelementptr %T, ptr null, i32 %t158
%add.ptr212 = getelementptr i8, ptr %start, i32 %X
%cmp214 = icmp ugt ptr %add.ptr212, %add.ptr
br i1 %cmp214, label %if.then216, label %if.end363
if.then216:
ret i32 1
if.end363:
ret i32 0
}
; PR3694
define i32 @test30(i32 %m, i32 %n) nounwind {
; CHECK-LABEL: @test30(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[N:%.*]] to i64
; CHECK-NEXT: [[TMP1:%.*]] = alloca i32, i64 [[TMP0]], align 4
; CHECK-NEXT: call void @test30f(ptr nonnull [[TMP1]]) #[[ATTR0]]
; CHECK-NEXT: [[TMP2:%.*]] = sext i32 [[M:%.*]] to i64
; CHECK-NEXT: [[TMP3:%.*]] = getelementptr [0 x i32], ptr [[TMP1]], i64 0, i64 [[TMP2]]
; CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[TMP3]], align 4
; CHECK-NEXT: ret i32 [[TMP4]]
;
entry:
%0 = alloca i32, i32 %n, align 4
call void @test30f(ptr %0) nounwind
%1 = getelementptr [0 x i32], ptr %0, i32 0, i32 %m
%2 = load i32, ptr %1, align 4
ret i32 %2
}
declare void @test30f(ptr)
define i1 @test31(ptr %A) {
; CHECK-LABEL: @test31(
; CHECK-NEXT: ret i1 true
;
%B = getelementptr i32, ptr %A, i32 1
%C = getelementptr i32, ptr %A, i64 1
%V = icmp eq ptr %B, %C
ret i1 %V
}
; PR1345
define ptr @test32(ptr %v) {
; CHECK-LABEL: @test32(
; CHECK-NEXT: [[A:%.*]] = alloca [4 x ptr], align 16
; CHECK-NEXT: store ptr null, ptr [[A]], align 8
; CHECK-NEXT: [[D:%.*]] = getelementptr inbounds { [16 x i8] }, ptr [[A]], i64 0, i32 0, i64 8
; CHECK-NEXT: store ptr [[V:%.*]], ptr [[D]], align 8
; CHECK-NEXT: [[F:%.*]] = getelementptr inbounds [4 x ptr], ptr [[A]], i64 0, i64 2
; CHECK-NEXT: [[G:%.*]] = load ptr, ptr [[F]], align 8
; CHECK-NEXT: ret ptr [[G]]
;
%A = alloca [4 x ptr], align 16
store ptr null, ptr %A
%D = getelementptr { [16 x i8] }, ptr %A, i32 0, i32 0, i32 8
store ptr %v, ptr %D
%F = getelementptr [4 x ptr], ptr %A, i32 0, i32 2
%G = load ptr, ptr %F
ret ptr %G
}
; PR3290
%struct.Key = type { { i32, i32 } }
%struct.anon = type <{ i8, [3 x i8], i32 }>
define ptr @test33(ptr %A) {
; CHECK-LABEL: @test33(
; CHECK-NEXT: [[C:%.*]] = getelementptr [[STRUCT_ANON:%.*]], ptr [[A:%.*]], i64 0, i32 2
; CHECK-NEXT: ret ptr [[C]]
;
%C = getelementptr %struct.anon, ptr %A, i32 0, i32 2
ret ptr %C
}
define ptr addrspace(1) @test33_as1(ptr addrspace(1) %A) {
; CHECK-LABEL: @test33_as1(
; CHECK-NEXT: [[C:%.*]] = getelementptr [[STRUCT_ANON:%.*]], ptr addrspace(1) [[A:%.*]], i16 0, i32 2
; CHECK-NEXT: ret ptr addrspace(1) [[C]]
;
%C = getelementptr %struct.anon, ptr addrspace(1) %A, i32 0, i32 2
ret ptr addrspace(1) %C
}
define ptr addrspace(1) @test33_array_as1(ptr addrspace(1) %A) {
; CHECK-LABEL: @test33_array_as1(
; CHECK-NEXT: [[C:%.*]] = getelementptr [5 x i32], ptr addrspace(1) [[A:%.*]], i16 0, i16 2
; CHECK-NEXT: ret ptr addrspace(1) [[C]]
;
%C = getelementptr [5 x i32], ptr addrspace(1) %A, i32 0, i32 2
ret ptr addrspace(1) %C
}
; Make sure the GEP indices use the right pointer sized integer
define ptr addrspace(1) @test33_array_struct_as1(ptr addrspace(1) %A) {
; CHECK-LABEL: @test33_array_struct_as1(
; CHECK-NEXT: [[C:%.*]] = getelementptr [20 x i32], ptr addrspace(1) [[A:%.*]], i16 0, i16 2
; CHECK-NEXT: ret ptr addrspace(1) [[C]]
;
%C = getelementptr [20 x i32], ptr addrspace(1) %A, i32 0, i32 2
ret ptr addrspace(1) %C
}
define ptr addrspace(1) @test33_addrspacecast(ptr %A) {
; CHECK-LABEL: @test33_addrspacecast(
; CHECK-NEXT: [[B:%.*]] = addrspacecast ptr [[A:%.*]] to ptr addrspace(1)
; CHECK-NEXT: [[C:%.*]] = getelementptr [[STRUCT_ANON:%.*]], ptr addrspace(1) [[B]], i16 0, i32 2
; CHECK-NEXT: ret ptr addrspace(1) [[C]]
;
%B = addrspacecast ptr %A to ptr addrspace(1)
%C = getelementptr %struct.anon, ptr addrspace(1) %B, i32 0, i32 2
ret ptr addrspace(1) %C
}
%T2 = type { ptr, i8 }
define ptr @test34(ptr %Val, i64 %V) nounwind {
; CHECK-LABEL: @test34(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[C_CAST:%.*]] = inttoptr i64 [[V:%.*]] to ptr
; CHECK-NEXT: ret ptr [[C_CAST]]
;
entry:
%A = alloca %T2, align 8
store i64 %V, ptr %A
%C = load ptr, ptr %A, align 8
ret ptr %C
}
%t0 = type { ptr, [19 x i8] }
%t1 = type { ptr, [0 x i8] }
@array = external global [11 x i8]
@s = external global %t0
@"\01LC8" = external constant [17 x i8]
; Instcombine should be able to fold this getelementptr.
define i32 @test35() nounwind {
; CHECK-LABEL: @test35(
; CHECK-NEXT: [[TMP1:%.*]] = call i32 (ptr, ...) @printf(ptr noundef nonnull dereferenceable(1) @"\01LC8", ptr nonnull getelementptr inbounds ([[T0:%.*]], ptr @s, i64 0, i32 1, i64 0)) #[[ATTR0]]
; CHECK-NEXT: ret i32 0
;
call i32 (ptr, ...) @printf(ptr @"\01LC8",
ptr getelementptr (%t1, ptr @s, i32 0, i32 1, i32 0)) nounwind
ret i32 0
}
; Don't treat signed offsets as unsigned.
define ptr @test36() nounwind {
; CHECK-LABEL: @test36(
; CHECK-NEXT: ret ptr getelementptr ([11 x i8], ptr @array, i64 -1, i64 10)
;
ret ptr getelementptr ([11 x i8], ptr @array, i32 0, i64 -1)
}
; Instcombine shouldn't assume that gep(A,0,1) != gep(A,1,0).
@A37 = external constant [1 x i8]
define i1 @test37() nounwind {
; CHECK-LABEL: @test37(
; CHECK-NEXT: ret i1 true
;
%t = icmp eq ptr getelementptr ([1 x i8], ptr @A37, i64 0, i64 1),
getelementptr ([1 x i8], ptr @A37, i64 1, i64 0)
ret i1 %t
}
; Test index promotion
define ptr @test38(ptr %I, i32 %n) {
; CHECK-LABEL: @test38(
; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[N:%.*]] to i64
; CHECK-NEXT: [[A:%.*]] = getelementptr i32, ptr [[I:%.*]], i64 [[TMP1]]
; CHECK-NEXT: ret ptr [[A]]
;
%A = getelementptr i32, ptr %I, i32 %n
ret ptr %A
}
; Test that we don't duplicate work when the second gep is a "bitcast".
%pr10322_t = type { ptr }
declare void @pr10322_f2(ptr)
declare void @pr10322_f3(ptr)
define void @pr10322_f1(ptr %foo) {
; CHECK-LABEL: @pr10322_f1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[ARRAYIDX8:%.*]] = getelementptr inbounds [[PR10322_T:%.*]], ptr [[FOO:%.*]], i64 2
; CHECK-NEXT: call void @pr10322_f2(ptr nonnull [[ARRAYIDX8]]) #[[ATTR0]]
; CHECK-NEXT: call void @pr10322_f3(ptr nonnull [[ARRAYIDX8]]) #[[ATTR0]]
; CHECK-NEXT: ret void
;
entry:
%arrayidx8 = getelementptr inbounds %pr10322_t, ptr %foo, i64 2
call void @pr10322_f2(ptr %arrayidx8) nounwind
call void @pr10322_f3(ptr %arrayidx8) nounwind
ret void
}
; Test that we combine the last two geps in this sequence, before we
; would wait for gep1 and gep2 to be combined and never combine 2 and 3.
%three_gep_t = type {i32}
%three_gep_t2 = type {%three_gep_t}
define void @three_gep_f(ptr %x) {
; CHECK-LABEL: @three_gep_f(
; CHECK-NEXT: [[GEP1:%.*]] = getelementptr [[THREE_GEP_T2:%.*]], ptr [[X:%.*]], i64 2
; CHECK-NEXT: call void @three_gep_h(ptr [[GEP1]])
; CHECK-NEXT: call void @three_gep_g(ptr [[GEP1]])
; CHECK-NEXT: ret void
;
%gep1 = getelementptr %three_gep_t2, ptr %x, i64 2
call void @three_gep_h(ptr %gep1)
call void @three_gep_g(ptr %gep1)
ret void
}
declare void @three_gep_g(ptr)
declare void @three_gep_h(ptr)
%struct.ham = type { i32, ptr, ptr, ptr }
%struct.zot = type { i64, i8 }
define void @test39(ptr %arg, i8 %arg1) nounwind {
; CHECK-LABEL: @test39(
; CHECK-NEXT: [[T:%.*]] = getelementptr inbounds [[STRUCT_HAM:%.*]], ptr [[ARG:%.*]], i64 0, i32 2
; CHECK-NEXT: [[T2:%.*]] = load ptr, ptr [[T]], align 8
; CHECK-NEXT: [[T4:%.*]] = getelementptr inbounds i8, ptr [[T2]], i64 -8
; CHECK-NEXT: store i8 [[ARG1:%.*]], ptr [[T4]], align 8
; CHECK-NEXT: ret void
;
%t = getelementptr inbounds %struct.ham, ptr %arg, i64 0, i32 2
%t2 = load ptr, ptr %t, align 8
%t4 = getelementptr inbounds i8, ptr %t2, i64 -8
store i8 %arg1, ptr %t4, align 8
ret void
}
define i1 @pr16483(ptr %a, ptr %b) {
; CHECK-LABEL: @pr16483(
; CHECK-NEXT: [[CMP:%.*]] = icmp ult ptr [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: ret i1 [[CMP]]
;
%cmp = icmp ult ptr %a, %b
ret i1 %cmp
}
define i8 @test_gep_bitcast_as1(ptr addrspace(1) %arr, i16 %N) {
; CHECK-LABEL: @test_gep_bitcast_as1(
; CHECK-NEXT: [[V:%.*]] = shl i16 [[N:%.*]], 2
; CHECK-NEXT: [[T:%.*]] = getelementptr i8, ptr addrspace(1) [[ARR:%.*]], i16 [[V]]
; CHECK-NEXT: [[X:%.*]] = load i8, ptr addrspace(1) [[T]], align 1
; CHECK-NEXT: ret i8 [[X]]
;
%V = mul i16 %N, 4
%t = getelementptr i8, ptr addrspace(1) %arr, i16 %V
%x = load i8, ptr addrspace(1) %t
ret i8 %x
}
; The element size of the array matches the element size of the pointer
define i64 @test_gep_bitcast_array_same_size_element(ptr %arr, i64 %N) {
; CHECK-LABEL: @test_gep_bitcast_array_same_size_element(
; CHECK-NEXT: [[V:%.*]] = shl i64 [[N:%.*]], 3
; CHECK-NEXT: [[T:%.*]] = getelementptr i64, ptr [[ARR:%.*]], i64 [[V]]
; CHECK-NEXT: [[X:%.*]] = load i64, ptr [[T]], align 4
; CHECK-NEXT: ret i64 [[X]]
;
%V = mul i64 %N, 8
%t = getelementptr i64, ptr %arr, i64 %V
%x = load i64, ptr %t
ret i64 %x
}
; gep should be done in the original address space.
define i64 @test_gep_bitcast_array_same_size_element_addrspacecast(ptr %arr, i64 %N) {
; CHECK-LABEL: @test_gep_bitcast_array_same_size_element_addrspacecast(
; CHECK-NEXT: [[CAST:%.*]] = addrspacecast ptr [[ARR:%.*]] to ptr addrspace(3)
; CHECK-NEXT: [[V:%.*]] = shl i64 [[N:%.*]], 3
; CHECK-NEXT: [[T:%.*]] = getelementptr i64, ptr addrspace(3) [[CAST]], i64 [[V]]
; CHECK-NEXT: [[X:%.*]] = load i64, ptr addrspace(3) [[T]], align 4
; CHECK-NEXT: ret i64 [[X]]
;
%cast = addrspacecast ptr %arr to ptr addrspace(3)
%V = mul i64 %N, 8
%t = getelementptr i64, ptr addrspace(3) %cast, i64 %V
%x = load i64, ptr addrspace(3) %t
ret i64 %x
}
; The element size of the array is different the element size of the pointer
define i8 @test_gep_bitcast_array_different_size_element(ptr %arr, i64 %N) {
; CHECK-LABEL: @test_gep_bitcast_array_different_size_element(
; CHECK-NEXT: [[V:%.*]] = shl i64 [[N:%.*]], 3
; CHECK-NEXT: [[T:%.*]] = getelementptr i8, ptr [[ARR:%.*]], i64 [[V]]
; CHECK-NEXT: [[X:%.*]] = load i8, ptr [[T]], align 1
; CHECK-NEXT: ret i8 [[X]]
;
%V = mul i64 %N, 8
%t = getelementptr i8, ptr %arr, i64 %V
%x = load i8, ptr %t
ret i8 %x
}
define i64 @test_gep_bitcast_array_same_size_element_as1(ptr addrspace(1) %arr, i16 %N) {
; CHECK-LABEL: @test_gep_bitcast_array_same_size_element_as1(
; CHECK-NEXT: [[V:%.*]] = shl i16 [[N:%.*]], 3
; CHECK-NEXT: [[T:%.*]] = getelementptr i64, ptr addrspace(1) [[ARR:%.*]], i16 [[V]]
; CHECK-NEXT: [[X:%.*]] = load i64, ptr addrspace(1) [[T]], align 4
; CHECK-NEXT: ret i64 [[X]]
;
%V = mul i16 %N, 8
%t = getelementptr i64, ptr addrspace(1) %arr, i16 %V
%x = load i64, ptr addrspace(1) %t
ret i64 %x
}
define i8 @test_gep_bitcast_array_different_size_element_as1(ptr addrspace(1) %arr, i16 %N) {
; CHECK-LABEL: @test_gep_bitcast_array_different_size_element_as1(
; CHECK-NEXT: [[V:%.*]] = shl i16 [[N:%.*]], 3
; CHECK-NEXT: [[T:%.*]] = getelementptr i8, ptr addrspace(1) [[ARR:%.*]], i16 [[V]]
; CHECK-NEXT: [[X:%.*]] = load i8, ptr addrspace(1) [[T]], align 1
; CHECK-NEXT: ret i8 [[X]]
;
%V = mul i16 %N, 8
%t = getelementptr i8, ptr addrspace(1) %arr, i16 %V
%x = load i8, ptr addrspace(1) %t
ret i8 %x
}
define i64 @test40() {
; CHECK-LABEL: @test40(
; CHECK-NEXT: ret i64 8
;
%array = alloca [3 x i32], align 4
%gep = getelementptr inbounds [3 x i32], ptr %array, i64 0, i64 2
%p = ptrtoint ptr %array to i64
%np = sub i64 0, %p
%gep2 = getelementptr i8, ptr %gep, i64 %np
%ret = ptrtoint ptr %gep2 to i64
ret i64 %ret
}
define i16 @test41(ptr addrspace(1) %array) {
; CHECK-LABEL: @test41(
; CHECK-NEXT: ret i16 8
;
%gep = getelementptr inbounds [3 x i32], ptr addrspace(1) %array, i16 0, i16 2
%p = ptrtoint ptr addrspace(1) %array to i16
%np = sub i16 0, %p
%gep2 = getelementptr i8, ptr addrspace(1) %gep, i16 %np
%ret = ptrtoint ptr addrspace(1) %gep2 to i16
ret i16 %ret
}
define ptr @test42i(ptr %c1, ptr %c2) {
; CHECK-LABEL: @test42i(
; CHECK-NEXT: [[PTRTOINT:%.*]] = ptrtoint ptr [[C1:%.*]] to i64
; CHECK-NEXT: [[SUB:%.*]] = sub i64 0, [[PTRTOINT]]
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[C2:%.*]], i64 [[SUB]]
; CHECK-NEXT: ret ptr [[GEP]]
;
%ptrtoint = ptrtoint ptr %c1 to i64
%sub = sub i64 0, %ptrtoint
%gep = getelementptr inbounds i8, ptr %c2, i64 %sub
ret ptr %gep
}
define ptr @test42(ptr %c1, ptr %c2) {
; CHECK-LABEL: @test42(
; CHECK-NEXT: [[PTRTOINT:%.*]] = ptrtoint ptr [[C1:%.*]] to i64
; CHECK-NEXT: [[SUB:%.*]] = sub i64 0, [[PTRTOINT]]
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[C2:%.*]], i64 [[SUB]]
; CHECK-NEXT: ret ptr [[GEP]]
;
%ptrtoint = ptrtoint ptr %c1 to i64
%sub = sub i64 0, %ptrtoint
%gep = getelementptr i8, ptr %c2, i64 %sub
ret ptr %gep
}
define ptr @test43i(ptr %c1, ptr %c2) {
; CHECK-LABEL: @test43i(
; CHECK-NEXT: [[PTRTOINT:%.*]] = ptrtoint ptr [[C1:%.*]] to i64
; CHECK-NEXT: [[SUB:%.*]] = sub i64 0, [[PTRTOINT]]
; CHECK-NEXT: [[SHR:%.*]] = ashr i64 [[SUB]], 1
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i16, ptr [[C2:%.*]], i64 [[SHR]]
; CHECK-NEXT: ret ptr [[GEP]]
;
%ptrtoint = ptrtoint ptr %c1 to i64
%sub = sub i64 0, %ptrtoint
%shr = ashr i64 %sub, 1
%gep = getelementptr inbounds i16, ptr %c2, i64 %shr
ret ptr %gep
}
define ptr @test44i(ptr %c1, ptr %c2) {
; CHECK-LABEL: @test44i(
; CHECK-NEXT: [[PTRTOINT:%.*]] = ptrtoint ptr [[C1:%.*]] to i64
; CHECK-NEXT: [[SUB:%.*]] = sub i64 0, [[PTRTOINT]]
; CHECK-NEXT: [[SHR:%.*]] = sdiv i64 [[SUB]], 7
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[C2:%.*]], i64 [[SHR]]
; CHECK-NEXT: ret ptr [[GEP]]
;
%ptrtoint = ptrtoint ptr %c1 to i64
%sub = sub i64 0, %ptrtoint
%shr = sdiv i64 %sub, 7
%gep = getelementptr inbounds %struct.C, ptr %c2, i64 %shr
ret ptr %gep
}
define ptr @test45(ptr %c1, ptr %c2) {
; CHECK-LABEL: @test45(
; CHECK-NEXT: [[PTRTOINT1:%.*]] = ptrtoint ptr [[C1:%.*]] to i64
; CHECK-NEXT: [[PTRTOINT2:%.*]] = ptrtoint ptr [[C2:%.*]] to i64
; CHECK-NEXT: [[SUB:%.*]] = sub i64 [[PTRTOINT2]], [[PTRTOINT1]]
; CHECK-NEXT: [[SHR:%.*]] = sdiv i64 [[SUB]], 7
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[C1]], i64 [[SHR]]
; CHECK-NEXT: ret ptr [[GEP]]
;
%ptrtoint1 = ptrtoint ptr %c1 to i64
%ptrtoint2 = ptrtoint ptr %c2 to i64
%sub = sub i64 %ptrtoint2, %ptrtoint1 ; C2 - C1
%shr = sdiv i64 %sub, 7
%gep = getelementptr inbounds %struct.C, ptr %c1, i64 %shr ; C1 + (C2 - C1)
ret ptr %gep
}
define ptr @test46(ptr %c1, ptr %c2, i64 %N) {
; CHECK-LABEL: @test46(
; CHECK-NEXT: [[PTRTOINT:%.*]] = ptrtoint ptr [[C1:%.*]] to i64
; CHECK-NEXT: [[SUB:%.*]] = sub i64 0, [[PTRTOINT]]
; CHECK-NEXT: [[SDIV:%.*]] = sdiv i64 [[SUB]], [[N:%.*]]
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[C2:%.*]], i64 [[SDIV]]
; CHECK-NEXT: ret ptr [[GEP]]
;
%ptrtoint = ptrtoint ptr %c1 to i64
%sub = sub i64 0, %ptrtoint
%sdiv = sdiv i64 %sub, %N
%gep = getelementptr inbounds %struct.C, ptr %c2, i64 %sdiv
ret ptr %gep
}
define ptr @test47(ptr %I, i64 %C, i64 %D) {
; CHECK-LABEL: @test47(
; CHECK-NEXT: [[B:%.*]] = getelementptr i32, ptr [[I:%.*]], i64 [[D:%.*]]
; CHECK-NEXT: ret ptr [[B]]
;
%sub = sub i64 %D, %C
%A = getelementptr i32, ptr %I, i64 %C
%B = getelementptr i32, ptr %A, i64 %sub
ret ptr %B
}
define ptr @test48(ptr %I, i64 %C, i64 %D) {
; CHECK-LABEL: @test48(
; CHECK-NEXT: [[B:%.*]] = getelementptr i32, ptr [[I:%.*]], i64 [[D:%.*]]
; CHECK-NEXT: ret ptr [[B]]
;
%sub = sub i64 %D, %C
%A = getelementptr i32, ptr %I, i64 %sub
%B = getelementptr i32, ptr %A, i64 %C
ret ptr %B
}
define ptr @test49(ptr %I, i64 %C) {
; CHECK-LABEL: @test49(
; CHECK-NEXT: [[B:%.*]] = getelementptr i32, ptr [[I:%.*]], i64 -1
; CHECK-NEXT: ret ptr [[B]]
;
%notC = xor i64 -1, %C
%A = getelementptr i32, ptr %I, i64 %C
%B = getelementptr i32, ptr %A, i64 %notC
ret ptr %B
}
define ptr addrspace(1) @ascast_0_gep(ptr %p) nounwind {
; CHECK-LABEL: @ascast_0_gep(
; CHECK-NEXT: [[X:%.*]] = addrspacecast ptr [[P:%.*]] to ptr addrspace(1)
; CHECK-NEXT: ret ptr addrspace(1) [[X]]
;
%x = addrspacecast ptr %p to ptr addrspace(1)
ret ptr addrspace(1) %x
}
; Do not merge the GEP and the addrspacecast, because it would undo the
; addrspacecast canonicalization.
define ptr addrspace(1) @ascast_0_0_gep(ptr %p) nounwind {
; CHECK-LABEL: @ascast_0_0_gep(
; CHECK-NEXT: [[X:%.*]] = addrspacecast ptr [[P:%.*]] to ptr addrspace(1)
; CHECK-NEXT: ret ptr addrspace(1) [[X]]
;
%x = addrspacecast ptr %p to ptr addrspace(1)
ret ptr addrspace(1) %x
}
define <2 x ptr> @PR32414(ptr %ptr) {
; CHECK-LABEL: @PR32414(
; CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds i32, ptr [[PTR:%.*]], <2 x i64> <i64 0, i64 1>
; CHECK-NEXT: ret <2 x ptr> [[T1]]
;
%t1 = getelementptr inbounds i32, ptr %ptr, <2 x i64> <i64 0, i64 1>
ret <2 x ptr> %t1
}
define ptr @test_bitcast_nzgep(ptr %base, i64 %idx) {
; CHECK-LABEL: @test_bitcast_nzgep(
; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds i32, ptr [[BASE:%.*]], i64 [[IDX:%.*]]
; CHECK-NEXT: ret ptr [[PTR]]
;
%ptr = getelementptr inbounds i32, ptr %base, i64 %idx
ret ptr %ptr
}
define ptr @test_zgep_nzgep(ptr %base, i64 %idx) {
; CHECK-LABEL: @test_zgep_nzgep(
; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds i32, ptr [[BASE:%.*]], i64 [[IDX:%.*]]
; CHECK-NEXT: ret ptr [[PTR]]
;
%ptr = getelementptr inbounds i32, ptr %base, i64 %idx
ret ptr %ptr
}
define ptr @test_nzgep_zgep(ptr %base, i64 %idx) {
; CHECK-LABEL: @test_nzgep_zgep(
; CHECK-NEXT: [[BASE2:%.*]] = getelementptr inbounds [1 x i32], ptr [[BASE:%.*]], i64 [[IDX:%.*]]
; CHECK-NEXT: ret ptr [[BASE2]]
;
%base2 = getelementptr inbounds [1 x i32], ptr %base, i64 %idx
ret ptr %base2
}
define ptr @test_gep_inbounds_of_gep(ptr %base) {
; CHECK-LABEL: @test_gep_inbounds_of_gep(
; CHECK-NEXT: [[PTR2:%.*]] = getelementptr i32, ptr [[BASE:%.*]], i64 8
; CHECK-NEXT: ret ptr [[PTR2]]
;
%ptr1 = getelementptr i32, ptr %base, i64 4
%ptr2 = getelementptr inbounds i32, ptr %ptr1, i64 4
ret ptr %ptr2
}
%struct.f = type { i32 }
@g0 = internal unnamed_addr constant %struct.f zeroinitializer, align 4
@g1 = internal unnamed_addr constant %struct.f { i32 -1 }, align 4
define ptr @PR45084(i1 %cond) {
; CHECK-LABEL: @PR45084(
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND:%.*]], ptr @g0, ptr @g1, !prof [[PROF0:![0-9]+]]
; CHECK-NEXT: ret ptr [[SEL]]
;
%sel = select i1 %cond, ptr @g0, ptr @g1, !prof !0
ret ptr %sel
}
define ptr @PR45084_extra_use(i1 %cond, ptr %p) {
; CHECK-LABEL: @PR45084_extra_use(
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND:%.*]], ptr @g0, ptr @g1
; CHECK-NEXT: store ptr [[SEL]], ptr [[P:%.*]], align 8
; CHECK-NEXT: ret ptr [[SEL]]
;
%sel = select i1 %cond, ptr @g0, ptr @g1
store ptr %sel, ptr %p
ret ptr %sel
}
define ptr @gep_null_inbounds(i64 %idx) {
; CHECK-LABEL: @gep_null_inbounds(
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr null, i64 [[IDX:%.*]]
; CHECK-NEXT: ret ptr [[GEP]]
;
%gep = getelementptr inbounds i8, ptr null, i64 %idx
ret ptr %gep
}
define ptr @gep_null_not_inbounds(i64 %idx) {
; CHECK-LABEL: @gep_null_not_inbounds(
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr null, i64 [[IDX:%.*]]
; CHECK-NEXT: ret ptr [[GEP]]
;
%gep = getelementptr i8, ptr null, i64 %idx
ret ptr %gep
}
define ptr @gep_null_defined(i64 %idx) null_pointer_is_valid {
; CHECK-LABEL: @gep_null_defined(
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr null, i64 [[IDX:%.*]]
; CHECK-NEXT: ret ptr [[GEP]]
;
%gep = getelementptr inbounds i8, ptr null, i64 %idx
ret ptr %gep
}
define ptr @gep_null_inbounds_different_type(i64 %idx1, i64 %idx2) {
; CHECK-LABEL: @gep_null_inbounds_different_type(
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [0 x i8], ptr null, i64 0, i64 [[IDX2:%.*]]
; CHECK-NEXT: ret ptr [[GEP]]
;
%gep = getelementptr inbounds [0 x i8], ptr null, i64 %idx1, i64 %idx2
ret ptr %gep
}
define ptr @D98588(ptr %c1, i64 %offset) {
; CHECK-LABEL: @D98588(
; CHECK-NEXT: [[C2_NEXT_IDX:%.*]] = shl nsw i64 [[OFFSET:%.*]], 3
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[C1:%.*]], i64 [[C2_NEXT_IDX]]
; CHECK-NEXT: ret ptr [[GEP]]
;
%c2_next = getelementptr inbounds i64, ptr %c1, i64 %offset
%ptrtoint1 = ptrtoint ptr %c1 to i64
%ptrtoint2 = ptrtoint ptr %c2_next to i64
%sub = sub i64 %ptrtoint2, %ptrtoint1 ; C2 - C1
%gep = getelementptr inbounds i8, ptr %c1, i64 %sub ; C1 + (C2 - C1)
ret ptr %gep
}
declare noalias ptr @malloc(i64) nounwind allockind("alloc,uninitialized") allocsize(0)
define i32 @test_gep_bitcast_malloc(ptr %a) {
; CHECK-LABEL: @test_gep_bitcast_malloc(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CALL:%.*]] = call noalias dereferenceable_or_null(16) ptr @malloc(i64 16)
; CHECK-NEXT: [[G3:%.*]] = getelementptr [[STRUCT_A:%.*]], ptr [[CALL]], i64 0, i32 2
; CHECK-NEXT: [[A_C:%.*]] = load i32, ptr [[G3]], align 4
; CHECK-NEXT: ret i32 [[A_C]]
;
entry:
%call = call noalias ptr @malloc(i64 16) #2
%g3 = getelementptr %struct.A, ptr %call, i32 0, i32 2
%a_c = load i32, ptr %g3, align 4
ret i32 %a_c
}
define ptr @gep_of_gep_multiuse_const_and_const(ptr %p, i64 %idx) {
; CHECK-LABEL: @gep_of_gep_multiuse_const_and_const(
; CHECK-NEXT: [[GEP1:%.*]] = getelementptr { i32, i32 }, ptr [[P:%.*]], i64 1
; CHECK-NEXT: call void @use(ptr [[GEP1]])
; CHECK-NEXT: [[GEP2:%.*]] = getelementptr { i32, i32 }, ptr [[P]], i64 1, i32 1
; CHECK-NEXT: ret ptr [[GEP2]]
;
%gep1 = getelementptr { i32, i32 }, ptr %p, i64 1
call void @use(ptr %gep1)
%gep2 = getelementptr { i32, i32 }, ptr %gep1, i64 0, i32 1
ret ptr %gep2
}
define ptr @gep_of_gep_multiuse_var_and_const(ptr %p, i64 %idx) {
; CHECK-LABEL: @gep_of_gep_multiuse_var_and_const(
; CHECK-NEXT: [[GEP1:%.*]] = getelementptr { i32, i32 }, ptr [[P:%.*]], i64 [[IDX:%.*]]
; CHECK-NEXT: call void @use(ptr [[GEP1]])
; CHECK-NEXT: [[GEP2:%.*]] = getelementptr { i32, i32 }, ptr [[P]], i64 [[IDX]], i32 1
; CHECK-NEXT: ret ptr [[GEP2]]
;
%gep1 = getelementptr { i32, i32 }, ptr %p, i64 %idx
call void @use(ptr %gep1)
%gep2 = getelementptr { i32, i32 }, ptr %gep1, i64 0, i32 1
ret ptr %gep2
}
define ptr @gep_of_gep_multiuse_var_and_var(ptr %p, i64 %idx, i64 %idx2) {
; CHECK-LABEL: @gep_of_gep_multiuse_var_and_var(
; CHECK-NEXT: [[GEP1:%.*]] = getelementptr [4 x i32], ptr [[P:%.*]], i64 [[IDX:%.*]]
; CHECK-NEXT: call void @use(ptr [[GEP1]])
; CHECK-NEXT: [[GEP2:%.*]] = getelementptr [4 x i32], ptr [[P]], i64 [[IDX]], i64 [[IDX2:%.*]]
; CHECK-NEXT: ret ptr [[GEP2]]
;
%gep1 = getelementptr [4 x i32], ptr %p, i64 %idx
call void @use(ptr %gep1)
%gep2 = getelementptr [4 x i32], ptr %gep1, i64 0, i64 %idx2
ret ptr %gep2
}
@g_i32_di = global i32 0
@g_i32_e = external global i32
@g_i32_ew = extern_weak global i32
@g_0xi8_e = external global [0 x i8]
define ptr @const_gep_global_di_i8_smaller() {
; CHECK-LABEL: @const_gep_global_di_i8_smaller(
; CHECK-NEXT: ret ptr getelementptr (i8, ptr @g_i32_di, i64 3)
;
ret ptr getelementptr (i8, ptr @g_i32_di, i64 3)
}
define ptr @const_gep_global_di_i8_exact() {
; CHECK-LABEL: @const_gep_global_di_i8_exact(
; CHECK-NEXT: ret ptr getelementptr inbounds (i32, ptr @g_i32_di, i64 1)
;
ret ptr getelementptr (i8, ptr @g_i32_di, i64 4)
}
define ptr @const_gep_global_di_i8_larger() {
; CHECK-LABEL: @const_gep_global_di_i8_larger(
; CHECK-NEXT: ret ptr getelementptr (i8, ptr @g_i32_di, i64 5)
;
ret ptr getelementptr (i8, ptr @g_i32_di, i64 5)
}
define ptr @const_gep_global_di_i64_larger() {
; CHECK-LABEL: @const_gep_global_di_i64_larger(
; CHECK-NEXT: ret ptr getelementptr (i32, ptr @g_i32_di, i64 2)
;
ret ptr getelementptr (i64, ptr @g_i32_di, i64 1)
}
define ptr @const_gep_global_e_smaller() {
; CHECK-LABEL: @const_gep_global_e_smaller(
; CHECK-NEXT: ret ptr getelementptr (i8, ptr @g_i32_e, i64 3)
;
ret ptr getelementptr (i8, ptr @g_i32_e, i64 3)
}
define ptr @const_gep_global_e_exact() {
; CHECK-LABEL: @const_gep_global_e_exact(
; CHECK-NEXT: ret ptr getelementptr inbounds (i32, ptr @g_i32_e, i64 1)
;
ret ptr getelementptr (i8, ptr @g_i32_e, i64 4)
}
define ptr @const_gep_global_e_larger() {
; CHECK-LABEL: @const_gep_global_e_larger(
; CHECK-NEXT: ret ptr getelementptr (i8, ptr @g_i32_e, i64 5)
;
ret ptr getelementptr (i8, ptr @g_i32_e, i64 5)
}
define ptr @const_gep_global_ew_smaller() {
; CHECK-LABEL: @const_gep_global_ew_smaller(
; CHECK-NEXT: ret ptr getelementptr (i8, ptr @g_i32_ew, i64 3)
;
ret ptr getelementptr (i8, ptr @g_i32_ew, i64 3)
}
define ptr @const_gep_global_ew_exact() {
; CHECK-LABEL: @const_gep_global_ew_exact(
; CHECK-NEXT: ret ptr getelementptr (i32, ptr @g_i32_ew, i64 1)
;
ret ptr getelementptr (i8, ptr @g_i32_ew, i64 4)
}
define ptr @const_gep_global_ew_larger() {
; CHECK-LABEL: @const_gep_global_ew_larger(
; CHECK-NEXT: ret ptr getelementptr (i8, ptr @g_i32_ew, i64 5)
;
ret ptr getelementptr (i8, ptr @g_i32_ew, i64 5)
}
define ptr @const_gep_0xi8_global() {
; CHECK-LABEL: @const_gep_0xi8_global(
; CHECK-NEXT: ret ptr getelementptr ([0 x i8], ptr @g_0xi8_e, i64 0, i64 10)
;
ret ptr getelementptr ([0 x i8], ptr @g_0xi8_e, i64 0, i64 10)
}
define ptr @const_gep_chain(ptr %p, i64 %a) {
; CHECK-LABEL: @const_gep_chain(
; CHECK-NEXT: [[P1:%.*]] = getelementptr inbounds i8, ptr [[P:%.*]], i64 [[A:%.*]]
; CHECK-NEXT: [[P4:%.*]] = getelementptr inbounds i8, ptr [[P1]], i64 6
; CHECK-NEXT: ret ptr [[P4]]
;
%p1 = getelementptr inbounds i8, ptr %p, i64 %a
%p2 = getelementptr inbounds i8, ptr %p1, i64 1
%p3 = getelementptr inbounds i8, ptr %p2, i64 2
%p4 = getelementptr inbounds i8, ptr %p3, i64 3
ret ptr %p4
}
!0 = !{!"branch_weights", i32 2, i32 10}