llvm/llvm/test/Transforms/InstCombine/compare-3way.ll

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

declare void @use(i32)

; These 18 exercise all combinations of signed comparison
; for each of the three values produced by your typical
; 3way compare function (-1, 0, 1)

define void @test_low_sgt(i64 %a, i64 %b) {
; CHECK-LABEL: define void @test_low_sgt
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
; CHECK-NEXT:    [[CMP_NOT:%.*]] = icmp slt i64 [[A]], [[B]]
; CHECK-NEXT:    br i1 [[CMP_NOT]], label [[NORMAL:%.*]], label [[UNREACHED:%.*]]
; CHECK:       normal:
; CHECK-NEXT:    ret void
; CHECK:       unreached:
; CHECK-NEXT:    [[RESULT:%.*]] = call i32 @llvm.scmp.i32.i64(i64 [[A]], i64 [[B]])
; CHECK-NEXT:    call void @use(i32 [[RESULT]])
; CHECK-NEXT:    ret void
;
  %eq = icmp eq i64 %a, %b
  %slt = icmp slt i64 %a, %b
  %. = select i1 %slt, i32 -1, i32 1
  %result = select i1 %eq, i32 0, i32 %.
  %cmp = icmp sgt i32 %result, -1
  br i1 %cmp, label %unreached, label %normal
normal:
  ret void
unreached:
  call void @use(i32 %result)
  ret void
}

define void @test_low_slt(i64 %a, i64 %b) {
; CHECK-LABEL: define void @test_low_slt
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
; CHECK-NEXT:    br i1 false, label [[UNREACHED:%.*]], label [[NORMAL:%.*]]
; CHECK:       normal:
; CHECK-NEXT:    ret void
; CHECK:       unreached:
; CHECK-NEXT:    ret void
;
  %eq = icmp eq i64 %a, %b
  %slt = icmp slt i64 %a, %b
  %. = select i1 %slt, i32 -1, i32 1
  %result = select i1 %eq, i32 0, i32 %.
  %cmp = icmp slt i32 %result, -1
  br i1 %cmp, label %unreached, label %normal
normal:
  ret void
unreached:
  call void @use(i32 %result)
  ret void
}

define void @test_low_sge(i64 %a, i64 %b) {
; CHECK-LABEL: define void @test_low_sge
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
; CHECK-NEXT:    br i1 true, label [[UNREACHED:%.*]], label [[NORMAL:%.*]]
; CHECK:       normal:
; CHECK-NEXT:    ret void
; CHECK:       unreached:
; CHECK-NEXT:    [[RESULT:%.*]] = call i32 @llvm.scmp.i32.i64(i64 [[A]], i64 [[B]])
; CHECK-NEXT:    call void @use(i32 [[RESULT]])
; CHECK-NEXT:    ret void
;
  %eq = icmp eq i64 %a, %b
  %slt = icmp slt i64 %a, %b
  %. = select i1 %slt, i32 -1, i32 1
  %result = select i1 %eq, i32 0, i32 %.
  %cmp = icmp sge i32 %result, -1
  br i1 %cmp, label %unreached, label %normal
normal:
  ret void
unreached:
  call void @use(i32 %result)
  ret void
}

define void @test_low_sle(i64 %a, i64 %b) {
; CHECK-LABEL: define void @test_low_sle
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i64 [[A]], [[B]]
; CHECK-NEXT:    br i1 [[TMP1]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]]
; CHECK:       normal:
; CHECK-NEXT:    ret void
; CHECK:       unreached:
; CHECK-NEXT:    call void @use(i32 -1)
; CHECK-NEXT:    ret void
;
  %eq = icmp eq i64 %a, %b
  %slt = icmp slt i64 %a, %b
  %. = select i1 %slt, i32 -1, i32 1
  %result = select i1 %eq, i32 0, i32 %.
  %cmp = icmp sle i32 %result, -1
  br i1 %cmp, label %unreached, label %normal
normal:
  ret void
unreached:
  call void @use(i32 %result)
  ret void
}

