; 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 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 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_IDX:%.*]] = shl nsw i64 [[IDX:%.*]], 3
; CHECK-NEXT:    [[P2_IDX1:%.*]] = shl nsw i64 [[IDX2:%.*]], 2
; CHECK-NEXT:    [[P2_OFFS:%.*]] = add nsw i64 [[P2_IDX]], [[P2_IDX1]]
; CHECK-NEXT:    ret i64 [[P2_OFFS]]
;
  %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:    [[DIFF_NEG:%.*]] = sub i64 0, [[A:%.*]]
; CHECK-NEXT:    ret i64 [[DIFF_NEG]]
;
  %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:    [[DIFF_NEG:%.*]] = sub i16 0, [[A:%.*]]
; CHECK-NEXT:    ret i16 [[DIFF_NEG]]
;
  %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 nuw 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 nuw 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 i64 [[A:%.*]] to i16
; CHECK-NEXT:    [[B_IDX:%.*]] = shl nuw 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 nuw 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 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 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 inbounds <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 i64 [[TMP0]], 4
; CHECK-NEXT:    [[PTR_IDX:%.*]] = mul nsw i64 [[X:%.*]], [[TMP1]]
; CHECK-NEXT:    ret i64 [[PTR_IDX]]
;
entry:
  %ptr = getelementptr inbounds <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
}
