llvm/llvm/test/Transforms/CorrelatedValuePropagation/uscmp.ll

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -passes=correlated-propagation -S | FileCheck %s

; If nothing is known we can't change anything
define i8 @ucmp_0(i32 %x, i32 %y) {
; CHECK-LABEL: @ucmp_0(
; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X:%.*]], i32 [[Y:%.*]])
; CHECK-NEXT:    ret i8 [[TMP1]]
;
  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
  ret i8 %1
}

define i8 @scmp_0(i32 %x, i32 %y) {
; CHECK-LABEL: @scmp_0(
; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X:%.*]], i32 [[Y:%.*]])
; CHECK-NEXT:    ret i8 [[TMP1]]
;
  %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
  ret i8 %1
}

; If we know that range of LHS < range of RHS then return -1
define i8 @ucmp_1(i32 %x, i32 %y) {
  ; X is within [4, 8)
; CHECK-LABEL: @ucmp_1(
; CHECK-NEXT:    [[COND1:%.*]] = icmp uge i32 [[X:%.*]], 4
; CHECK-NEXT:    call void @llvm.assume(i1 [[COND1]])
; CHECK-NEXT:    [[COND2:%.*]] = icmp ult i32 [[X]], 8
; CHECK-NEXT:    call void @llvm.assume(i1 [[COND2]])
; CHECK-NEXT:    [[COND3:%.*]] = icmp uge i32 [[Y:%.*]], 8
; CHECK-NEXT:    call void @llvm.assume(i1 [[COND3]])
; CHECK-NEXT:    ret i8 -1
;
  %cond1 = icmp uge i32 %x, 4
  call void @llvm.assume(i1 %cond1)
  %cond2 = icmp ult i32 %x, 8
  call void @llvm.assume(i1 %cond2)
  ; Y is within [8, UNSIGNED_MAX)
  %cond3 = icmp uge i32 %y, 8
  call void @llvm.assume(i1 %cond3)

  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
  ret i8 %1
}

define i8 @scmp_1(i32 %x, i32 %y) {
  ; X is within [-5, 3)
; CHECK-LABEL: @scmp_1(
; CHECK-NEXT:    [[COND1:%.*]] = icmp sge i32 [[X:%.*]], -5
; CHECK-NEXT:    call void @llvm.assume(i1 [[COND1]])
; CHECK-NEXT:    [[COND2:%.*]] = icmp slt i32 [[X]], 3
; CHECK-NEXT:    call void @llvm.assume(i1 [[COND2]])
; CHECK-NEXT:    [[COND3:%.*]] = icmp sge i32 [[Y:%.*]], 3
; CHECK-NEXT:    call void @llvm.assume(i1 [[COND3]])
; CHECK-NEXT:    ret i8 -1
;
  %cond1 = icmp sge i32 %x, -5
  call void @llvm.assume(i1 %cond1)
  %cond2 = icmp slt i32 %x, 3
  call void @llvm.assume(i1 %cond2)
  ; Y is within [3, SIGNED_MAX)
  %cond3 = icmp sge i32 %y, 3
  call void @llvm.assume(i1 %cond3)

  %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
  ret i8 %1
}

; If we know that range of LHS > range of RHS then return 1
define i8 @ucmp_2(i32 %x, i32 %y) {
  ; X is within [4, UNSIGNED_MAX)
; CHECK-LABEL: @ucmp_2(
; CHECK-NEXT:    [[COND1:%.*]] = icmp uge i32 [[X:%.*]], 4
; CHECK-NEXT:    call void @llvm.assume(i1 [[COND1]])
; CHECK-NEXT:    [[COND2:%.*]] = icmp ult i32 [[Y:%.*]], 4
; CHECK-NEXT:    call void @llvm.assume(i1 [[COND2]])
; CHECK-NEXT:    ret i8 1
;
  %cond1 = icmp uge i32 %x, 4
  call void @llvm.assume(i1 %cond1)
  ; Y is within [0, 4)
  %cond2 = icmp ult i32 %y, 4
  call void @llvm.assume(i1 %cond2)

  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
  ret i8 %1
}

define i8 @scmp_2(i32 %x, i32 %y) {
  ; X is within [4, SIGNED_MAX)
; CHECK-LABEL: @scmp_2(
; CHECK-NEXT:    [[COND1:%.*]] = icmp sge i32 [[X:%.*]], 4
; CHECK-NEXT:    call void @llvm.assume(i1 [[COND1]])
; CHECK-NEXT:    [[COND2:%.*]] = icmp slt i32 [[Y:%.*]], 4
; CHECK-NEXT:    call void @llvm.assume(i1 [[COND2]])
; CHECK-NEXT:    ret i8 1
;
  %cond1 = icmp sge i32 %x, 4
  call void @llvm.assume(i1 %cond1)
  ; Y is within [SIGNED_MIN, 4)
  %cond2 = icmp slt i32 %y, 4
  call void @llvm.assume(i1 %cond2)

  %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
  ret i8 %1
}

; If we know that LHS and RHS are both constants then return 0
define i8 @ucmp_5(i32 %x, i32 %y) {
; CHECK-LABEL: @ucmp_5(
; CHECK-NEXT:    [[COND1:%.*]] = icmp eq i32 [[X:%.*]], 4
; CHECK-NEXT:    call void @llvm.assume(i1 [[COND1]])
; CHECK-NEXT:    [[COND2:%.*]] = icmp eq i32 [[Y:%.*]], 4
; CHECK-NEXT:    call void @llvm.assume(i1 [[COND2]])
; CHECK-NEXT:    ret i8 0
;
  %cond1 = icmp eq i32 %x, 4
  call void @llvm.assume(i1 %cond1)
  %cond2 = icmp eq i32 %y, 4
  call void @llvm.assume(i1 %cond2)

  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
  ret i8 %1
}

define i8 @scmp_5(i32 %x, i32 %y) {
; CHECK-LABEL: @scmp_5(
; CHECK-NEXT:    [[COND1:%.*]] = icmp eq i32 [[X:%.*]], -5
; CHECK-NEXT:    call void @llvm.assume(i1 [[COND1]])
; CHECK-NEXT:    [[COND2:%.*]] = icmp eq i32 [[Y:%.*]], -5
; CHECK-NEXT:    call void @llvm.assume(i1 [[COND2]])
; CHECK-NEXT:    ret i8 0
;
  %cond1 = icmp eq i32 %x, -5
  call void @llvm.assume(i1 %cond1)
  %cond2 = icmp eq i32 %y, -5
  call void @llvm.assume(i1 %cond2)

  %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
  ret i8 %1
}

; We can infer ranges based on the location where a UCMP/SCMP result is used
define i8 @scmp_6(i32 noundef %x) {
; CHECK-LABEL: @scmp_6(
; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i32 [[X:%.*]], 10
; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[TMP1]], i8 -1, i8 5
; CHECK-NEXT:    ret i8 [[TMP2]]
;
  %1 = icmp slt i32 %x, 10
  %2 = call i8 @llvm.scmp(i32 %x, i32 10)
  %3 = select i1 %1, i8 %2, i8 5
  ret i8 %3
}

; Negative test: ranges overlap
define i8 @ucmp_3(i32 %x, i32 %y) {
  ; X is within [4, UNSIGNED_MAX)
; CHECK-LABEL: @ucmp_3(
; CHECK-NEXT:    [[COND1:%.*]] = icmp uge i32 [[X:%.*]], 4
; CHECK-NEXT:    call void @llvm.assume(i1 [[COND1]])
; CHECK-NEXT:    [[COND2:%.*]] = icmp ult i32 [[Y:%.*]], 6
; CHECK-NEXT:    call void @llvm.assume(i1 [[COND2]])
; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
; CHECK-NEXT:    ret i8 [[TMP1]]
;
  %cond1 = icmp uge i32 %x, 4
  call void @llvm.assume(i1 %cond1)
  ; Y is within [0, 6)
  %cond2 = icmp ult i32 %y, 6
  call void @llvm.assume(i1 %cond2)

  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
  ret i8 %1
}

define i8 @scmp_3(i32 %x, i32 %y) {
  ; X is within [2, SIGNED_MAX)
; CHECK-LABEL: @scmp_3(
; CHECK-NEXT:    [[COND1:%.*]] = icmp sge i32 [[X:%.*]], 2
; CHECK-NEXT:    call void @llvm.assume(i1 [[COND1]])
; CHECK-NEXT:    [[COND2:%.*]] = icmp slt i32 [[Y:%.*]], 4
; CHECK-NEXT:    call void @llvm.assume(i1 [[COND2]])
; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
; CHECK-NEXT:    ret i8 [[TMP1]]
;
  %cond1 = icmp sge i32 %x, 2
  call void @llvm.assume(i1 %cond1)
  ; Y is within [SIGNED_MIN, 4)
  %cond2 = icmp slt i32 %y, 4
  call void @llvm.assume(i1 %cond2)

  %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
  ret i8 %1
}

; Negative test: mismatched signedness of range-establishing comparisons and
;                of the intrinsic
define i8 @ucmp_4(i32 %x, i32 %y) {
  ; X is within [4, SIGNED_MAX)
; CHECK-LABEL: @ucmp_4(
; CHECK-NEXT:    [[COND1:%.*]] = icmp sge i32 [[X:%.*]], 4
; CHECK-NEXT:    call void @llvm.assume(i1 [[COND1]])
; CHECK-NEXT:    [[COND2:%.*]] = icmp slt i32 [[Y:%.*]], 4
; CHECK-NEXT:    call void @llvm.assume(i1 [[COND2]])
; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
; CHECK-NEXT:    ret i8 [[TMP1]]
;
  %cond1 = icmp sge i32 %x, 4
  call void @llvm.assume(i1 %cond1)
  ; Y is within [0, 4)
  %cond2 = icmp slt i32 %y, 4
  call void @llvm.assume(i1 %cond2)

  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
  ret i8 %1
}

define i8 @scmp_4(i32 %x, i32 %y) {
  ; X is within [4, UNSIGNED_MAX)
; CHECK-LABEL: @scmp_4(
; CHECK-NEXT:    [[COND1:%.*]] = icmp uge i32 [[X:%.*]], 4
; CHECK-NEXT:    call void @llvm.assume(i1 [[COND1]])
; CHECK-NEXT:    [[COND2:%.*]] = icmp ult i32 [[Y:%.*]], 4
; CHECK-NEXT:    call void @llvm.assume(i1 [[COND2]])
; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
; CHECK-NEXT:    ret i8 [[TMP1]]
;
  %cond1 = icmp uge i32 %x, 4
  call void @llvm.assume(i1 %cond1)
  ; Y is within [0, 4)
  %cond2 = icmp ult i32 %y, 4
  call void @llvm.assume(i1 %cond2)

  %1 = call i8 @llvm.scmp(i32 %x, i32 %y)
  ret i8 %1
}

; Negative test: ranges are the same, but we can't be sure the values are equal
define i8 @ucmp_6(i32 %x, i32 %y) {
  ; Both X and Y are within [0, 10]
; CHECK-LABEL: @ucmp_6(
; CHECK-NEXT:    [[COND1:%.*]] = icmp ule i32 [[X:%.*]], 10
; CHECK-NEXT:    call void @llvm.assume(i1 [[COND1]])
; CHECK-NEXT:    [[COND2:%.*]] = icmp ule i32 [[Y:%.*]], 10
; CHECK-NEXT:    call void @llvm.assume(i1 [[COND2]])
; CHECK-NEXT:    [[TMP1:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
; CHECK-NEXT:    ret i8 [[TMP1]]
;
  %cond1 = icmp ule i32 %x, 10
  call void @llvm.assume(i1 %cond1)
  %cond2 = icmp ule i32 %y, 10
  call void @llvm.assume(i1 %cond2)

  %1 = call i8 @llvm.ucmp(i32 %x, i32 %y)
  ret i8 %1
}