define void @test_low_ne(i64 %a, i64 %b) {
; CHECK-LABEL: define void @test_low_ne
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i64 [[A]], [[B]]
; CHECK-NEXT:    br i1 [[TMP1]], label [[NORMAL:%.*]], label [[UNREACHED:%.*]]
; CHECK:       normal:
; CHECK-NEXT:    ret void
; CHECK:       unreached:
; CHECK-NEXT:    [[RESULT:%.*]] = call i32 @llvm.scmp.i32.i64(i64 [[A]], i64 [[B]])
; CHECK-NEXT:    call void @use(i32 [[RESULT]])
; CHECK-NEXT:    ret void
;
  %eq = icmp eq i64 %a, %b
  %slt = icmp slt i64 %a, %b
  %. = select i1 %slt, i32 -1, i32 1
  %result = select i1 %eq, i32 0, i32 %.
  %cmp = icmp ne i32 %result, -1
  br i1 %cmp, label %unreached, label %normal
normal:
  ret void
unreached:
  call void @use(i32 %result)
  ret void
}

define void @test_low_eq(i64 %a, i64 %b) {
; CHECK-LABEL: define void @test_low_eq
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i64 [[A]], [[B]]
; CHECK-NEXT:    br i1 [[TMP1]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]]
; CHECK:       normal:
; CHECK-NEXT:    ret void
; CHECK:       unreached:
; CHECK-NEXT:    call void @use(i32 -1)
; CHECK-NEXT:    ret void
;
  %eq = icmp eq i64 %a, %b
  %slt = icmp slt i64 %a, %b
  %. = select i1 %slt, i32 -1, i32 1
  %result = select i1 %eq, i32 0, i32 %.
  %cmp = icmp eq i32 %result, -1
  br i1 %cmp, label %unreached, label %normal
normal:
  ret void
unreached:
  call void @use(i32 %result)
  ret void
}

define void @test_mid_sgt(i64 %a, i64 %b) {
; CHECK-LABEL: define void @test_mid_sgt
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt i64 [[A]], [[B]]
; CHECK-NEXT:    br i1 [[TMP1]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]]
; CHECK:       normal:
; CHECK-NEXT:    ret void
; CHECK:       unreached:
; CHECK-NEXT:    call void @use(i32 1)
; CHECK-NEXT:    ret void
;
  %eq = icmp eq i64 %a, %b
  %slt = icmp slt i64 %a, %b
  %. = select i1 %slt, i32 -1, i32 1
  %result = select i1 %eq, i32 0, i32 %.
  %cmp = icmp sgt i32 %result, 0
  br i1 %cmp, label %unreached, label %normal
normal:
  ret void
unreached:
  call void @use(i32 %result)
  ret void
}

define void @test_mid_slt(i64 %a, i64 %b) {
; CHECK-LABEL: define void @test_mid_slt
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i64 [[A]], [[B]]
; CHECK-NEXT:    br i1 [[TMP1]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]]
; CHECK:       normal:
; CHECK-NEXT:    ret void
; CHECK:       unreached:
; CHECK-NEXT:    call void @use(i32 -1)
; CHECK-NEXT:    ret void
;
  %eq = icmp eq i64 %a, %b
  %slt = icmp slt i64 %a, %b
  %. = select i1 %slt, i32 -1, i32 1
  %result = select i1 %eq, i32 0, i32 %.
  %cmp = icmp slt i32 %result, 0
  br i1 %cmp, label %unreached, label %normal
normal:
  ret void
unreached:
  call void @use(i32 %result)
  ret void
}

define void @test_mid_sge(i64 %a, i64 %b) {
; CHECK-LABEL: define void @test_mid_sge
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
; CHECK-NEXT:    [[CMP_NOT:%.*]] = icmp slt i64 [[A]], [[B]]
; CHECK-NEXT:    br i1 [[CMP_NOT]], label [[NORMAL:%.*]], label [[UNREACHED:%.*]]
; CHECK:       normal:
; CHECK-NEXT:    ret void
; CHECK:       unreached:
; CHECK-NEXT:    [[RESULT:%.*]] = call i32 @llvm.scmp.i32.i64(i64 [[A]], i64 [[B]])
; CHECK-NEXT:    call void @use(i32 [[RESULT]])
; CHECK-NEXT:    ret void
;
  %eq = icmp eq i64 %a, %b
  %slt = icmp slt i64 %a, %b
  %. = select i1 %slt, i32 -1, i32 1
  %result = select i1 %eq, i32 0, i32 %.
  %cmp = icmp sge i32 %result, 0
  br i1 %cmp, label %unreached, label %normal
normal:
  ret void
unreached:
  call void @use(i32 %result)
  ret void
}

