| ; 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:64-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-p2:32:32" |
| |
| define i64 @test_inbounds(ptr %base, i64 %idx) { |
| ; CHECK-LABEL: @test_inbounds( |
| ; CHECK-NEXT: [[P2_IDX:%.*]] = shl nsw i64 [[IDX:%.*]], 2 |
| ; CHECK-NEXT: ret i64 [[P2_IDX]] |
| ; |
| %p2 = getelementptr inbounds [0 x i32], ptr %base, i64 0, i64 %idx |
| %i1 = ptrtoint ptr %base to i64 |
| %i2 = ptrtoint ptr %p2 to i64 |
| %d = sub i64 %i2, %i1 |
| ret i64 %d |
| } |
| |
| define i64 @test_partial_inbounds1(ptr %base, i64 %idx) { |
| ; CHECK-LABEL: @test_partial_inbounds1( |
| ; CHECK-NEXT: [[P2_IDX:%.*]] = shl i64 [[IDX:%.*]], 2 |
| ; CHECK-NEXT: ret i64 [[P2_IDX]] |
| ; |
| %p2 = getelementptr [0 x i32], ptr %base, i64 0, i64 %idx |
| %i1 = ptrtoint ptr %base to i64 |
| %i2 = ptrtoint ptr %p2 to i64 |
| %d = sub i64 %i2, %i1 |
| ret i64 %d |
| } |
| |
| define i64 @test_partial_inbounds2(ptr %base, i64 %idx) { |
| ; CHECK-LABEL: @test_partial_inbounds2( |
| ; CHECK-NEXT: [[P2_IDX:%.*]] = shl nsw i64 [[IDX:%.*]], 2 |
| ; CHECK-NEXT: ret i64 [[P2_IDX]] |
| ; |
| %p2 = getelementptr inbounds [0 x i32], ptr %base, i64 0, i64 %idx |
| %i1 = ptrtoint ptr %base to i64 |
| %i2 = ptrtoint ptr %p2 to i64 |
| %d = sub i64 %i2, %i1 |
| ret i64 %d |
| } |
| |
| define i64 @test_inbounds_nuw(ptr %base, i64 %idx) { |
| ; CHECK-LABEL: @test_inbounds_nuw( |
| ; CHECK-NEXT: [[P2_IDX:%.*]] = shl nuw nsw i64 [[IDX:%.*]], 2 |
| ; CHECK-NEXT: ret i64 [[P2_IDX]] |
| ; |
| %p2 = getelementptr inbounds [0 x i32], ptr %base, i64 0, i64 %idx |
| %i1 = ptrtoint ptr %base to i64 |
| %i2 = ptrtoint ptr %p2 to i64 |
| %d = sub nuw i64 %i2, %i1 |
| ret i64 %d |
| } |
| |
| define i64 @test_nuw(ptr %base, i64 %idx) { |
| ; CHECK-LABEL: @test_nuw( |
| ; CHECK-NEXT: [[P2_IDX:%.*]] = shl i64 [[IDX:%.*]], 2 |
| ; CHECK-NEXT: ret i64 [[P2_IDX]] |
| ; |
| %p2 = getelementptr [0 x i32], ptr %base, i64 0, i64 %idx |
| %i1 = ptrtoint ptr %base to i64 |
| %i2 = ptrtoint ptr %p2 to i64 |
| %d = sub nuw i64 %i2, %i1 |
| ret i64 %d |
| } |
| |
| define i32 @test_inbounds_nuw_trunc(ptr %base, i64 %idx) { |
| ; CHECK-LABEL: @test_inbounds_nuw_trunc( |
| ; CHECK-NEXT: [[IDX_TR:%.*]] = trunc i64 [[IDX:%.*]] to i32 |
| ; CHECK-NEXT: [[D:%.*]] = shl i32 [[IDX_TR]], 2 |
| ; CHECK-NEXT: ret i32 [[D]] |
| ; |
| %p2 = getelementptr inbounds [0 x i32], ptr %base, i64 0, i64 %idx |
| %i1 = ptrtoint ptr %base to i64 |
| %i2 = ptrtoint ptr %p2 to i64 |
| %t1 = trunc i64 %i1 to i32 |
| %t2 = trunc i64 %i2 to i32 |
| %d = sub nuw i32 %t2, %t1 |
| ret i32 %d |
| } |
| |
| define i64 @test_inbounds_nuw_swapped(ptr %base, i64 %idx) { |
| ; CHECK-LABEL: @test_inbounds_nuw_swapped( |
| ; CHECK-NEXT: [[P2_IDX_NEG:%.*]] = mul nsw i64 [[IDX:%.*]], -4 |
| ; CHECK-NEXT: ret i64 [[P2_IDX_NEG]] |
| ; |
| %p2 = getelementptr inbounds [0 x i32], ptr %base, i64 0, i64 %idx |
| %i1 = ptrtoint ptr %p2 to i64 |
| %i2 = ptrtoint ptr %base to i64 |
| %d = sub nuw i64 %i2, %i1 |
| ret i64 %d |
| } |
| |
| define i64 @test_inbounds1_nuw_swapped(ptr %base, i64 %idx) { |
| ; CHECK-LABEL: @test_inbounds1_nuw_swapped( |
| ; CHECK-NEXT: [[P2_IDX_NEG:%.*]] = mul i64 [[IDX:%.*]], -4 |
| ; CHECK-NEXT: ret i64 [[P2_IDX_NEG]] |
| ; |
| %p2 = getelementptr [0 x i32], ptr %base, i64 0, i64 %idx |
| %i1 = ptrtoint ptr %p2 to i64 |
| %i2 = ptrtoint ptr %base to i64 |
| %d = sub nuw i64 %i2, %i1 |
| ret i64 %d |
| } |
| |
| define i64 @test_inbounds2_nuw_swapped(ptr %base, i64 %idx) { |
| ; CHECK-LABEL: @test_inbounds2_nuw_swapped( |
| ; CHECK-NEXT: [[P2_IDX_NEG:%.*]] = mul nsw i64 [[IDX:%.*]], -4 |
| ; CHECK-NEXT: ret i64 [[P2_IDX_NEG]] |
| ; |
| %p2 = getelementptr inbounds [0 x i32], ptr %base, i64 0, i64 %idx |
| %i1 = ptrtoint ptr %p2 to i64 |
| %i2 = ptrtoint ptr %base to i64 |
| %d = sub nuw i64 %i2, %i1 |
| ret i64 %d |
| } |
| |
| define i64 @test_inbounds_two_gep(ptr %base, i64 %idx, i64 %idx2) { |
| ; CHECK-LABEL: @test_inbounds_two_gep( |
| ; CHECK-NEXT: [[TMP1:%.*]] = sub nsw i64 [[IDX2:%.*]], [[IDX:%.*]] |
| ; CHECK-NEXT: [[GEPDIFF:%.*]] = shl nsw i64 [[TMP1]], 2 |
| ; CHECK-NEXT: ret i64 [[GEPDIFF]] |
| ; |
| %p1 = getelementptr inbounds [0 x i32], ptr %base, i64 0, i64 %idx |
| %p2 = getelementptr inbounds [0 x i32], ptr %base, i64 0, i64 %idx2 |
| %i1 = ptrtoint ptr %p1 to i64 |
| %i2 = ptrtoint ptr %p2 to i64 |
| %d = sub i64 %i2, %i1 |
| ret i64 %d |
| } |
| |
| define i64 @test_inbounds_nsw_two_gep(ptr %base, i64 %idx, i64 %idx2) { |
| ; CHECK-LABEL: @test_inbounds_nsw_two_gep( |
| ; CHECK-NEXT: [[TMP1:%.*]] = sub nsw i64 [[IDX2:%.*]], [[IDX:%.*]] |
| ; CHECK-NEXT: [[GEPDIFF:%.*]] = shl nsw i64 [[TMP1]], 2 |
| ; CHECK-NEXT: ret i64 [[GEPDIFF]] |
| ; |
| %p1 = getelementptr inbounds [0 x i32], ptr %base, i64 0, i64 %idx |
| %p2 = getelementptr inbounds [0 x i32], ptr %base, i64 0, i64 %idx2 |
| %i1 = ptrtoint ptr %p1 to i64 |
| %i2 = ptrtoint ptr %p2 to i64 |
| %d = sub nsw i64 %i2, %i1 |
| ret i64 %d |
| } |
| |
| define i64 @test_inbounds_nuw_two_gep(ptr %base, i64 %idx, i64 %idx2) { |
| ; CHECK-LABEL: @test_inbounds_nuw_two_gep( |
| ; CHECK-NEXT: [[TMP1:%.*]] = sub nsw i64 [[IDX2:%.*]], [[IDX:%.*]] |
| ; CHECK-NEXT: [[GEPDIFF:%.*]] = shl nsw i64 [[TMP1]], 2 |
| ; CHECK-NEXT: ret i64 [[GEPDIFF]] |
| ; |
| %p1 = getelementptr inbounds [0 x i32], ptr %base, i64 0, i64 %idx |
| %p2 = getelementptr inbounds [0 x i32], ptr %base, i64 0, i64 %idx2 |
| %i1 = ptrtoint ptr %p1 to i64 |
| %i2 = ptrtoint ptr %p2 to i64 |
| %d = sub nuw i64 %i2, %i1 |
| ret i64 %d |
| } |
| |
| define i64 @test_nusw_two_gep(ptr %base, i64 %idx, i64 %idx2) { |
| ; CHECK-LABEL: @test_nusw_two_gep( |
| ; CHECK-NEXT: [[TMP1:%.*]] = sub i64 [[IDX2:%.*]], [[IDX:%.*]] |
| ; CHECK-NEXT: [[GEPDIFF:%.*]] = shl i64 [[TMP1]], 2 |
| ; CHECK-NEXT: ret i64 [[GEPDIFF]] |
| ; |
| %p1 = getelementptr nusw [0 x i32], ptr %base, i64 0, i64 %idx |
| %p2 = getelementptr nusw [0 x i32], ptr %base, i64 0, i64 %idx2 |
| %i1 = ptrtoint ptr %p1 to i64 |
| %i2 = ptrtoint ptr %p2 to i64 |
| %d = sub i64 %i2, %i1 |
| ret i64 %d |
| } |
| |
| define i64 @test_nuw_two_gep(ptr %base, i64 %idx, i64 %idx2) { |
| ; CHECK-LABEL: @test_nuw_two_gep( |
| ; CHECK-NEXT: [[TMP1:%.*]] = sub nuw i64 [[IDX2:%.*]], [[IDX:%.*]] |
| ; CHECK-NEXT: [[GEPDIFF:%.*]] = shl nuw i64 [[TMP1]], 2 |
| ; CHECK-NEXT: ret i64 [[GEPDIFF]] |
| ; |
| %p1 = getelementptr nuw [0 x i32], ptr %base, i64 0, i64 %idx |
| %p2 = getelementptr nuw [0 x i32], ptr %base, i64 0, i64 %idx2 |
| %i1 = ptrtoint ptr %p1 to i64 |
| %i2 = ptrtoint ptr %p2 to i64 |
| %d = sub nuw i64 %i2, %i1 |
| ret i64 %d |
| } |
| |
| define i64 @test_nuw_two_gep_missing_nuw_on_sub(ptr %base, i64 %idx, i64 %idx2) { |
| ; CHECK-LABEL: @test_nuw_two_gep_missing_nuw_on_sub( |
| ; CHECK-NEXT: [[TMP1:%.*]] = sub i64 [[IDX2:%.*]], [[IDX:%.*]] |
| ; CHECK-NEXT: [[GEPDIFF:%.*]] = shl i64 [[TMP1]], 2 |
| ; CHECK-NEXT: ret i64 [[GEPDIFF]] |
| ; |
| %p1 = getelementptr nuw [0 x i32], ptr %base, i64 0, i64 %idx |
| %p2 = getelementptr nuw [0 x i32], ptr %base, i64 0, i64 %idx2 |
| %i1 = ptrtoint ptr %p1 to i64 |
| %i2 = ptrtoint ptr %p2 to i64 |
| %d = sub i64 %i2, %i1 |
| ret i64 %d |
| } |
| |
| define i64 @test_nuw_two_gep_missing_nuw_on_one_gep(ptr %base, i64 %idx, i64 %idx2) { |
| ; CHECK-LABEL: @test_nuw_two_gep_missing_nuw_on_one_gep( |
| ; CHECK-NEXT: [[TMP1:%.*]] = sub i64 [[IDX2:%.*]], [[IDX:%.*]] |
| ; CHECK-NEXT: [[GEPDIFF:%.*]] = shl i64 [[TMP1]], 2 |
| ; CHECK-NEXT: ret i64 [[GEPDIFF]] |
| ; |
| %p1 = getelementptr nuw [0 x i32], ptr %base, i64 0, i64 %idx |
| %p2 = getelementptr [0 x i32], ptr %base, i64 0, i64 %idx2 |
| %i1 = ptrtoint ptr %p1 to i64 |
| %i2 = ptrtoint ptr %p2 to i64 |
| %d = sub nuw i64 %i2, %i1 |
| ret i64 %d |
| } |
| |
| define i64 @test_inbounds_nuw_multi_index(ptr %base, i64 %idx, i64 %idx2) { |
| ; CHECK-LABEL: @test_inbounds_nuw_multi_index( |
| ; CHECK-NEXT: [[P2_SPLIT_IDX:%.*]] = shl nsw i64 [[IDX:%.*]], 3 |
| ; CHECK-NEXT: [[P2_IDX:%.*]] = shl nsw i64 [[IDX2:%.*]], 2 |
| ; CHECK-NEXT: [[D:%.*]] = add nsw i64 [[P2_SPLIT_IDX]], [[P2_IDX]] |
| ; CHECK-NEXT: ret i64 [[D]] |
| ; |
| %p2 = getelementptr inbounds [0 x [2 x i32]], ptr %base, i64 0, i64 %idx, i64 %idx2 |
| %i1 = ptrtoint ptr %base to i64 |
| %i2 = ptrtoint ptr %p2 to i64 |
| %d = sub nuw i64 %i2, %i1 |
| ret i64 %d |
| } |
| |
| ; rdar://7362831 |
| define i32 @test23(ptr %P, i64 %A){ |
| ; CHECK-LABEL: @test23( |
| ; CHECK-NEXT: [[G:%.*]] = trunc i64 [[A:%.*]] to i32 |
| ; CHECK-NEXT: ret i32 [[G]] |
| ; |
| %B = getelementptr inbounds i8, ptr %P, i64 %A |
| %C = ptrtoint ptr %B to i64 |
| %D = trunc i64 %C to i32 |
| %E = ptrtoint ptr %P to i64 |
| %F = trunc i64 %E to i32 |
| %G = sub i32 %D, %F |
| ret i32 %G |
| } |
| |
| define i8 @test23_as1(ptr addrspace(1) %P, i16 %A) { |
| ; CHECK-LABEL: @test23_as1( |
| ; CHECK-NEXT: [[G:%.*]] = trunc i16 [[A:%.*]] to i8 |
| ; CHECK-NEXT: ret i8 [[G]] |
| ; |
| %B = getelementptr inbounds i8, ptr addrspace(1) %P, i16 %A |
| %C = ptrtoint ptr addrspace(1) %B to i16 |
| %D = trunc i16 %C to i8 |
| %E = ptrtoint ptr addrspace(1) %P to i16 |
| %F = trunc i16 %E to i8 |
| %G = sub i8 %D, %F |
| ret i8 %G |
| } |
| |
| define i64 @test24(ptr %P, i64 %A){ |
| ; CHECK-LABEL: @test24( |
| ; CHECK-NEXT: ret i64 [[A:%.*]] |
| ; |
| %B = getelementptr inbounds i8, ptr %P, i64 %A |
| %C = ptrtoint ptr %B to i64 |
| %E = ptrtoint ptr %P to i64 |
| %G = sub i64 %C, %E |
| ret i64 %G |
| } |
| |
| define i16 @test24_as1(ptr addrspace(1) %P, i16 %A) { |
| ; CHECK-LABEL: @test24_as1( |
| ; CHECK-NEXT: ret i16 [[A:%.*]] |
| ; |
| %B = getelementptr inbounds i8, ptr addrspace(1) %P, i16 %A |
| %C = ptrtoint ptr addrspace(1) %B to i16 |
| %E = ptrtoint ptr addrspace(1) %P to i16 |
| %G = sub i16 %C, %E |
| ret i16 %G |
| } |
| |
| define i64 @test24a(ptr %P, i64 %A){ |
| ; CHECK-LABEL: @test24a( |
| ; CHECK-NEXT: [[GEPDIFF:%.*]] = sub nsw i64 0, [[A:%.*]] |
| ; CHECK-NEXT: ret i64 [[GEPDIFF]] |
| ; |
| %B = getelementptr inbounds i8, ptr %P, i64 %A |
| %C = ptrtoint ptr %B to i64 |
| %E = ptrtoint ptr %P to i64 |
| %G = sub i64 %E, %C |
| ret i64 %G |
| } |
| |
| define i16 @test24a_as1(ptr addrspace(1) %P, i16 %A) { |
| ; CHECK-LABEL: @test24a_as1( |
| ; CHECK-NEXT: [[GEPDIFF:%.*]] = sub nsw i16 0, [[A:%.*]] |
| ; CHECK-NEXT: ret i16 [[GEPDIFF]] |
| ; |
| %B = getelementptr inbounds i8, ptr addrspace(1) %P, i16 %A |
| %C = ptrtoint ptr addrspace(1) %B to i16 |
| %E = ptrtoint ptr addrspace(1) %P to i16 |
| %G = sub i16 %E, %C |
| ret i16 %G |
| } |
| |
| @Arr = external global [42 x i16] |
| |
| define i64 @test24b(ptr %P, i64 %A){ |
| ; CHECK-LABEL: @test24b( |
| ; CHECK-NEXT: [[B_IDX:%.*]] = shl nsw i64 [[A:%.*]], 1 |
| ; CHECK-NEXT: ret i64 [[B_IDX]] |
| ; |
| %B = getelementptr inbounds [42 x i16], ptr @Arr, i64 0, i64 %A |
| %C = ptrtoint ptr %B to i64 |
| %G = sub i64 %C, ptrtoint (ptr @Arr to i64) |
| ret i64 %G |
| } |
| |
| define i64 @test25(ptr %P, i64 %A){ |
| ; CHECK-LABEL: @test25( |
| ; CHECK-NEXT: [[B_IDX:%.*]] = shl nsw i64 [[A:%.*]], 1 |
| ; CHECK-NEXT: [[GEPDIFF:%.*]] = add nsw i64 [[B_IDX]], -84 |
| ; CHECK-NEXT: ret i64 [[GEPDIFF]] |
| ; |
| %B = getelementptr inbounds [42 x i16], ptr @Arr, i64 0, i64 %A |
| %C = ptrtoint ptr %B to i64 |
| %G = sub i64 %C, ptrtoint (ptr getelementptr ([42 x i16], ptr @Arr, i64 1, i64 0) to i64) |
| ret i64 %G |
| } |
| |
| define i64 @zext_ptrtoint_sub_ptrtoint(ptr %p, i32 %offset) { |
| ; CHECK-LABEL: @zext_ptrtoint_sub_ptrtoint( |
| ; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[OFFSET:%.*]] to i64 |
| ; CHECK-NEXT: [[A:%.*]] = getelementptr bfloat, ptr @Arr, i64 [[TMP1]] |
| ; CHECK-NEXT: [[TMP2:%.*]] = ptrtoint ptr [[A]] to i64 |
| ; CHECK-NEXT: [[C:%.*]] = and i64 [[TMP2]], 4294967294 |
| ; CHECK-NEXT: [[D:%.*]] = sub i64 [[C]], ptrtoint (ptr @Arr to i64) |
| ; CHECK-NEXT: ret i64 [[D]] |
| ; |
| %A = getelementptr bfloat, ptr @Arr, i32 %offset |
| %B = ptrtoint ptr %A to i32 |
| %C = zext i32 %B to i64 |
| %D = sub i64 %C, ptrtoint (ptr @Arr to i64) |
| ret i64 %D |
| } |
| |
| define i64 @ptrtoint_sub_zext_ptrtoint(ptr %p, i32 %offset) { |
| ; CHECK-LABEL: @ptrtoint_sub_zext_ptrtoint( |
| ; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[OFFSET:%.*]] to i64 |
| ; CHECK-NEXT: [[A:%.*]] = getelementptr bfloat, ptr @Arr, i64 [[TMP1]] |
| ; CHECK-NEXT: [[TMP2:%.*]] = ptrtoint ptr [[A]] to i64 |
| ; CHECK-NEXT: [[C:%.*]] = and i64 [[TMP2]], 4294967294 |
| ; CHECK-NEXT: [[D:%.*]] = sub i64 ptrtoint (ptr @Arr to i64), [[C]] |
| ; CHECK-NEXT: ret i64 [[D]] |
| ; |
| %A = getelementptr bfloat, ptr @Arr, i32 %offset |
| %B = ptrtoint ptr %A to i32 |
| %C = zext i32 %B to i64 |
| %D = sub i64 ptrtoint (ptr @Arr to i64), %C |
| ret i64 %D |
| } |
| |
| define i64 @negative_zext_ptrtoint_sub_ptrtoint(ptr %p, i32 %offset) { |
| ; CHECK-LABEL: @negative_zext_ptrtoint_sub_ptrtoint( |
| ; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[OFFSET:%.*]] to i64 |
| ; CHECK-NEXT: [[A:%.*]] = getelementptr bfloat, ptr @Arr, i64 [[TMP1]] |
| ; CHECK-NEXT: [[TMP2:%.*]] = ptrtoint ptr [[A]] to i64 |
| ; CHECK-NEXT: [[C:%.*]] = and i64 [[TMP2]], 65534 |
| ; CHECK-NEXT: [[D:%.*]] = sub i64 [[C]], ptrtoint (ptr @Arr to i64) |
| ; CHECK-NEXT: ret i64 [[D]] |
| ; |
| %A = getelementptr bfloat, ptr @Arr, i32 %offset |
| %B = ptrtoint ptr %A to i16 |
| %C = zext i16 %B to i64 |
| %D = sub i64 %C, ptrtoint (ptr @Arr to i64) |
| ret i64 %D |
| } |
| |
| define i64 @negative_ptrtoint_sub_zext_ptrtoint(ptr %p, i32 %offset) { |
| ; CHECK-LABEL: @negative_ptrtoint_sub_zext_ptrtoint( |
| ; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[OFFSET:%.*]] to i64 |
| ; CHECK-NEXT: [[A:%.*]] = getelementptr bfloat, ptr @Arr, i64 [[TMP1]] |
| ; CHECK-NEXT: [[TMP2:%.*]] = ptrtoint ptr [[A]] to i64 |
| ; CHECK-NEXT: [[C:%.*]] = and i64 [[TMP2]], 65534 |
| ; CHECK-NEXT: [[D:%.*]] = sub i64 ptrtoint (ptr @Arr to i64), [[C]] |
| ; CHECK-NEXT: ret i64 [[D]] |
| ; |
| %A = getelementptr bfloat, ptr @Arr, i32 %offset |
| %B = ptrtoint ptr %A to i16 |
| %C = zext i16 %B to i64 |
| %D = sub i64 ptrtoint (ptr @Arr to i64), %C |
| ret i64 %D |
| } |
| |
| @Arr_as1 = external addrspace(1) global [42 x i16] |
| |
| define i16 @test25_as1(ptr addrspace(1) %P, i64 %A) { |
| ; CHECK-LABEL: @test25_as1( |
| ; CHECK-NEXT: [[TMP1:%.*]] = trunc nsw i64 [[A:%.*]] to i16 |
| ; CHECK-NEXT: [[B_IDX:%.*]] = shl nsw i16 [[TMP1]], 1 |
| ; CHECK-NEXT: [[GEPDIFF:%.*]] = add nsw i16 [[B_IDX]], -84 |
| ; CHECK-NEXT: ret i16 [[GEPDIFF]] |
| ; |
| %B = getelementptr inbounds [42 x i16], ptr addrspace(1) @Arr_as1, i64 0, i64 %A |
| %C = ptrtoint ptr addrspace(1) %B to i16 |
| %G = sub i16 %C, ptrtoint (ptr addrspace(1) getelementptr ([42 x i16], ptr addrspace(1) @Arr_as1, i64 1, i64 0) to i16) |
| ret i16 %G |
| } |
| |
| @Arr_as2 = external addrspace(2) global [42 x i16] |
| |
| define i64 @ptrtoint_sub_zext_ptrtoint_as2_inbounds(i32 %offset) { |
| ; CHECK-LABEL: @ptrtoint_sub_zext_ptrtoint_as2_inbounds( |
| ; CHECK-NEXT: [[A:%.*]] = getelementptr inbounds bfloat, ptr addrspace(2) @Arr_as2, i32 [[OFFSET:%.*]] |
| ; CHECK-NEXT: [[B:%.*]] = ptrtoint ptr addrspace(2) [[A]] to i32 |
| ; CHECK-NEXT: [[C:%.*]] = zext i32 [[B]] to i64 |
| ; CHECK-NEXT: [[D:%.*]] = sub nsw i64 ptrtoint (ptr addrspace(2) @Arr_as2 to i64), [[C]] |
| ; CHECK-NEXT: ret i64 [[D]] |
| ; |
| %A = getelementptr inbounds bfloat, ptr addrspace(2) @Arr_as2, i32 %offset |
| %B = ptrtoint ptr addrspace(2) %A to i32 |
| %C = zext i32 %B to i64 |
| %D = sub i64 ptrtoint (ptr addrspace(2) @Arr_as2 to i64), %C |
| ret i64 %D |
| } |
| |
| define i64 @zext_ptrtoint_sub_ptrtoint_as2_nusw(i32 %offset) { |
| ; CHECK-LABEL: @zext_ptrtoint_sub_ptrtoint_as2_nusw( |
| ; CHECK-NEXT: [[A_IDX:%.*]] = shl nsw i32 [[OFFSET:%.*]], 1 |
| ; CHECK-NEXT: [[D:%.*]] = sext i32 [[A_IDX]] to i64 |
| ; CHECK-NEXT: ret i64 [[D]] |
| ; |
| %A = getelementptr nusw bfloat, ptr addrspace(2) @Arr_as2, i32 %offset |
| %B = ptrtoint ptr addrspace(2) %A to i32 |
| %C = zext i32 %B to i64 |
| %D = sub i64 %C, ptrtoint (ptr addrspace(2) @Arr_as2 to i64) |
| ret i64 %D |
| } |
| |
| define i64 @zext_ptrtoint_sub_ptrtoint_as2_nuw(i32 %offset) { |
| ; CHECK-LABEL: @zext_ptrtoint_sub_ptrtoint_as2_nuw( |
| ; CHECK-NEXT: [[A_IDX:%.*]] = shl nuw i32 [[OFFSET:%.*]], 1 |
| ; CHECK-NEXT: [[D:%.*]] = zext i32 [[A_IDX]] to i64 |
| ; CHECK-NEXT: ret i64 [[D]] |
| ; |
| %A = getelementptr nuw bfloat, ptr addrspace(2) @Arr_as2, i32 %offset |
| %B = ptrtoint ptr addrspace(2) %A to i32 |
| %C = zext i32 %B to i64 |
| %D = sub i64 %C, ptrtoint (ptr addrspace(2) @Arr_as2 to i64) |
| ret i64 %D |
| } |
| |
| define i64 @zext_ptrtoint_sub_ptrtoint_as2_nusw_nuw(i32 %offset) { |
| ; CHECK-LABEL: @zext_ptrtoint_sub_ptrtoint_as2_nusw_nuw( |
| ; CHECK-NEXT: [[A_IDX:%.*]] = shl nuw nsw i32 [[OFFSET:%.*]], 1 |
| ; CHECK-NEXT: [[D:%.*]] = zext nneg i32 [[A_IDX]] to i64 |
| ; CHECK-NEXT: ret i64 [[D]] |
| ; |
| %A = getelementptr nusw nuw bfloat, ptr addrspace(2) @Arr_as2, i32 %offset |
| %B = ptrtoint ptr addrspace(2) %A to i32 |
| %C = zext i32 %B to i64 |
| %D = sub i64 %C, ptrtoint (ptr addrspace(2) @Arr_as2 to i64) |
| ret i64 %D |
| } |
| |
| define i64 @zext_ptrtoint_sub_zext_ptrtoint_as2_nusw(i32 %offset) { |
| ; CHECK-LABEL: @zext_ptrtoint_sub_zext_ptrtoint_as2_nusw( |
| ; CHECK-NEXT: [[A_IDX:%.*]] = shl nsw i32 [[OFFSET:%.*]], 1 |
| ; CHECK-NEXT: [[E:%.*]] = sext i32 [[A_IDX]] to i64 |
| ; CHECK-NEXT: ret i64 [[E]] |
| ; |
| %A = getelementptr nusw bfloat, ptr addrspace(2) @Arr_as2, i32 %offset |
| %B = ptrtoint ptr addrspace(2) %A to i32 |
| %C = zext i32 %B to i64 |
| %D = zext i32 ptrtoint (ptr addrspace(2) @Arr_as2 to i32) to i64 |
| %E = sub i64 %C, %D |
| ret i64 %E |
| } |
| |
| define i64 @zext_ptrtoint_sub_zext_ptrtoint_as2_nuw(i32 %offset) { |
| ; CHECK-LABEL: @zext_ptrtoint_sub_zext_ptrtoint_as2_nuw( |
| ; CHECK-NEXT: [[A_IDX:%.*]] = shl nuw i32 [[OFFSET:%.*]], 1 |
| ; CHECK-NEXT: [[E:%.*]] = zext i32 [[A_IDX]] to i64 |
| ; CHECK-NEXT: ret i64 [[E]] |
| ; |
| %A = getelementptr nuw bfloat, ptr addrspace(2) @Arr_as2, i32 %offset |
| %B = ptrtoint ptr addrspace(2) %A to i32 |
| %C = zext i32 %B to i64 |
| %D = zext i32 ptrtoint (ptr addrspace(2) @Arr_as2 to i32) to i64 |
| %E = sub i64 %C, %D |
| ret i64 %E |
| } |
| |
| define i64 @negative_zext_ptrtoint_sub_ptrtoint_as2_nuw(i32 %offset) { |
| ; CHECK-LABEL: @negative_zext_ptrtoint_sub_ptrtoint_as2_nuw( |
| ; CHECK-NEXT: [[A:%.*]] = getelementptr nuw bfloat, ptr addrspace(2) @Arr_as2, i32 [[OFFSET:%.*]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = ptrtoint ptr addrspace(2) [[A]] to i32 |
| ; CHECK-NEXT: [[B_MASK:%.*]] = and i32 [[TMP1]], 65534 |
| ; CHECK-NEXT: [[C:%.*]] = zext nneg i32 [[B_MASK]] to i64 |
| ; CHECK-NEXT: [[D:%.*]] = sub nsw i64 [[C]], ptrtoint (ptr addrspace(2) @Arr_as2 to i64) |
| ; CHECK-NEXT: ret i64 [[D]] |
| ; |
| %A = getelementptr nuw bfloat, ptr addrspace(2) @Arr_as2, i32 %offset |
| %B = ptrtoint ptr addrspace(2) %A to i16 |
| %C = zext i16 %B to i64 |
| %D = sub i64 %C, ptrtoint (ptr addrspace(2) @Arr_as2 to i64) |
| ret i64 %D |
| } |
| |
| define i64 @ptrtoint_sub_zext_ptrtoint_as2_inbounds_local(ptr addrspace(2) %p, i32 %offset) { |
| ; CHECK-LABEL: @ptrtoint_sub_zext_ptrtoint_as2_inbounds_local( |
| ; CHECK-NEXT: [[A:%.*]] = getelementptr inbounds bfloat, ptr addrspace(2) [[P:%.*]], i32 [[OFFSET:%.*]] |
| ; CHECK-NEXT: [[B:%.*]] = ptrtoint ptr addrspace(2) [[A]] to i32 |
| ; CHECK-NEXT: [[C:%.*]] = zext i32 [[B]] to i64 |
| ; CHECK-NEXT: [[TMP1:%.*]] = ptrtoint ptr addrspace(2) [[P]] to i32 |
| ; CHECK-NEXT: [[CC:%.*]] = zext i32 [[TMP1]] to i64 |
| ; CHECK-NEXT: [[D:%.*]] = sub nsw i64 [[CC]], [[C]] |
| ; CHECK-NEXT: ret i64 [[D]] |
| ; |
| %A = getelementptr inbounds bfloat, ptr addrspace(2) %p, i32 %offset |
| %B = ptrtoint ptr addrspace(2) %A to i32 |
| %C = zext i32 %B to i64 |
| %CC = ptrtoint ptr addrspace(2) %p to i64 |
| %D = sub i64 %CC, %C |
| ret i64 %D |
| } |
| |
| define i64 @zext_ptrtoint_sub_ptrtoint_as2_nusw_local(ptr addrspace(2) %p, i32 %offset) { |
| ; CHECK-LABEL: @zext_ptrtoint_sub_ptrtoint_as2_nusw_local( |
| ; CHECK-NEXT: [[A_IDX:%.*]] = shl nsw i32 [[OFFSET:%.*]], 1 |
| ; CHECK-NEXT: [[D:%.*]] = sext i32 [[A_IDX]] to i64 |
| ; CHECK-NEXT: ret i64 [[D]] |
| ; |
| %A = getelementptr nusw bfloat, ptr addrspace(2) %p, i32 %offset |
| %B = ptrtoint ptr addrspace(2) %A to i32 |
| %C = zext i32 %B to i64 |
| %CC = ptrtoint ptr addrspace(2) %p to i64 |
| %D = sub i64 %C, %CC |
| ret i64 %D |
| } |
| |
| define i64 @zext_ptrtoint_sub_ptrtoint_as2_nuw_local(ptr addrspace(2) %p, i32 %offset) { |
| ; CHECK-LABEL: @zext_ptrtoint_sub_ptrtoint_as2_nuw_local( |
| ; CHECK-NEXT: [[A_IDX:%.*]] = shl nuw i32 [[OFFSET:%.*]], 1 |
| ; CHECK-NEXT: [[D:%.*]] = zext i32 [[A_IDX]] to i64 |
| ; CHECK-NEXT: ret i64 [[D]] |
| ; |
| %A = getelementptr nuw bfloat, ptr addrspace(2) %p, i32 %offset |
| %B = ptrtoint ptr addrspace(2) %A to i32 |
| %C = zext i32 %B to i64 |
| %CC = ptrtoint ptr addrspace(2) %p to i64 |
| %D = sub i64 %C, %CC |
| ret i64 %D |
| } |
| |
| define i64 @zext_ptrtoint_sub_ptrtoint_as2_nusw_nuw_local(ptr addrspace(2) %p, i32 %offset) { |
| ; CHECK-LABEL: @zext_ptrtoint_sub_ptrtoint_as2_nusw_nuw_local( |
| ; CHECK-NEXT: [[A_IDX:%.*]] = shl nuw nsw i32 [[OFFSET:%.*]], 1 |
| ; CHECK-NEXT: [[D:%.*]] = zext nneg i32 [[A_IDX]] to i64 |
| ; CHECK-NEXT: ret i64 [[D]] |
| ; |
| %A = getelementptr nusw nuw bfloat, ptr addrspace(2) %p, i32 %offset |
| %B = ptrtoint ptr addrspace(2) %A to i32 |
| %C = zext i32 %B to i64 |
| %CC = ptrtoint ptr addrspace(2) %p to i64 |
| %D = sub i64 %C, %CC |
| ret i64 %D |
| } |
| |
| define i64 @zext_ptrtoint_sub_zext_ptrtoint_as2_nusw_local(ptr addrspace(2) %p, i32 %offset) { |
| ; CHECK-LABEL: @zext_ptrtoint_sub_zext_ptrtoint_as2_nusw_local( |
| ; CHECK-NEXT: [[A_IDX:%.*]] = shl nsw i32 [[OFFSET:%.*]], 1 |
| ; CHECK-NEXT: [[E:%.*]] = sext i32 [[A_IDX]] to i64 |
| ; CHECK-NEXT: ret i64 [[E]] |
| ; |
| %A = getelementptr nusw bfloat, ptr addrspace(2) %p, i32 %offset |
| %B = ptrtoint ptr addrspace(2) %A to i32 |
| %C = zext i32 %B to i64 |
| %CC = ptrtoint ptr addrspace(2) %p to i32 |
| %D = zext i32 %CC to i64 |
| %E = sub i64 %C, %D |
| ret i64 %E |
| } |
| |
| define i64 @zext_ptrtoint_sub_zext_ptrtoint_as2_nuw_local(ptr addrspace(2) %p, i32 %offset) { |
| ; CHECK-LABEL: @zext_ptrtoint_sub_zext_ptrtoint_as2_nuw_local( |
| ; CHECK-NEXT: [[A_IDX:%.*]] = shl nuw i32 [[OFFSET:%.*]], 1 |
| ; CHECK-NEXT: [[E:%.*]] = zext i32 [[A_IDX]] to i64 |
| ; CHECK-NEXT: ret i64 [[E]] |
| ; |
| %A = getelementptr nuw bfloat, ptr addrspace(2) %p, i32 %offset |
| %B = ptrtoint ptr addrspace(2) %A to i32 |
| %C = zext i32 %B to i64 |
| %CC = ptrtoint ptr addrspace(2) %p to i32 |
| %D = zext i32 %CC to i64 |
| %E = sub i64 %C, %D |
| ret i64 %E |
| } |
| |
| define i64 @negative_zext_ptrtoint_sub_ptrtoint_as2_nuw_local(ptr addrspace(2) %p, i32 %offset) { |
| ; CHECK-LABEL: @negative_zext_ptrtoint_sub_ptrtoint_as2_nuw_local( |
| ; CHECK-NEXT: [[A:%.*]] = getelementptr nuw bfloat, ptr addrspace(2) [[P:%.*]], i32 [[OFFSET:%.*]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = ptrtoint ptr addrspace(2) [[A]] to i32 |
| ; CHECK-NEXT: [[B_MASK:%.*]] = and i32 [[TMP1]], 65535 |
| ; CHECK-NEXT: [[C:%.*]] = zext nneg i32 [[B_MASK]] to i64 |
| ; CHECK-NEXT: [[TMP2:%.*]] = ptrtoint ptr addrspace(2) [[P]] to i32 |
| ; CHECK-NEXT: [[CC:%.*]] = zext i32 [[TMP2]] to i64 |
| ; CHECK-NEXT: [[D:%.*]] = sub nsw i64 [[C]], [[CC]] |
| ; CHECK-NEXT: ret i64 [[D]] |
| ; |
| %A = getelementptr nuw bfloat, ptr addrspace(2) %p, i32 %offset |
| %B = ptrtoint ptr addrspace(2) %A to i16 |
| %C = zext i16 %B to i64 |
| %CC = ptrtoint ptr addrspace(2) %p to i64 |
| %D = sub i64 %C, %CC |
| ret i64 %D |
| } |
| |
| define i64 @test30(ptr %foo, i64 %i, i64 %j) { |
| ; CHECK-LABEL: @test30( |
| ; CHECK-NEXT: [[GEP1_IDX:%.*]] = shl nsw i64 [[I:%.*]], 2 |
| ; CHECK-NEXT: [[GEPDIFF:%.*]] = sub nsw i64 [[GEP1_IDX]], [[J:%.*]] |
| ; CHECK-NEXT: ret i64 [[GEPDIFF]] |
| ; |
| %gep1 = getelementptr inbounds i32, ptr %foo, i64 %i |
| %gep2 = getelementptr inbounds i8, ptr %foo, i64 %j |
| %cast1 = ptrtoint ptr %gep1 to i64 |
| %cast2 = ptrtoint ptr %gep2 to i64 |
| %sub = sub i64 %cast1, %cast2 |
| ret i64 %sub |
| } |
| |
| define i16 @test30_as1(ptr addrspace(1) %foo, i16 %i, i16 %j) { |
| ; CHECK-LABEL: @test30_as1( |
| ; CHECK-NEXT: [[GEP1_IDX:%.*]] = shl nsw i16 [[I:%.*]], 2 |
| ; CHECK-NEXT: [[GEPDIFF:%.*]] = sub nsw i16 [[GEP1_IDX]], [[J:%.*]] |
| ; CHECK-NEXT: ret i16 [[GEPDIFF]] |
| ; |
| %gep1 = getelementptr inbounds i32, ptr addrspace(1) %foo, i16 %i |
| %gep2 = getelementptr inbounds i8, ptr addrspace(1) %foo, i16 %j |
| %cast1 = ptrtoint ptr addrspace(1) %gep1 to i16 |
| %cast2 = ptrtoint ptr addrspace(1) %gep2 to i16 |
| %sub = sub i16 %cast1, %cast2 |
| ret i16 %sub |
| } |
| |
| ; Inbounds translates to 'nsw' on sub |
| |
| define i64 @gep_diff_both_inbounds(ptr %foo, i64 %i, i64 %j) { |
| ; CHECK-LABEL: @gep_diff_both_inbounds( |
| ; CHECK-NEXT: [[GEPDIFF:%.*]] = sub nsw i64 [[I:%.*]], [[J:%.*]] |
| ; CHECK-NEXT: ret i64 [[GEPDIFF]] |
| ; |
| %gep1 = getelementptr inbounds i8, ptr %foo, i64 %i |
| %gep2 = getelementptr inbounds i8, ptr %foo, i64 %j |
| %cast1 = ptrtoint ptr %gep1 to i64 |
| %cast2 = ptrtoint ptr %gep2 to i64 |
| %sub = sub i64 %cast1, %cast2 |
| ret i64 %sub |
| } |
| |
| ; Negative test for 'nsw' - both geps must be inbounds |
| |
| define i64 @gep_diff_first_inbounds(ptr %foo, i64 %i, i64 %j) { |
| ; CHECK-LABEL: @gep_diff_first_inbounds( |
| ; CHECK-NEXT: [[GEPDIFF:%.*]] = sub i64 [[I:%.*]], [[J:%.*]] |
| ; CHECK-NEXT: ret i64 [[GEPDIFF]] |
| ; |
| %gep1 = getelementptr inbounds i8, ptr %foo, i64 %i |
| %gep2 = getelementptr i8, ptr %foo, i64 %j |
| %cast1 = ptrtoint ptr %gep1 to i64 |
| %cast2 = ptrtoint ptr %gep2 to i64 |
| %sub = sub i64 %cast1, %cast2 |
| ret i64 %sub |
| } |
| |
| ; Negative test for 'nsw' - both geps must be inbounds |
| |
| define i64 @gep_diff_second_inbounds(ptr %foo, i64 %i, i64 %j) { |
| ; CHECK-LABEL: @gep_diff_second_inbounds( |
| ; CHECK-NEXT: [[GEPDIFF:%.*]] = sub i64 [[I:%.*]], [[J:%.*]] |
| ; CHECK-NEXT: ret i64 [[GEPDIFF]] |
| ; |
| %gep1 = getelementptr i8, ptr %foo, i64 %i |
| %gep2 = getelementptr inbounds i8, ptr %foo, i64 %j |
| %cast1 = ptrtoint ptr %gep1 to i64 |
| %cast2 = ptrtoint ptr %gep2 to i64 |
| %sub = sub i64 %cast1, %cast2 |
| ret i64 %sub |
| } |
| |
| define i64 @gep_diff_with_bitcast(ptr %p, i64 %idx) { |
| ; CHECK-LABEL: @gep_diff_with_bitcast( |
| ; CHECK-NEXT: ret i64 [[IDX:%.*]] |
| ; |
| %i1 = getelementptr inbounds [4 x i64], ptr %p, i64 %idx |
| %i3 = ptrtoint ptr %i1 to i64 |
| %i4 = ptrtoint ptr %p to i64 |
| %i5 = sub nuw i64 %i3, %i4 |
| %i6 = lshr i64 %i5, 5 |
| ret i64 %i6 |
| } |
| |
| define i64 @sub_scalable(ptr noundef %val1) { |
| ; CHECK-LABEL: @sub_scalable( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[TMP0:%.*]] = call i64 @llvm.vscale.i64() |
| ; CHECK-NEXT: [[TMP1:%.*]] = shl nuw i64 [[TMP0]], 4 |
| ; CHECK-NEXT: ret i64 [[TMP1]] |
| ; |
| entry: |
| %gep1 = getelementptr <vscale x 4 x i32>, ptr %val1, i64 1 |
| %sub.ptr.lhs.cast.i = ptrtoint ptr %gep1 to i64 |
| %sub.ptr.rhs.cast.i = ptrtoint ptr %val1 to i64 |
| %sub.ptr.sub.i = sub i64 %sub.ptr.lhs.cast.i, %sub.ptr.rhs.cast.i |
| ret i64 %sub.ptr.sub.i |
| } |
| |
| define i64 @sub_scalable2(ptr noundef %val1) { |
| ; CHECK-LABEL: @sub_scalable2( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[TMP0:%.*]] = call i64 @llvm.vscale.i64() |
| ; CHECK-NEXT: [[TMP1:%.*]] = shl nuw i64 [[TMP0]], 4 |
| ; CHECK-NEXT: [[TMP2:%.*]] = call i64 @llvm.vscale.i64() |
| ; CHECK-NEXT: [[GEP2_IDX:%.*]] = shl i64 [[TMP2]], 5 |
| ; CHECK-NEXT: [[GEPDIFF:%.*]] = sub i64 [[TMP1]], [[GEP2_IDX]] |
| ; CHECK-NEXT: ret i64 [[GEPDIFF]] |
| ; |
| entry: |
| %gep1 = getelementptr <vscale x 4 x i32>, ptr %val1, i64 1 |
| %sub.ptr.lhs.cast.i = ptrtoint ptr %gep1 to i64 |
| %gep2 = getelementptr <vscale x 4 x i32>, ptr %val1, i64 2 |
| %sub.ptr.rhs.cast.i = ptrtoint ptr %gep2 to i64 |
| %sub.ptr.sub.i = sub i64 %sub.ptr.lhs.cast.i, %sub.ptr.rhs.cast.i |
| ret i64 %sub.ptr.sub.i |
| } |
| |
| define i64 @nullptrtoint_scalable_c() { |
| ; CHECK-LABEL: @nullptrtoint_scalable_c( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[TMP0:%.*]] = call i64 @llvm.vscale.i64() |
| ; CHECK-NEXT: [[PTR_IDX:%.*]] = shl i64 [[TMP0]], 7 |
| ; CHECK-NEXT: ret i64 [[PTR_IDX]] |
| ; |
| entry: |
| %ptr = getelementptr nusw <vscale x 4 x i32>, ptr null, i64 8 |
| %ret = ptrtoint ptr %ptr to i64 |
| ret i64 %ret |
| } |
| |
| define i64 @nullptrtoint_scalable_x(i64 %x) { |
| ; CHECK-LABEL: @nullptrtoint_scalable_x( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[TMP0:%.*]] = call i64 @llvm.vscale.i64() |
| ; CHECK-NEXT: [[TMP1:%.*]] = shl nuw i64 [[TMP0]], 4 |
| ; CHECK-NEXT: [[PTR_IDX:%.*]] = mul nsw i64 [[X:%.*]], [[TMP1]] |
| ; CHECK-NEXT: ret i64 [[PTR_IDX]] |
| ; |
| entry: |
| %ptr = getelementptr nusw <vscale x 4 x i32>, ptr null, i64 %x |
| %ret = ptrtoint ptr %ptr to i64 |
| ret i64 %ret |
| } |
| |
| define i1 @_gep_phi1(ptr %str1) { |
| ; CHECK-LABEL: @_gep_phi1( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[CMP_I:%.*]] = icmp eq ptr [[STR1:%.*]], null |
| ; CHECK-NEXT: br i1 [[CMP_I]], label [[_Z3FOOPKC_EXIT:%.*]], label [[LOR_LHS_FALSE_I:%.*]] |
| ; CHECK: lor.lhs.false.i: |
| ; CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[STR1]], align 1 |
| ; CHECK-NEXT: [[CMP1_I:%.*]] = icmp eq i8 [[TMP0]], 0 |
| ; CHECK-NEXT: br i1 [[CMP1_I]], label [[_Z3FOOPKC_EXIT]], label [[WHILE_COND_I:%.*]] |
| ; CHECK: while.cond.i: |
| ; CHECK-NEXT: [[A_PN_I:%.*]] = phi ptr [ [[TEST_0_I:%.*]], [[WHILE_COND_I]] ], [ [[STR1]], [[LOR_LHS_FALSE_I]] ] |
| ; CHECK-NEXT: [[TEST_0_I]] = getelementptr inbounds nuw i8, ptr [[A_PN_I]], i64 1 |
| ; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[TEST_0_I]], align 1 |
| ; CHECK-NEXT: [[CMP3_NOT_I:%.*]] = icmp eq i8 [[TMP1]], 0 |
| ; CHECK-NEXT: br i1 [[CMP3_NOT_I]], label [[WHILE_END_I:%.*]], label [[WHILE_COND_I]] |
| ; CHECK: while.end.i: |
| ; CHECK-NEXT: br label [[_Z3FOOPKC_EXIT]] |
| ; CHECK: _Z3fooPKc.exit: |
| ; CHECK-NEXT: [[TOBOOL:%.*]] = phi i1 [ true, [[WHILE_END_I]] ], [ false, [[LOR_LHS_FALSE_I]] ], [ false, [[ENTRY:%.*]] ] |
| ; CHECK-NEXT: ret i1 [[TOBOOL]] |
| ; |
| entry: |
| %cmp.i = icmp eq ptr %str1, null |
| br i1 %cmp.i, label %_Z3fooPKc.exit, label %lor.lhs.false.i |
| |
| lor.lhs.false.i: |
| %0 = load i8, ptr %str1, align 1 |
| %cmp1.i = icmp eq i8 %0, 0 |
| br i1 %cmp1.i, label %_Z3fooPKc.exit, label %while.cond.i |
| |
| while.cond.i: |
| %a.pn.i = phi ptr [ %test.0.i, %while.cond.i ], [ %str1, %lor.lhs.false.i ] |
| %test.0.i = getelementptr inbounds i8, ptr %a.pn.i, i64 1 |
| %1 = load i8, ptr %test.0.i, align 1 |
| %cmp3.not.i = icmp eq i8 %1, 0 |
| br i1 %cmp3.not.i, label %while.end.i, label %while.cond.i |
| |
| while.end.i: |
| %sub.ptr.lhs.cast.i = ptrtoint ptr %test.0.i to i64 |
| %sub.ptr.rhs.cast.i = ptrtoint ptr %str1 to i64 |
| %sub.ptr.sub.i = sub i64 %sub.ptr.lhs.cast.i, %sub.ptr.rhs.cast.i |
| br label %_Z3fooPKc.exit |
| |
| _Z3fooPKc.exit: |
| %retval.0.i = phi i64 [ %sub.ptr.sub.i, %while.end.i ], [ 0, %lor.lhs.false.i ], [ 0, %entry ] |
| %tobool = icmp ne i64 %retval.0.i, 0 |
| ret i1 %tobool |
| } |
| |
| define i1 @_gep_phi2(ptr %str1, i64 %val2) { |
| ; CHECK-LABEL: @_gep_phi2( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[CMP_I:%.*]] = icmp eq ptr [[STR1:%.*]], null |
| ; CHECK-NEXT: br i1 [[CMP_I]], label [[_Z3FOOPKC_EXIT:%.*]], label [[LOR_LHS_FALSE_I:%.*]] |
| ; CHECK: lor.lhs.false.i: |
| ; CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[STR1]], align 1 |
| ; CHECK-NEXT: [[CMP1_I:%.*]] = icmp eq i8 [[TMP0]], 0 |
| ; CHECK-NEXT: br i1 [[CMP1_I]], label [[_Z3FOOPKC_EXIT]], label [[WHILE_COND_I:%.*]] |
| ; CHECK: while.cond.i: |
| ; CHECK-NEXT: [[A_PN_I:%.*]] = phi ptr [ [[TEST_0_I:%.*]], [[WHILE_COND_I]] ], [ [[STR1]], [[LOR_LHS_FALSE_I]] ] |
| ; CHECK-NEXT: [[TEST_0_I]] = getelementptr inbounds nuw i8, ptr [[A_PN_I]], i64 1 |
| ; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[TEST_0_I]], align 1 |
| ; CHECK-NEXT: [[CMP3_NOT_I:%.*]] = icmp eq i8 [[TMP1]], 0 |
| ; CHECK-NEXT: br i1 [[CMP3_NOT_I]], label [[WHILE_END_I:%.*]], label [[WHILE_COND_I]] |
| ; CHECK: while.end.i: |
| ; CHECK-NEXT: br label [[_Z3FOOPKC_EXIT]] |
| ; CHECK: _Z3fooPKc.exit: |
| ; CHECK-NEXT: [[RETVAL_0_I:%.*]] = phi i64 [ 1, [[WHILE_END_I]] ], [ 0, [[LOR_LHS_FALSE_I]] ], [ 0, [[ENTRY:%.*]] ] |
| ; CHECK-NEXT: [[TMP2:%.*]] = or i64 [[RETVAL_0_I]], [[VAL2:%.*]] |
| ; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[TMP2]], 0 |
| ; CHECK-NEXT: ret i1 [[TOBOOL]] |
| ; |
| entry: |
| %cmp.i = icmp eq ptr %str1, null |
| br i1 %cmp.i, label %_Z3fooPKc.exit, label %lor.lhs.false.i |
| |
| lor.lhs.false.i: |
| %0 = load i8, ptr %str1, align 1 |
| %cmp1.i = icmp eq i8 %0, 0 |
| br i1 %cmp1.i, label %_Z3fooPKc.exit, label %while.cond.i |
| |
| while.cond.i: |
| %a.pn.i = phi ptr [ %test.0.i, %while.cond.i ], [ %str1, %lor.lhs.false.i ] |
| %test.0.i = getelementptr inbounds i8, ptr %a.pn.i, i64 1 |
| %1 = load i8, ptr %test.0.i, align 1 |
| %cmp3.not.i = icmp eq i8 %1, 0 |
| br i1 %cmp3.not.i, label %while.end.i, label %while.cond.i |
| |
| while.end.i: |
| %sub.ptr.lhs.cast.i = ptrtoint ptr %test.0.i to i64 |
| %sub.ptr.rhs.cast.i = ptrtoint ptr %str1 to i64 |
| %sub.ptr.sub.i = sub i64 %sub.ptr.lhs.cast.i, %sub.ptr.rhs.cast.i |
| br label %_Z3fooPKc.exit |
| |
| _Z3fooPKc.exit: |
| %retval.0.i = phi i64 [ %sub.ptr.sub.i, %while.end.i ], [ 0, %lor.lhs.false.i ], [ 0, %entry ] |
| %2 = or i64 %retval.0.i, %val2 |
| %tobool = icmp eq i64 %2, 0 |
| ret i1 %tobool |
| } |
| |
| define i64 @multiple_geps_one_chain(ptr %base, i64 %idx, i64 %idx2) { |
| ; CHECK-LABEL: @multiple_geps_one_chain( |
| ; CHECK-NEXT: [[P2_IDX1:%.*]] = add i64 [[IDX:%.*]], [[IDX2:%.*]] |
| ; CHECK-NEXT: [[D:%.*]] = shl i64 [[P2_IDX1]], 2 |
| ; CHECK-NEXT: ret i64 [[D]] |
| ; |
| %p2 = getelementptr inbounds i32, ptr %base, i64 %idx |
| %p3 = getelementptr inbounds i32, ptr %p2, i64 %idx2 |
| %i1 = ptrtoint ptr %base to i64 |
| %i2 = ptrtoint ptr %p3 to i64 |
| %d = sub i64 %i2, %i1 |
| ret i64 %d |
| } |
| |
| define i64 @multiple_geps_one_chain_commuted(ptr %base, i64 %idx, i64 %idx2) { |
| ; CHECK-LABEL: @multiple_geps_one_chain_commuted( |
| ; CHECK-NEXT: [[P2_IDX1:%.*]] = add i64 [[IDX:%.*]], [[IDX2:%.*]] |
| ; CHECK-NEXT: [[DOTNEG:%.*]] = mul i64 [[P2_IDX1]], -4 |
| ; CHECK-NEXT: ret i64 [[DOTNEG]] |
| ; |
| %p2 = getelementptr inbounds i32, ptr %base, i64 %idx |
| %p3 = getelementptr inbounds i32, ptr %p2, i64 %idx2 |
| %i1 = ptrtoint ptr %base to i64 |
| %i2 = ptrtoint ptr %p3 to i64 |
| %d = sub i64 %i1, %i2 |
| ret i64 %d |
| } |
| |
| define i64 @multiple_geps_two_chains(ptr %base, i64 %idx, i64 %idx2, i64 %idx3) { |
| ; CHECK-LABEL: @multiple_geps_two_chains( |
| ; CHECK-NEXT: [[P2_IDX1:%.*]] = add i64 [[IDX:%.*]], [[IDX2:%.*]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = sub i64 [[P2_IDX1]], [[IDX3:%.*]] |
| ; CHECK-NEXT: [[GEPDIFF:%.*]] = shl i64 [[TMP1]], 2 |
| ; CHECK-NEXT: ret i64 [[GEPDIFF]] |
| ; |
| %p2 = getelementptr inbounds i32, ptr %base, i64 %idx |
| %p3 = getelementptr inbounds i32, ptr %p2, i64 %idx2 |
| %p4 = getelementptr inbounds i32, ptr %base, i64 %idx3 |
| %i1 = ptrtoint ptr %p4 to i64 |
| %i2 = ptrtoint ptr %p3 to i64 |
| %d = sub i64 %i2, %i1 |
| ret i64 %d |
| } |
| |
| define i64 @multiple_geps_two_chains_commuted(ptr %base, i64 %idx, i64 %idx2, i64 %idx3) { |
| ; CHECK-LABEL: @multiple_geps_two_chains_commuted( |
| ; CHECK-NEXT: [[P2_IDX1:%.*]] = add i64 [[IDX:%.*]], [[IDX2:%.*]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = sub i64 [[IDX3:%.*]], [[P2_IDX1]] |
| ; CHECK-NEXT: [[GEPDIFF:%.*]] = shl i64 [[TMP1]], 2 |
| ; CHECK-NEXT: ret i64 [[GEPDIFF]] |
| ; |
| %p2 = getelementptr inbounds i32, ptr %base, i64 %idx |
| %p3 = getelementptr inbounds i32, ptr %p2, i64 %idx2 |
| %p4 = getelementptr inbounds i32, ptr %base, i64 %idx3 |
| %i1 = ptrtoint ptr %p4 to i64 |
| %i2 = ptrtoint ptr %p3 to i64 |
| %d = sub i64 %i1, %i2 |
| ret i64 %d |
| } |
| |
| declare void @use(ptr) |
| |
| define i64 @multiple_geps_two_chains_gep_base(ptr %base, i64 %base.idx, i64 %idx, i64 %idx2, i64 %idx3) { |
| ; CHECK-LABEL: @multiple_geps_two_chains_gep_base( |
| ; CHECK-NEXT: [[GEP_BASE:%.*]] = getelementptr inbounds i32, ptr [[BASE:%.*]], i64 [[BASE_IDX:%.*]] |
| ; CHECK-NEXT: call void @use(ptr [[GEP_BASE]]) |
| ; CHECK-NEXT: [[P2_IDX1:%.*]] = add i64 [[IDX:%.*]], [[IDX2:%.*]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = sub i64 [[P2_IDX1]], [[IDX3:%.*]] |
| ; CHECK-NEXT: [[GEPDIFF:%.*]] = shl i64 [[TMP1]], 2 |
| ; CHECK-NEXT: ret i64 [[GEPDIFF]] |
| ; |
| %gep.base = getelementptr inbounds i32, ptr %base, i64 %base.idx |
| call void @use(ptr %gep.base) |
| %p2 = getelementptr inbounds i32, ptr %gep.base, i64 %idx |
| %p3 = getelementptr inbounds i32, ptr %p2, i64 %idx2 |
| %p4 = getelementptr inbounds i32, ptr %gep.base, i64 %idx3 |
| %i1 = ptrtoint ptr %p4 to i64 |
| %i2 = ptrtoint ptr %p3 to i64 |
| %d = sub i64 %i2, %i1 |
| ret i64 %d |
| } |
| |
| define i64 @multiple_geps_two_chains_multi_use(ptr %base, i64 %idx1, i64 %idx2, i64 %idx3, i64 %idx4) { |
| ; CHECK-LABEL: @multiple_geps_two_chains_multi_use( |
| ; CHECK-NEXT: [[P1_IDX1:%.*]] = add i64 [[IDX1:%.*]], [[IDX2:%.*]] |
| ; CHECK-NEXT: [[P4_IDX:%.*]] = shl i64 [[P1_IDX1]], 2 |
| ; CHECK-NEXT: [[P5:%.*]] = getelementptr inbounds i8, ptr [[P2:%.*]], i64 [[P4_IDX]] |
| ; CHECK-NEXT: [[P3_IDX2:%.*]] = add i64 [[IDX3:%.*]], [[IDX4:%.*]] |
| ; CHECK-NEXT: [[P4_IDX1:%.*]] = shl i64 [[P3_IDX2]], 2 |
| ; CHECK-NEXT: [[P4:%.*]] = getelementptr inbounds i8, ptr [[P2]], i64 [[P4_IDX1]] |
| ; CHECK-NEXT: call void @use(ptr [[P5]]) |
| ; CHECK-NEXT: call void @use(ptr [[P4]]) |
| ; CHECK-NEXT: [[GEPDIFF:%.*]] = sub nsw i64 [[P4_IDX]], [[P4_IDX1]] |
| ; CHECK-NEXT: ret i64 [[GEPDIFF]] |
| ; |
| %p1 = getelementptr inbounds i32, ptr %base, i64 %idx1 |
| %p2 = getelementptr inbounds i32, ptr %p1, i64 %idx2 |
| %p3 = getelementptr inbounds i32, ptr %base, i64 %idx3 |
| %p4 = getelementptr inbounds i32, ptr %p3, i64 %idx4 |
| call void @use(ptr %p2) |
| call void @use(ptr %p4) |
| %i1 = ptrtoint ptr %p4 to i64 |
| %i2 = ptrtoint ptr %p2 to i64 |
| %d = sub i64 %i2, %i1 |
| ret i64 %d |
| } |
| |
| define i64 @multiple_geps_two_chains_partial_multi_use(ptr %base, i64 %idx1, i64 %idx2, i64 %idx3, i64 %idx4, i64 %idx5, i64 %idx6) { |
| ; CHECK-LABEL: @multiple_geps_two_chains_partial_multi_use( |
| ; CHECK-NEXT: [[P1_IDX1:%.*]] = add i64 [[IDX1:%.*]], [[IDX2:%.*]] |
| ; CHECK-NEXT: [[P4_IDX:%.*]] = shl i64 [[P1_IDX1]], 2 |
| ; CHECK-NEXT: [[P3:%.*]] = getelementptr inbounds i8, ptr [[P2:%.*]], i64 [[P4_IDX]] |
| ; CHECK-NEXT: [[P4_IDX2:%.*]] = add i64 [[IDX4:%.*]], [[IDX5:%.*]] |
| ; CHECK-NEXT: [[P5_IDX:%.*]] = shl i64 [[P4_IDX2]], 2 |
| ; CHECK-NEXT: [[P4:%.*]] = getelementptr inbounds i8, ptr [[P2]], i64 [[P5_IDX]] |
| ; CHECK-NEXT: call void @use(ptr [[P3]]) |
| ; CHECK-NEXT: call void @use(ptr [[P4]]) |
| ; CHECK-NEXT: [[TMP3:%.*]] = add i64 [[P1_IDX1]], [[IDX3:%.*]] |
| ; CHECK-NEXT: [[TMP4:%.*]] = add i64 [[P4_IDX2]], [[IDX6:%.*]] |
| ; CHECK-NEXT: [[TMP5:%.*]] = sub i64 [[TMP3]], [[TMP4]] |
| ; CHECK-NEXT: [[GEPDIFF:%.*]] = shl i64 [[TMP5]], 2 |
| ; CHECK-NEXT: ret i64 [[GEPDIFF]] |
| ; |
| %p1 = getelementptr inbounds i32, ptr %base, i64 %idx1 |
| %p2 = getelementptr inbounds i32, ptr %p1, i64 %idx2 |
| %p3 = getelementptr inbounds i32, ptr %p2, i64 %idx3 |
| %p4 = getelementptr inbounds i32, ptr %base, i64 %idx4 |
| %p5 = getelementptr inbounds i32, ptr %p4, i64 %idx5 |
| %p6 = getelementptr inbounds i32, ptr %p5, i64 %idx6 |
| call void @use(ptr %p2) |
| call void @use(ptr %p5) |
| %i1 = ptrtoint ptr %p6 to i64 |
| %i2 = ptrtoint ptr %p3 to i64 |
| %d = sub i64 %i2, %i1 |
| ret i64 %d |
| } |
| |
| define i64 @multiple_geps_two_chains_partial_multi_use_insert_point(ptr %p, i64 %idx1, i64 %idx2, i64 %idx3) { |
| ; CHECK-LABEL: @multiple_geps_two_chains_partial_multi_use_insert_point( |
| ; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 8 |
| ; CHECK-NEXT: call void @use(ptr [[GEP2]]) |
| ; CHECK-NEXT: [[TMP1:%.*]] = add i64 [[IDX2:%.*]], [[IDX3:%.*]] |
| ; CHECK-NEXT: [[GEP4:%.*]] = getelementptr i8, ptr [[GEP2]], i64 [[TMP1]] |
| ; CHECK-NEXT: call void @use(ptr [[GEP4]]) |
| ; CHECK-NEXT: [[TMP2:%.*]] = add i64 [[TMP1]], 8 |
| ; CHECK-NEXT: [[GEPDIFF:%.*]] = sub i64 [[IDX1:%.*]], [[TMP2]] |
| ; CHECK-NEXT: ret i64 [[GEPDIFF]] |
| ; |
| %gep1 = getelementptr i8, ptr %p, i64 %idx1 |
| %gep2 = getelementptr i8, ptr %p, i64 8 |
| call void @use(ptr %gep2) |
| %gep3 = getelementptr i8, ptr %gep2, i64 %idx2 |
| %gep4 = getelementptr i8, ptr %gep3, i64 %idx3 |
| call void @use(ptr %gep4) |
| %gep1.int = ptrtoint ptr %gep1 to i64 |
| %gep4.int = ptrtoint ptr %gep4 to i64 |
| %sub = sub i64 %gep1.int, %gep4.int |
| ret i64 %sub |
| } |
| |
| define i64 @multiple_geps_inbounds(ptr %base, i64 %idx, i64 %idx2) { |
| ; CHECK-LABEL: @multiple_geps_inbounds( |
| ; CHECK-NEXT: [[D:%.*]] = add nsw i64 [[IDX:%.*]], [[IDX2:%.*]] |
| ; CHECK-NEXT: ret i64 [[D]] |
| ; |
| %p2 = getelementptr inbounds i8, ptr %base, i64 %idx |
| %p3 = getelementptr inbounds i8, ptr %p2, i64 %idx2 |
| %i1 = ptrtoint ptr %base to i64 |
| %i2 = ptrtoint ptr %p3 to i64 |
| %d = sub i64 %i2, %i1 |
| ret i64 %d |
| } |
| |
| define i64 @multiple_geps_nusw(ptr %base, i64 %idx, i64 %idx2) { |
| ; CHECK-LABEL: @multiple_geps_nusw( |
| ; CHECK-NEXT: [[D:%.*]] = add i64 [[IDX:%.*]], [[IDX2:%.*]] |
| ; CHECK-NEXT: ret i64 [[D]] |
| ; |
| %p2 = getelementptr nusw i8, ptr %base, i64 %idx |
| %p3 = getelementptr nusw i8, ptr %p2, i64 %idx2 |
| %i1 = ptrtoint ptr %base to i64 |
| %i2 = ptrtoint ptr %p3 to i64 |
| %d = sub i64 %i2, %i1 |
| ret i64 %d |
| } |
| |
| define i64 @multiple_geps_nuw(ptr %base, i64 %idx, i64 %idx2) { |
| ; CHECK-LABEL: @multiple_geps_nuw( |
| ; CHECK-NEXT: [[D:%.*]] = add nuw i64 [[IDX:%.*]], [[IDX2:%.*]] |
| ; CHECK-NEXT: ret i64 [[D]] |
| ; |
| %p2 = getelementptr nuw i8, ptr %base, i64 %idx |
| %p3 = getelementptr nuw i8, ptr %p2, i64 %idx2 |
| %i1 = ptrtoint ptr %base to i64 |
| %i2 = ptrtoint ptr %p3 to i64 |
| %d = sub i64 %i2, %i1 |
| ret i64 %d |
| } |
| |
| |
| define i64 @multiple_geps_inbounds_nuw(ptr %base, i64 %idx, i64 %idx2) { |
| ; CHECK-LABEL: @multiple_geps_inbounds_nuw( |
| ; CHECK-NEXT: [[D:%.*]] = add nuw nsw i64 [[IDX:%.*]], [[IDX2:%.*]] |
| ; CHECK-NEXT: ret i64 [[D]] |
| ; |
| %p2 = getelementptr inbounds nuw i8, ptr %base, i64 %idx |
| %p3 = getelementptr inbounds nuw i8, ptr %p2, i64 %idx2 |
| %i1 = ptrtoint ptr %base to i64 |
| %i2 = ptrtoint ptr %p3 to i64 |
| %d = sub i64 %i2, %i1 |
| ret i64 %d |
| } |
| |
| define <2 x i64> @splat_geps(ptr %base, <2 x i64> %idx1, <2 x i64> %idx2) { |
| ; CHECK-LABEL: @splat_geps( |
| ; CHECK-NEXT: [[D:%.*]] = sub nsw <2 x i64> [[IDX2:%.*]], [[IDX1:%.*]] |
| ; CHECK-NEXT: ret <2 x i64> [[D]] |
| ; |
| %gep1 = getelementptr inbounds i8, ptr %base, <2 x i64> %idx1 |
| %gep2 = getelementptr inbounds i8, ptr %base, <2 x i64> %idx2 |
| %gep1.int = ptrtoint <2 x ptr> %gep1 to <2 x i64> |
| %gep2.int = ptrtoint <2 x ptr> %gep2 to <2 x i64> |
| %d = sub <2 x i64> %gep2.int, %gep1.int |
| ret <2 x i64> %d |
| } |
| |
| define <2 x i64> @splat_geps_multiple(ptr %base, i64 %idx0, <2 x i64> %idx1, <2 x i64> %idx2) { |
| ; CHECK-LABEL: @splat_geps_multiple( |
| ; CHECK-NEXT: [[DOTSPLATINSERT:%.*]] = insertelement <2 x i64> poison, i64 [[IDX0:%.*]], i64 0 |
| ; CHECK-NEXT: [[DOTSPLAT:%.*]] = shufflevector <2 x i64> [[DOTSPLATINSERT]], <2 x i64> poison, <2 x i32> zeroinitializer |
| ; CHECK-NEXT: [[TMP1:%.*]] = add nsw <2 x i64> [[DOTSPLAT]], [[IDX1:%.*]] |
| ; CHECK-NEXT: [[D:%.*]] = sub nsw <2 x i64> [[IDX2:%.*]], [[TMP1]] |
| ; CHECK-NEXT: ret <2 x i64> [[D]] |
| ; |
| %gep0 = getelementptr inbounds i8, ptr %base, i64 %idx0 |
| %gep1 = getelementptr inbounds i8, ptr %gep0, <2 x i64> %idx1 |
| %gep2 = getelementptr inbounds i8, ptr %base, <2 x i64> %idx2 |
| %gep1.int = ptrtoint <2 x ptr> %gep1 to <2 x i64> |
| %gep2.int = ptrtoint <2 x ptr> %gep2 to <2 x i64> |
| %d = sub <2 x i64> %gep2.int, %gep1.int |
| ret <2 x i64> %d |
| } |
| |
| define i64 @nuw_ptrdiff_shl_nsw(ptr %base, i64 %idx) { |
| ; CHECK-LABEL: @nuw_ptrdiff_shl_nsw( |
| ; CHECK-NEXT: [[OFFSET:%.*]] = shl nuw nsw i64 [[IDX:%.*]], 3 |
| ; CHECK-NEXT: ret i64 [[OFFSET]] |
| ; |
| %offset = shl nsw i64 %idx, 3 |
| %gep = getelementptr inbounds i8, ptr %base, i64 %offset |
| %lhs = ptrtoint ptr %gep to i64 |
| %rhs = ptrtoint ptr %base to i64 |
| %diff = sub nuw i64 %lhs, %rhs |
| ret i64 %diff |
| } |
| |
| define i64 @nuw_ptrdiff_shl_nonsw(ptr %base, i64 %idx) { |
| ; CHECK-LABEL: @nuw_ptrdiff_shl_nonsw( |
| ; CHECK-NEXT: [[OFFSET:%.*]] = shl i64 [[IDX:%.*]], 3 |
| ; CHECK-NEXT: ret i64 [[OFFSET]] |
| ; |
| %offset = shl i64 %idx, 3 |
| %gep = getelementptr inbounds i8, ptr %base, i64 %offset |
| %lhs = ptrtoint ptr %gep to i64 |
| %rhs = ptrtoint ptr %base to i64 |
| %diff = sub nuw i64 %lhs, %rhs |
| ret i64 %diff |
| } |
| |
| define i64 @nuw_ptrdiff_mul_nsw_nneg_scale(ptr %base, i64 %idx) { |
| ; CHECK-LABEL: @nuw_ptrdiff_mul_nsw_nneg_scale( |
| ; CHECK-NEXT: [[OFFSET:%.*]] = mul nuw nsw i64 [[IDX:%.*]], 3 |
| ; CHECK-NEXT: ret i64 [[OFFSET]] |
| ; |
| %offset = mul nsw i64 %idx, 3 |
| %gep = getelementptr inbounds i8, ptr %base, i64 %offset |
| %lhs = ptrtoint ptr %gep to i64 |
| %rhs = ptrtoint ptr %base to i64 |
| %diff = sub nuw i64 %lhs, %rhs |
| ret i64 %diff |
| } |
| |
| define i64 @nuw_ptrdiff_mul_nsw_unknown_scale(ptr %base, i64 %idx, i64 %scale) { |
| ; CHECK-LABEL: @nuw_ptrdiff_mul_nsw_unknown_scale( |
| ; CHECK-NEXT: [[OFFSET:%.*]] = mul nsw i64 [[IDX:%.*]], [[SCALE:%.*]] |
| ; CHECK-NEXT: ret i64 [[OFFSET]] |
| ; |
| %offset = mul nsw i64 %idx, %scale |
| %gep = getelementptr inbounds i8, ptr %base, i64 %offset |
| %lhs = ptrtoint ptr %gep to i64 |
| %rhs = ptrtoint ptr %base to i64 |
| %diff = sub nuw i64 %lhs, %rhs |
| ret i64 %diff |
| } |
| |
| declare void @usei64(i64) |
| |
| define i64 @nuw_ptrdiff_mul_nsw_nneg_scale_multiuse(ptr %base, i64 %idx) { |
| ; CHECK-LABEL: @nuw_ptrdiff_mul_nsw_nneg_scale_multiuse( |
| ; CHECK-NEXT: [[OFFSET:%.*]] = mul nsw i64 [[IDX:%.*]], 3 |
| ; CHECK-NEXT: call void @usei64(i64 [[OFFSET]]) |
| ; CHECK-NEXT: ret i64 [[OFFSET]] |
| ; |
| %offset = mul nsw i64 %idx, 3 |
| call void @usei64(i64 %offset) |
| %gep = getelementptr inbounds i8, ptr %base, i64 %offset |
| %lhs = ptrtoint ptr %gep to i64 |
| %rhs = ptrtoint ptr %base to i64 |
| %diff = sub nuw i64 %lhs, %rhs |
| ret i64 %diff |
| } |
| |
| define i64 @multiple_geps_multi_use_below_limit(ptr %base, i64 %idx1, i64 %idx2, i64 %idx3, i64 %idx4) { |
| ; CHECK-LABEL: @multiple_geps_multi_use_below_limit( |
| ; CHECK-NEXT: [[P2:%.*]] = getelementptr inbounds nuw i8, ptr [[P1:%.*]], i64 [[IDX2:%.*]] |
| ; CHECK-NEXT: call void @use(ptr [[P2]]) |
| ; CHECK-NEXT: [[P4:%.*]] = getelementptr inbounds nuw i8, ptr [[P2]], i64 [[IDX5:%.*]] |
| ; CHECK-NEXT: call void @use(ptr [[P4]]) |
| ; CHECK-NEXT: [[P3:%.*]] = getelementptr inbounds nuw i8, ptr [[P1]], i64 [[IDX3:%.*]] |
| ; CHECK-NEXT: call void @use(ptr [[P3]]) |
| ; CHECK-NEXT: [[P5:%.*]] = getelementptr inbounds nuw i8, ptr [[P3]], i64 [[IDX4:%.*]] |
| ; CHECK-NEXT: call void @use(ptr [[P5]]) |
| ; CHECK-NEXT: [[TMP1:%.*]] = add nuw nsw i64 [[IDX2]], [[IDX5]] |
| ; CHECK-NEXT: [[TMP2:%.*]] = add nuw nsw i64 [[IDX3]], [[IDX4]] |
| ; CHECK-NEXT: [[GEPDIFF:%.*]] = sub nsw i64 [[TMP1]], [[TMP2]] |
| ; CHECK-NEXT: ret i64 [[GEPDIFF]] |
| ; |
| %p1 = getelementptr inbounds nuw i8, ptr %base, i64 %idx1 |
| call void @use(ptr %p1) |
| %p2 = getelementptr inbounds nuw i8, ptr %p1, i64 %idx2 |
| call void @use(ptr %p2) |
| %p3 = getelementptr inbounds nuw i8, ptr %base, i64 %idx3 |
| call void @use(ptr %p3) |
| %p4 = getelementptr inbounds nuw i8, ptr %p3, i64 %idx4 |
| call void @use(ptr %p4) |
| %i1 = ptrtoint ptr %p4 to i64 |
| %i2 = ptrtoint ptr %p2 to i64 |
| %d = sub i64 %i2, %i1 |
| ret i64 %d |
| } |
| |
| define i64 @multiple_geps_multi_use_above_limit(ptr %base, i64 %idx1, i64 %idx2, i64 %idx3, i64 %idx4, i64 %idx5) { |
| ; CHECK-LABEL: @multiple_geps_multi_use_above_limit( |
| ; CHECK-NEXT: [[P2:%.*]] = getelementptr inbounds nuw i8, ptr [[P1:%.*]], i64 [[IDX2:%.*]] |
| ; CHECK-NEXT: call void @use(ptr [[P2]]) |
| ; CHECK-NEXT: [[P3:%.*]] = getelementptr inbounds nuw i8, ptr [[P2]], i64 [[IDX6:%.*]] |
| ; CHECK-NEXT: call void @use(ptr [[P3]]) |
| ; CHECK-NEXT: [[P5:%.*]] = getelementptr inbounds nuw i8, ptr [[P1]], i64 [[TMP3:%.*]] |
| ; CHECK-NEXT: call void @use(ptr [[P5]]) |
| ; CHECK-NEXT: [[P6:%.*]] = getelementptr inbounds nuw i8, ptr [[P5]], i64 [[IDX7:%.*]] |
| ; CHECK-NEXT: call void @use(ptr [[P6]]) |
| ; CHECK-NEXT: [[P7:%.*]] = getelementptr inbounds nuw i8, ptr [[P6]], i64 [[IDX5:%.*]] |
| ; CHECK-NEXT: call void @use(ptr [[P7]]) |
| ; CHECK-NEXT: [[I1:%.*]] = ptrtoint ptr [[P7]] to i64 |
| ; CHECK-NEXT: [[I2:%.*]] = ptrtoint ptr [[P3]] to i64 |
| ; CHECK-NEXT: [[D:%.*]] = sub i64 [[I2]], [[I1]] |
| ; CHECK-NEXT: ret i64 [[D]] |
| ; |
| %p1 = getelementptr inbounds nuw i8, ptr %base, i64 %idx1 |
| call void @use(ptr %p1) |
| %p2 = getelementptr inbounds nuw i8, ptr %p1, i64 %idx2 |
| call void @use(ptr %p2) |
| %p3 = getelementptr inbounds nuw i8, ptr %base, i64 %idx3 |
| call void @use(ptr %p3) |
| %p4 = getelementptr inbounds nuw i8, ptr %p3, i64 %idx4 |
| call void @use(ptr %p4) |
| %p5 = getelementptr inbounds nuw i8, ptr %p4, i64 %idx5 |
| call void @use(ptr %p5) |
| %i1 = ptrtoint ptr %p5 to i64 |
| %i2 = ptrtoint ptr %p2 to i64 |
| %d = sub i64 %i2, %i1 |
| ret i64 %d |
| } |