The idea behind this canonicalization is that it allows us to handle less patterns, because we know that some will be canonicalized away. This is indeed very useful to e.g. know that constants are always on the right. However, this is only useful if the canonicalization is actually reliable. This is the case for constants, but not for arguments: Moving these to the right makes it look like the "more complex" expression is guaranteed to be on the left, but this is not actually the case in practice. It fails as soon as you replace the argument with another instruction. The end result is that it looks like things correctly work in tests, while they actually don't. We use the "thwart complexity-based canonicalization" trick to handle this in tests, but it's often a challenge for new contributors to get this right, and based on the regressions this PR originally exposed, we clearly don't get this right in many cases. For this reason, I think that it's better to remove this complexity canonicalization. It will make it much easier to write tests for commuted cases and make sure that they are handled.
534 lines
18 KiB
LLVM
534 lines
18 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: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"
|
|
|
|
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_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 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
|
|
}
|
|
|
|
@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 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
|
|
}
|
|
|
|
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 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 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
|
|
}
|