define void @test_mid_sle(i64 %a, i64 %b) {
; CHECK-LABEL: define void @test_mid_sle
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
; CHECK-NEXT:    [[CMP_NOT:%.*]] = icmp sgt i64 [[A]], [[B]]
; CHECK-NEXT:    br i1 [[CMP_NOT]], label [[NORMAL:%.*]], label [[UNREACHED:%.*]]
; CHECK:       normal:
; CHECK-NEXT:    ret void
; CHECK:       unreached:
; CHECK-NEXT:    [[RESULT:%.*]] = call i32 @llvm.scmp.i32.i64(i64 [[A]], i64 [[B]])
; CHECK-NEXT:    call void @use(i32 [[RESULT]])
; CHECK-NEXT:    ret void
;
  %eq = icmp eq i64 %a, %b
  %slt = icmp slt i64 %a, %b
  %. = select i1 %slt, i32 -1, i32 1
  %result = select i1 %eq, i32 0, i32 %.
  %cmp = icmp sle i32 %result, 0
  br i1 %cmp, label %unreached, label %normal
normal:
  ret void
unreached:
  call void @use(i32 %result)
  ret void
}

define void @test_mid_ne(i64 %a, i64 %b) {
; CHECK-LABEL: define void @test_mid_ne
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
; CHECK-NEXT:    [[EQ:%.*]] = icmp eq i64 [[A]], [[B]]
; CHECK-NEXT:    br i1 [[EQ]], label [[NORMAL:%.*]], label [[UNREACHED:%.*]]
; CHECK:       normal:
; CHECK-NEXT:    ret void
; CHECK:       unreached:
; CHECK-NEXT:    [[RESULT:%.*]] = call i32 @llvm.scmp.i32.i64(i64 [[A]], i64 [[B]])
; CHECK-NEXT:    call void @use(i32 [[RESULT]])
; CHECK-NEXT:    ret void
;
  %eq = icmp eq i64 %a, %b
  %slt = icmp slt i64 %a, %b
  %. = select i1 %slt, i32 -1, i32 1
  %result = select i1 %eq, i32 0, i32 %.
  %cmp = icmp ne i32 %result, 0
  br i1 %cmp, label %unreached, label %normal
normal:
  ret void
unreached:
  call void @use(i32 %result)
  ret void
}

define void @test_mid_eq(i64 %a, i64 %b) {
; CHECK-LABEL: define void @test_mid_eq
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
; CHECK-NEXT:    [[EQ:%.*]] = icmp eq i64 [[A]], [[B]]
; CHECK-NEXT:    br i1 [[EQ]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]]
; CHECK:       normal:
; CHECK-NEXT:    ret void
; CHECK:       unreached:
; CHECK-NEXT:    call void @use(i32 0)
; CHECK-NEXT:    ret void
;
  %eq = icmp eq i64 %a, %b
  %slt = icmp slt i64 %a, %b
  %. = select i1 %slt, i32 -1, i32 1
  %result = select i1 %eq, i32 0, i32 %.
  %cmp = icmp eq i32 %result, 0
  br i1 %cmp, label %unreached, label %normal
normal:
  ret void
unreached:
  call void @use(i32 %result)
  ret void
}

define void @test_high_sgt(i64 %a, i64 %b) {
; CHECK-LABEL: define void @test_high_sgt
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
; CHECK-NEXT:    br i1 false, label [[UNREACHED:%.*]], label [[NORMAL:%.*]]
; CHECK:       normal:
; CHECK-NEXT:    ret void
; CHECK:       unreached:
; CHECK-NEXT:    ret void
;
  %eq = icmp eq i64 %a, %b
  %slt = icmp slt i64 %a, %b
  %. = select i1 %slt, i32 -1, i32 1
  %result = select i1 %eq, i32 0, i32 %.
  %cmp = icmp sgt i32 %result, 1
  br i1 %cmp, label %unreached, label %normal
normal:
  ret void
unreached:
  call void @use(i32 %result)
  ret void
}

define void @test_high_slt(i64 %a, i64 %b) {
; CHECK-LABEL: define void @test_high_slt
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
; CHECK-NEXT:    [[CMP_NOT:%.*]] = icmp sgt i64 [[A]], [[B]]
; CHECK-NEXT:    br i1 [[CMP_NOT]], label [[NORMAL:%.*]], label [[UNREACHED:%.*]]
; CHECK:       normal:
; CHECK-NEXT:    ret void
; CHECK:       unreached:
; CHECK-NEXT:    [[RESULT:%.*]] = call i32 @llvm.scmp.i32.i64(i64 [[A]], i64 [[B]])
; CHECK-NEXT:    call void @use(i32 [[RESULT]])
; CHECK-NEXT:    ret void
;
  %eq = icmp eq i64 %a, %b
  %slt = icmp slt i64 %a, %b
  %. = select i1 %slt, i32 -1, i32 1
  %result = select i1 %eq, i32 0, i32 %.
  %cmp = icmp slt i32 %result, 1
  br i1 %cmp, label %unreached, label %normal
normal:
  ret void
unreached:
  call void @use(i32 %result)
  ret void
}

define void @test_high_sge(i64 %a, i64 %b) {
; CHECK-LABEL: define void @test_high_sge
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt i64 [[A]], [[B]]
; CHECK-NEXT:    br i1 [[TMP1]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]]
; CHECK:       normal:
; CHECK-NEXT:    ret void
; CHECK:       unreached:
; CHECK-NEXT:    call void @use(i32 1)
; CHECK-NEXT:    ret void
;
  %eq = icmp eq i64 %a, %b
  %slt = icmp slt i64 %a, %b
  %. = select i1 %slt, i32 -1, i32 1
  %result = select i1 %eq, i32 0, i32 %.
  %cmp = icmp sge i32 %result, 1
  br i1 %cmp, label %unreached, label %normal
normal:
  ret void
unreached:
  call void @use(i32 %result)
  ret void
}

define void @test_high_sle(i64 %a, i64 %b) {
; CHECK-LABEL: define void @test_high_sle
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
; CHECK-NEXT:    br i1 true, label [[UNREACHED:%.*]], label [[NORMAL:%.*]]
; CHECK:       normal:
; CHECK-NEXT:    ret void
; CHECK:       unreached:
; CHECK-NEXT:    [[RESULT:%.*]] = call i32 @llvm.scmp.i32.i64(i64 [[A]], i64 [[B]])
; CHECK-NEXT:    call void @use(i32 [[RESULT]])
; CHECK-NEXT:    ret void
;
  %eq = icmp eq i64 %a, %b
  %slt = icmp slt i64 %a, %b
  %. = select i1 %slt, i32 -1, i32 1
  %result = select i1 %eq, i32 0, i32 %.
  %cmp = icmp sle i32 %result, 1
  br i1 %cmp, label %unreached, label %normal
normal:
  ret void
unreached:
  call void @use(i32 %result)
  ret void
}

define void @test_high_ne(i64 %a, i64 %b) {
; CHECK-LABEL: define void @test_high_ne
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt i64 [[A]], [[B]]
; CHECK-NEXT:    br i1 [[TMP1]], label [[NORMAL:%.*]], label [[UNREACHED:%.*]]
; CHECK:       normal:
; CHECK-NEXT:    ret void
; CHECK:       unreached:
; CHECK-NEXT:    [[RESULT:%.*]] = call i32 @llvm.scmp.i32.i64(i64 [[A]], i64 [[B]])
; CHECK-NEXT:    call void @use(i32 [[RESULT]])
; CHECK-NEXT:    ret void
;
  %eq = icmp eq i64 %a, %b
  %slt = icmp slt i64 %a, %b
  %. = select i1 %slt, i32 -1, i32 1
  %result = select i1 %eq, i32 0, i32 %.
  %cmp = icmp ne i32 %result, 1
  br i1 %cmp, label %unreached, label %normal
normal:
  ret void
unreached:
  call void @use(i32 %result)
  ret void
}

define void @test_high_eq(i64 %a, i64 %b) {
; CHECK-LABEL: define void @test_high_eq
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt i64 [[A]], [[B]]
; CHECK-NEXT:    br i1 [[TMP1]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]]
; CHECK:       normal:
; CHECK-NEXT:    ret void
; CHECK:       unreached:
; CHECK-NEXT:    call void @use(i32 1)
; CHECK-NEXT:    ret void
;
  %eq = icmp eq i64 %a, %b
  %slt = icmp slt i64 %a, %b
  %. = select i1 %slt, i32 -1, i32 1
  %result = select i1 %eq, i32 0, i32 %.
  %cmp = icmp eq i32 %result, 1
  br i1 %cmp, label %unreached, label %normal
normal:
  ret void
unreached:
  call void @use(i32 %result)
  ret void
}

; These five make sure we didn't accidentally hard code one of the
; produced values

define void @non_standard_low(i64 %a, i64 %b) {
; CHECK-LABEL: define void @non_standard_low
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i64 [[A]], [[B]]
; CHECK-NEXT:    br i1 [[TMP1]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]]
; CHECK:       normal:
; CHECK-NEXT:    ret void
; CHECK:       unreached:
; CHECK-NEXT:    call void @use(i32 -3)
; CHECK-NEXT:    ret void
;
  %eq = icmp eq i64 %a, %b
  %slt = icmp slt i64 %a, %b
  %. = select i1 %slt, i32 -3, i32 -1
  %result = select i1 %eq, i32 -2, i32 %.
  %cmp = icmp eq i32 %result, -3
  br i1 %cmp, label %unreached, label %normal
normal:
  ret void
unreached:
  call void @use(i32 %result)
  ret void
}

define void @non_standard_mid(i64 %a, i64 %b) {
; CHECK-LABEL: define void @non_standard_mid
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
; CHECK-NEXT:    [[EQ:%.*]] = icmp eq i64 [[A]], [[B]]
; CHECK-NEXT:    br i1 [[EQ]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]]
; CHECK:       normal:
; CHECK-NEXT:    ret void
; CHECK:       unreached:
; CHECK-NEXT:    call void @use(i32 -2)
; CHECK-NEXT:    ret void
;
  %eq = icmp eq i64 %a, %b
  %slt = icmp slt i64 %a, %b
  %. = select i1 %slt, i32 -3, i32 -1
  %result = select i1 %eq, i32 -2, i32 %.
  %cmp = icmp eq i32 %result, -2
  br i1 %cmp, label %unreached, label %normal
normal:
  ret void
unreached:
  call void @use(i32 %result)
  ret void
}

define void @non_standard_high(i64 %a, i64 %b) {
; CHECK-LABEL: define void @non_standard_high
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = icmp sgt i64 [[A]], [[B]]
; CHECK-NEXT:    br i1 [[TMP1]], label [[UNREACHED:%.*]], label [[NORMAL:%.*]]
; CHECK:       normal:
; CHECK-NEXT:    ret void
; CHECK:       unreached:
; CHECK-NEXT:    call void @use(i32 -1)
; CHECK-NEXT:    ret void
;
  %eq = icmp eq i64 %a, %b
  %slt = icmp slt i64 %a, %b
  %. = select i1 %slt, i32 -3, i32 -1
  %result = select i1 %eq, i32 -2, i32 %.
  %cmp = icmp eq i32 %result, -1
  br i1 %cmp, label %unreached, label %normal
normal:
  ret void
unreached:
  call void @use(i32 %result)
  ret void
}

define void @non_standard_bound1(i64 %a, i64 %b) {
; CHECK-LABEL: define void @non_standard_bound1
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
; CHECK-NEXT:    br i1 false, label [[UNREACHED:%.*]], label [[NORMAL:%.*]]
; CHECK:       normal:
; CHECK-NEXT:    ret void
; CHECK:       unreached:
; CHECK-NEXT:    ret void
;
  %eq = icmp eq i64 %a, %b
  %slt = icmp slt i64 %a, %b
  %. = select i1 %slt, i32 -3, i32 -1
  %result = select i1 %eq, i32 -2, i32 %.
  %cmp = icmp eq i32 %result, -20
  br i1 %cmp, label %unreached, label %normal
normal:
  ret void
unreached:
  call void @use(i32 %result)
  ret void
}

define void @non_standard_bound2(i64 %a, i64 %b) {
; CHECK-LABEL: define void @non_standard_bound2
; CHECK-SAME: (i64 [[A:%.*]], i64 [[B:%.*]]) {
; CHECK-NEXT:    br i1 false, label [[UNREACHED:%.*]], label [[NORMAL:%.*]]
; CHECK:       normal:
; CHECK-NEXT:    ret void
; CHECK:       unreached:
; CHECK-NEXT:    ret void
;
  %eq = icmp eq i64 %a, %b
  %slt = icmp slt i64 %a, %b
  %. = select i1 %slt, i32 -3, i32 -1
  %result = select i1 %eq, i32 -2, i32 %.
  %cmp = icmp eq i32 %result, 0
  br i1 %cmp, label %unreached, label %normal
normal:
  ret void
unreached:
  call void @use(i32 %result)
  ret void
}