llvm/llvm/test/Transforms/InstCombine/icmp-select.ll

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

declare void @use(i8)
declare void @use.i1(i1)
declare i8 @llvm.umin.i8(i8, i8)

define i1 @icmp_select_const(i8 %x, i8 %y) {
; CHECK-LABEL: @icmp_select_const(
; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i8 [[X:%.*]], 0
; CHECK-NEXT:    [[CMP21:%.*]] = icmp eq i8 [[Y:%.*]], 0
; CHECK-NEXT:    [[CMP2:%.*]] = select i1 [[CMP1]], i1 true, i1 [[CMP21]]
; CHECK-NEXT:    ret i1 [[CMP2]]
;
  %cmp1 = icmp eq i8 %x, 0
  %sel = select i1 %cmp1, i8 0, i8 %y
  %cmp2 = icmp eq i8 %sel, 0
  ret i1 %cmp2
}

define i1 @icmp_select_var(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: @icmp_select_var(
; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i8 [[X:%.*]], 0
; CHECK-NEXT:    [[CMP21:%.*]] = icmp eq i8 [[Y:%.*]], [[Z:%.*]]
; CHECK-NEXT:    [[CMP2:%.*]] = select i1 [[CMP1]], i1 true, i1 [[CMP21]]
; CHECK-NEXT:    ret i1 [[CMP2]]
;
  %cmp1 = icmp eq i8 %x, 0
  %sel = select i1 %cmp1, i8 %z, i8 %y
  %cmp2 = icmp eq i8 %sel, %z
  ret i1 %cmp2
}

define i1 @icmp_select_var_commuted(i8 %x, i8 %y, i8 %_z) {
; CHECK-LABEL: @icmp_select_var_commuted(
; CHECK-NEXT:    [[Z:%.*]] = udiv i8 42, [[_Z:%.*]]
; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i8 [[X:%.*]], 0
; CHECK-NEXT:    [[CMP21:%.*]] = icmp eq i8 [[Y:%.*]], [[Z]]
; CHECK-NEXT:    [[CMP2:%.*]] = select i1 [[CMP1]], i1 true, i1 [[CMP21]]
; CHECK-NEXT:    ret i1 [[CMP2]]
;
  %z = udiv i8 42, %_z ; thwart complexity-based canonicalization
  %cmp1 = icmp eq i8 %x, 0
  %sel = select i1 %cmp1, i8 %z, i8 %y
  %cmp2 = icmp eq i8 %z, %sel
  ret i1 %cmp2
}

define i1 @icmp_select_var_select(i8 %x, i8 %y, i1 %c) {
; CHECK-LABEL: @icmp_select_var_select(
; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i8 [[X:%.*]], 0
; CHECK-NEXT:    [[CMP212:%.*]] = icmp eq i8 [[X]], [[Y:%.*]]
; CHECK-NEXT:    [[NOT_C:%.*]] = xor i1 [[C:%.*]], true
; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[CMP1]], i1 true, i1 [[NOT_C]]
; CHECK-NEXT:    [[CMP2:%.*]] = select i1 [[TMP1]], i1 true, i1 [[CMP212]]
; CHECK-NEXT:    ret i1 [[CMP2]]
;
  %z = select i1 %c, i8 %x, i8 %y
  %cmp1 = icmp eq i8 %x, 0
  %sel = select i1 %cmp1, i8 %z, i8 %y
  %cmp2 = icmp eq i8 %z, %sel
  ret i1 %cmp2
}

define i1 @icmp_select_var_both_fold(i8 %x, i8 %y, i8 %_z) {
; CHECK-LABEL: @icmp_select_var_both_fold(
; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i8 [[X:%.*]], 0
; CHECK-NEXT:    ret i1 [[CMP1]]
;
  %z = or i8 %_z, 1
  %cmp1 = icmp eq i8 %x, 0
  %sel = select i1 %cmp1, i8 %z, i8 2
  %cmp2 = icmp eq i8 %sel, %z
  ret i1 %cmp2
}

define i1 @icmp_select_var_extra_use(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: @icmp_select_var_extra_use(
; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i8 [[X:%.*]], 0
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], i8 [[Z:%.*]], i8 [[Y:%.*]]
; CHECK-NEXT:    call void @use(i8 [[SEL]])
; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i8 [[SEL]], [[Z]]
; CHECK-NEXT:    ret i1 [[CMP2]]
;
  %cmp1 = icmp eq i8 %x, 0
  %sel = select i1 %cmp1, i8 %z, i8 %y
  call void @use(i8 %sel)
  %cmp2 = icmp eq i8 %sel, %z
  ret i1 %cmp2
}

define i1 @icmp_select_var_both_fold_extra_use(i8 %x, i8 %y, i8 %_z) {
; CHECK-LABEL: @icmp_select_var_both_fold_extra_use(
; CHECK-NEXT:    [[Z:%.*]] = or i8 [[_Z:%.*]], 1
; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i8 [[X:%.*]], 0
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], i8 [[Z]], i8 2
; CHECK-NEXT:    call void @use(i8 [[SEL]])
; CHECK-NEXT:    ret i1 [[CMP1]]
;
  %z = or i8 %_z, 1
  %cmp1 = icmp eq i8 %x, 0
  %sel = select i1 %cmp1, i8 %z, i8 2
  call void @use(i8 %sel)
  %cmp2 = icmp eq i8 %sel, %z
  ret i1 %cmp2
}

define i1 @icmp_select_var_pred_ne(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: @icmp_select_var_pred_ne(
; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne i8 [[X:%.*]], 0
; CHECK-NEXT:    [[CMP21:%.*]] = icmp ne i8 [[Y:%.*]], [[Z:%.*]]
; CHECK-NEXT:    [[CMP2:%.*]] = select i1 [[CMP1]], i1 [[CMP21]], i1 false
; CHECK-NEXT:    ret i1 [[CMP2]]
;
  %cmp1 = icmp eq i8 %x, 0
  %sel = select i1 %cmp1, i8 %z, i8 %y
  %cmp2 = icmp ne i8 %sel, %z
  ret i1 %cmp2
}

define i1 @icmp_select_var_pred_ult(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: @icmp_select_var_pred_ult(
; CHECK-NEXT:    [[Z1:%.*]] = add nuw i8 [[Z:%.*]], 2
; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i8 [[X:%.*]], 0
; CHECK-NEXT:    [[CMP21:%.*]] = icmp ult i8 [[Y:%.*]], [[Z1]]
; CHECK-NEXT:    [[CMP2:%.*]] = select i1 [[CMP1]], i1 true, i1 [[CMP21]]
; CHECK-NEXT:    ret i1 [[CMP2]]
;
  %z1 = add nuw i8 %z, 2
  %cmp1 = icmp eq i8 %x, 0
  %sel = select i1 %cmp1, i8 %z, i8 %y
  %cmp2 = icmp ult i8 %sel, %z1
  ret i1 %cmp2
}

define i1 @icmp_select_var_pred_uge(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: @icmp_select_var_pred_uge(
; CHECK-NEXT:    [[Z1:%.*]] = add nuw i8 [[Z:%.*]], 2
; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne i8 [[X:%.*]], 0
; CHECK-NEXT:    [[CMP21:%.*]] = icmp uge i8 [[Y:%.*]], [[Z1]]
; CHECK-NEXT:    [[CMP2:%.*]] = select i1 [[CMP1]], i1 [[CMP21]], i1 false
; CHECK-NEXT:    ret i1 [[CMP2]]
;
  %z1 = add nuw i8 %z, 2
  %cmp1 = icmp eq i8 %x, 0
  %sel = select i1 %cmp1, i8 %z, i8 %y
  %cmp2 = icmp uge i8 %sel, %z1
  ret i1 %cmp2
}

define i1 @icmp_select_var_pred_uge_commuted(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: @icmp_select_var_pred_uge_commuted(
; CHECK-NEXT:    [[Z1:%.*]] = add nuw i8 [[Z:%.*]], 2
; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i8 [[X:%.*]], 0
; CHECK-NEXT:    [[CMP21:%.*]] = icmp ule i8 [[Y:%.*]], [[Z1]]
; CHECK-NEXT:    [[CMP2:%.*]] = select i1 [[CMP1]], i1 true, i1 [[CMP21]]
; CHECK-NEXT:    ret i1 [[CMP2]]
;
  %z1 = add nuw i8 %z, 2
  %cmp1 = icmp eq i8 %x, 0
  %sel = select i1 %cmp1, i8 %z, i8 %y
  %cmp2 = icmp uge i8 %z1, %sel
  ret i1 %cmp2
}

define i1 @icmp_select_implied_cond(i8 %x, i8 %y) {
; CHECK-LABEL: @icmp_select_implied_cond(
; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i8 [[X:%.*]], 0
; CHECK-NEXT:    [[CMP21:%.*]] = icmp eq i8 [[Y:%.*]], [[X]]
; CHECK-NEXT:    [[CMP2:%.*]] = select i1 [[CMP1]], i1 true, i1 [[CMP21]]
; CHECK-NEXT:    ret i1 [[CMP2]]
;
  %cmp1 = icmp eq i8 %x, 0
  %sel = select i1 %cmp1, i8 0, i8 %y
  %cmp2 = icmp eq i8 %sel, %x
  ret i1 %cmp2
}

define i1 @icmp_select_implied_cond_ne(i8 %x, i8 %y) {
; CHECK-LABEL: @icmp_select_implied_cond_ne(
; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne i8 [[X:%.*]], 0
; CHECK-NEXT:    [[CMP21:%.*]] = icmp ne i8 [[Y:%.*]], [[X]]
; CHECK-NEXT:    [[CMP2:%.*]] = select i1 [[CMP1]], i1 [[CMP21]], i1 false
; CHECK-NEXT:    ret i1 [[CMP2]]
;
  %cmp1 = icmp eq i8 %x, 0
  %sel = select i1 %cmp1, i8 0, i8 %y
  %cmp2 = icmp ne i8 %sel, %x
  ret i1 %cmp2
}

define i1 @icmp_select_implied_cond_swapped_select(i8 %x, i8 %y) {
; CHECK-LABEL: @icmp_select_implied_cond_swapped_select(
; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i8 [[X:%.*]], 0
; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i8 [[Y:%.*]], 0
; CHECK-NEXT:    [[CMP2:%.*]] = select i1 [[CMP1]], i1 [[TMP1]], i1 false
; CHECK-NEXT:    ret i1 [[CMP2]]
;
  %cmp1 = icmp eq i8 %x, 0
  %sel = select i1 %cmp1, i8 %y, i8 0
  %cmp2 = icmp eq i8 %sel, %x
  ret i1 %cmp2
}

define i1 @icmp_select_implied_cond_swapped_select_with_inv_cond(i8 %x, i8 %y) {
; CHECK-LABEL: @icmp_select_implied_cond_swapped_select_with_inv_cond(
; CHECK-NEXT:    [[CMP1:%.*]] = icmp ne i8 [[X:%.*]], 0
; CHECK-NEXT:    call void @use.i1(i1 [[CMP1]])
; CHECK-NEXT:    [[CMP21:%.*]] = icmp eq i8 [[Y:%.*]], [[X]]
; CHECK-NEXT:    [[NOT_CMP1:%.*]] = xor i1 [[CMP1]], true
; CHECK-NEXT:    [[CMP2:%.*]] = select i1 [[NOT_CMP1]], i1 true, i1 [[CMP21]]
; CHECK-NEXT:    ret i1 [[CMP2]]
;
  %cmp1 = icmp ne i8 %x, 0
  call void @use.i1(i1 %cmp1)
  %sel = select i1 %cmp1, i8 %y, i8 0
  %cmp2 = icmp eq i8 %sel, %x
  ret i1 %cmp2
}

define i1 @icmp_select_implied_cond_relational(i8 %x, i8 %y) {
; CHECK-LABEL: @icmp_select_implied_cond_relational(
; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt i8 [[X:%.*]], 10
; CHECK-NEXT:    [[CMP21:%.*]] = icmp ult i8 [[Y:%.*]], [[X]]
; CHECK-NEXT:    [[CMP2:%.*]] = select i1 [[CMP1]], i1 true, i1 [[CMP21]]
; CHECK-NEXT:    ret i1 [[CMP2]]
;
  %cmp1 = icmp ugt i8 %x, 10
  %sel = select i1 %cmp1, i8 10, i8 %y
  %cmp2 = icmp ult i8 %sel, %x
  ret i1 %cmp2
}

define i1 @icmp_select_implied_cond_relational_off_by_one(i8 %x, i8 %y) {
; CHECK-LABEL: @icmp_select_implied_cond_relational_off_by_one(
; CHECK-NEXT:    [[CMP1:%.*]] = icmp ugt i8 [[X:%.*]], 10
; CHECK-NEXT:    call void @use.i1(i1 [[CMP1]])
; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], i8 11, i8 [[Y:%.*]]
; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i8 [[SEL]], [[X]]
; CHECK-NEXT:    ret i1 [[CMP2]]
;
  %cmp1 = icmp ugt i8 %x, 10
  call void @use.i1(i1 %cmp1)
  %sel = select i1 %cmp1, i8 11, i8 %y
  %cmp2 = icmp ult i8 %sel, %x
  ret i1 %cmp2
}

define i1 @umin_seq_comparison(i8 %x, i8 %y) {
; CHECK-LABEL: @umin_seq_comparison(
; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i8 [[X:%.*]], 0
; CHECK-NEXT:    [[CMP21:%.*]] = icmp ule i8 [[X]], [[Y:%.*]]
; CHECK-NEXT:    [[CMP2:%.*]] = select i1 [[CMP1]], i1 true, i1 [[CMP21]]
; CHECK-NEXT:    ret i1 [[CMP2]]
;
  %min = call i8 @llvm.umin.i8(i8 %x, i8 %y)
  %cmp1 = icmp eq i8 %x, 0
  %sel = select i1 %cmp1, i8 0, i8 %min
  %cmp2 = icmp eq i8 %sel, %x
  ret i1 %cmp2
}

; ((A ? TC : FC) & (B ? TC : FC)) == 0 --> xor A, B

define i1 @select_constants_and_icmp_eq0(i1 %x, i1 %y) {
; CHECK-LABEL: @select_constants_and_icmp_eq0(
; CHECK-NEXT:    [[CMP:%.*]] = xor i1 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT:    ret i1 [[CMP]]
;
  %s1 = select i1 %x, i8 2, i8 1
  %s2 = select i1 %y, i8 2, i8 1
  %and = and i8 %s1, %s2
  %cmp = icmp eq i8 %and, 0
  ret i1 %cmp
}

; extra uses on all intermediates are ok

define i1 @select_constants_and_icmp_eq0_uses(i1 %x, i1 %y) {
; CHECK-LABEL: @select_constants_and_icmp_eq0_uses(
; CHECK-NEXT:    [[S1:%.*]] = select i1 [[X:%.*]], i8 2, i8 1
; CHECK-NEXT:    call void @use(i8 [[S1]])
; CHECK-NEXT:    [[S2:%.*]] = select i1 [[Y:%.*]], i8 2, i8 1
; CHECK-NEXT:    call void @use(i8 [[S2]])
; CHECK-NEXT:    [[AND:%.*]] = and i8 [[S1]], [[S2]]
; CHECK-NEXT:    call void @use(i8 [[AND]])
; CHECK-NEXT:    [[CMP:%.*]] = xor i1 [[X]], [[Y]]
; CHECK-NEXT:    ret i1 [[CMP]]
;
  %s1 = select i1 %x, i8 2, i8 1
  call void @use(i8 %s1)
  %s2 = select i1 %y, i8 2, i8 1
  call void @use(i8 %s2)
  %and = and i8 %s1, %s2
  call void @use(i8 %and)
  %cmp = icmp eq i8 %and, 0
  ret i1 %cmp
}

; vector splat constants are ok

define <2 x i1> @select_constants_and_icmp_eq0_vec_splat(<2 x i1> %x, <2 x i1> %y) {
; CHECK-LABEL: @select_constants_and_icmp_eq0_vec_splat(
; CHECK-NEXT:    [[CMP:%.*]] = xor <2 x i1> [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT:    ret <2 x i1> [[CMP]]
;
  %s1 = select <2 x i1> %x, <2 x i9> <i9 3, i9 3>, <2 x i9> <i9 48, i9 48>
  %s2 = select <2 x i1> %y, <2 x i9> <i9 3, i9 3>, <2 x i9> <i9 48, i9 48>
  %and = and <2 x i9> %s1, %s2
  %cmp = icmp eq <2 x i9> %and, zeroinitializer
  ret <2 x i1> %cmp
}

; common bit set - simplified via known bits

define i1 @select_constants_and_icmp_eq0_common_bit(i1 %x, i1 %y) {
; CHECK-LABEL: @select_constants_and_icmp_eq0_common_bit(
; CHECK-NEXT:    ret i1 false
;
  %s1 = select i1 %x, i8 2, i8 3
  %s2 = select i1 %y, i8 2, i8 3
  %and = and i8 %s1, %s2
  %cmp = icmp eq i8 %and, 0
  ret i1 %cmp
}

; negative test - need matching constants

define i1 @select_constants_and_icmp_eq0_no_common_op1(i1 %x, i1 %y) {
; CHECK-LABEL: @select_constants_and_icmp_eq0_no_common_op1(
; CHECK-NEXT:    [[S1:%.*]] = select i1 [[X:%.*]], i8 16, i8 3
; CHECK-NEXT:    [[S2:%.*]] = select i1 [[Y:%.*]], i8 24, i8 3
; CHECK-NEXT:    [[AND:%.*]] = and i8 [[S1]], [[S2]]
; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[AND]], 0
; CHECK-NEXT:    ret i1 [[CMP]]
;
  %s1 = select i1 %x, i8 16, i8 3
  %s2 = select i1 %y, i8 24, i8 3
  %and = and i8 %s1, %s2
  %cmp = icmp eq i8 %and, 0
  ret i1 %cmp
}

; negative test - need matching constants

define i1 @select_constants_and_icmp_eq0_no_common_op2(i1 %x, i1 %y) {
; CHECK-LABEL: @select_constants_and_icmp_eq0_no_common_op2(
; CHECK-NEXT:    [[S1:%.*]] = select i1 [[X:%.*]], i8 16, i8 3
; CHECK-NEXT:    [[S2:%.*]] = select i1 [[Y:%.*]], i8 16, i8 7
; CHECK-NEXT:    [[AND:%.*]] = and i8 [[S1]], [[S2]]
; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[AND]], 0
; CHECK-NEXT:    ret i1 [[CMP]]
;
  %s1 = select i1 %x, i8 16, i8 3
  %s2 = select i1 %y, i8 16, i8 7
  %and = and i8 %s1, %s2
  %cmp = icmp eq i8 %and, 0
  ret i1 %cmp
}

; reduces via FoldOpInstSelect, but this could be a simple 'or'

define i1 @select_constants_and_icmp_eq0_zero_tval(i1 %x, i1 %y) {
; CHECK-LABEL: @select_constants_and_icmp_eq0_zero_tval(
; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[X:%.*]], i1 true, i1 [[Y:%.*]]
; CHECK-NEXT:    ret i1 [[TMP1]]
;
  %s1 = select i1 %x, i8 0, i8 12
  %s2 = select i1 %y, i8 0, i8 12
  %and = and i8 %s1, %s2
  %cmp = icmp eq i8 %and, 0
  ret i1 %cmp
}

; reduces via FoldOpInstSelect, but this could be a simple 'not-of-and'

define i1 @select_constants_and_icmp_eq0_zero_fval(i1 %x, i1 %y) {
; CHECK-LABEL: @select_constants_and_icmp_eq0_zero_fval(
; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[X:%.*]], i1 [[Y:%.*]], i1 false
; CHECK-NEXT:    [[NOT_:%.*]] = xor i1 [[TMP1]], true
; CHECK-NEXT:    ret i1 [[NOT_]]
;
  %s1 = select i1 %x, i8 12, i8 0
  %s2 = select i1 %y, i8 12, i8 0
  %and = and i8 %s1, %s2
  %cmp = icmp eq i8 %and, 0
  ret i1 %cmp
}

; TODO: x & y

define i1 @select_constants_and_icmp_eq_tval(i1 %x, i1 %y) {
; CHECK-LABEL: @select_constants_and_icmp_eq_tval(
; CHECK-NEXT:    [[S1:%.*]] = select i1 [[X:%.*]], i8 6, i8 1
; CHECK-NEXT:    [[S2:%.*]] = select i1 [[Y:%.*]], i8 6, i8 1
; CHECK-NEXT:    [[AND:%.*]] = and i8 [[S1]], [[S2]]
; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[AND]], 6
; CHECK-NEXT:    ret i1 [[CMP]]
;
  %s1 = select i1 %x, i8 6, i8 1
  %s2 = select i1 %y, i8 6, i8 1
  %and = and i8 %s1, %s2
  %cmp = icmp eq i8 %and, 6
  ret i1 %cmp
}

; TODO: ~(x | y)

define i1 @select_constants_and_icmp_eq_fval(i1 %x, i1 %y) {
; CHECK-LABEL: @select_constants_and_icmp_eq_fval(
; CHECK-NEXT:    [[S1:%.*]] = select i1 [[X:%.*]], i8 12, i8 3
; CHECK-NEXT:    [[S2:%.*]] = select i1 [[Y:%.*]], i8 12, i8 3
; CHECK-NEXT:    [[AND:%.*]] = and i8 [[S1]], [[S2]]
; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[AND]], 3
; CHECK-NEXT:    ret i1 [[CMP]]
;
  %s1 = select i1 %x, i8 12, i8 3
  %s2 = select i1 %y, i8 12, i8 3
  %and = and i8 %s1, %s2
  %cmp = icmp eq i8 %and, 3
  ret i1 %cmp
}

; ((A ? TC : FC) & (B ? TC : FC)) != 0 --> not(xor A, B)

define i1 @select_constants_and_icmp_ne0(i1 %x, i1 %y) {
; CHECK-LABEL: @select_constants_and_icmp_ne0(
; CHECK-NEXT:    [[TMP1:%.*]] = xor i1 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT:    [[CMP:%.*]] = xor i1 [[TMP1]], true
; CHECK-NEXT:    ret i1 [[CMP]]
;
  %s1 = select i1 %x, i8 2, i8 1
  %s2 = select i1 %y, i8 2, i8 1
  %and = and i8 %s1, %s2
  %cmp = icmp ne i8 %and, 0
  ret i1 %cmp
}

; extra uses on select intermediates are ok

define i1 @select_constants_and_icmp_ne0_uses(i1 %x, i1 %y) {
; CHECK-LABEL: @select_constants_and_icmp_ne0_uses(
; CHECK-NEXT:    [[S1:%.*]] = select i1 [[X:%.*]], i8 2, i8 1
; CHECK-NEXT:    call void @use(i8 [[S1]])
; CHECK-NEXT:    [[S2:%.*]] = select i1 [[Y:%.*]], i8 2, i8 1
; CHECK-NEXT:    call void @use(i8 [[S2]])
; CHECK-NEXT:    [[TMP1:%.*]] = xor i1 [[X]], [[Y]]
; CHECK-NEXT:    [[CMP:%.*]] = xor i1 [[TMP1]], true
; CHECK-NEXT:    ret i1 [[CMP]]
;
  %s1 = select i1 %x, i8 2, i8 1
  call void @use(i8 %s1)
  %s2 = select i1 %y, i8 2, i8 1
  call void @use(i8 %s2)
  %and = and i8 %s1, %s2
  %cmp = icmp ne i8 %and, 0
  ret i1 %cmp
}

; negative test - don't create extra instructions

define i1 @select_constants_and_icmp_ne0_all_uses(i1 %x, i1 %y) {
; CHECK-LABEL: @select_constants_and_icmp_ne0_all_uses(
; CHECK-NEXT:    [[S1:%.*]] = select i1 [[X:%.*]], i8 2, i8 1
; CHECK-NEXT:    call void @use(i8 [[S1]])
; CHECK-NEXT:    [[S2:%.*]] = select i1 [[Y:%.*]], i8 2, i8 1
; CHECK-NEXT:    call void @use(i8 [[S2]])
; CHECK-NEXT:    [[AND:%.*]] = and i8 [[S1]], [[S2]]
; CHECK-NEXT:    call void @use(i8 [[AND]])
; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 [[AND]], 0
; CHECK-NEXT:    ret i1 [[CMP]]
;
  %s1 = select i1 %x, i8 2, i8 1
  call void @use(i8 %s1)
  %s2 = select i1 %y, i8 2, i8 1
  call void @use(i8 %s2)
  %and = and i8 %s1, %s2
  call void @use(i8 %and)
  %cmp = icmp ne i8 %and, 0
  ret i1 %cmp
}

; vector splat constants are ok

define <2 x i1> @select_constants_and_icmp_ne0_vec_splat(<2 x i1> %x, <2 x i1> %y) {
; CHECK-LABEL: @select_constants_and_icmp_ne0_vec_splat(
; CHECK-NEXT:    [[TMP1:%.*]] = xor <2 x i1> [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT:    [[CMP:%.*]] = xor <2 x i1> [[TMP1]], <i1 true, i1 true>
; CHECK-NEXT:    ret <2 x i1> [[CMP]]
;
  %s1 = select <2 x i1> %x, <2 x i9> <i9 3, i9 3>, <2 x i9> <i9 48, i9 48>
  %s2 = select <2 x i1> %y, <2 x i9> <i9 3, i9 3>, <2 x i9> <i9 48, i9 48>
  %and = and <2 x i9> %s1, %s2
  %cmp = icmp ne <2 x i9> %and, zeroinitializer
  ret <2 x i1> %cmp
}

; common bit set - simplified via known bits

define i1 @select_constants_and_icmp_ne0_common_bit(i1 %x, i1 %y) {
; CHECK-LABEL: @select_constants_and_icmp_ne0_common_bit(
; CHECK-NEXT:    ret i1 true
;
  %s1 = select i1 %x, i8 2, i8 3
  %s2 = select i1 %y, i8 2, i8 3
  %and = and i8 %s1, %s2
  %cmp = icmp ne i8 %and, 0
  ret i1 %cmp
}

; negative test - need matching constants

define i1 @select_constants_and_icmp_ne0_no_common_op1(i1 %x, i1 %y) {
; CHECK-LABEL: @select_constants_and_icmp_ne0_no_common_op1(
; CHECK-NEXT:    [[S1:%.*]] = select i1 [[X:%.*]], i8 16, i8 3
; CHECK-NEXT:    [[S2:%.*]] = select i1 [[Y:%.*]], i8 24, i8 3
; CHECK-NEXT:    [[AND:%.*]] = and i8 [[S1]], [[S2]]
; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 [[AND]], 0
; CHECK-NEXT:    ret i1 [[CMP]]
;
  %s1 = select i1 %x, i8 16, i8 3
  %s2 = select i1 %y, i8 24, i8 3
  %and = and i8 %s1, %s2
  %cmp = icmp ne i8 %and, 0
  ret i1 %cmp
}

; negative test - need matching constants

define i1 @select_constants_and_icmp_ne0_no_common_op2(i1 %x, i1 %y) {
; CHECK-LABEL: @select_constants_and_icmp_ne0_no_common_op2(
; CHECK-NEXT:    [[S1:%.*]] = select i1 [[X:%.*]], i8 16, i8 3
; CHECK-NEXT:    [[S2:%.*]] = select i1 [[Y:%.*]], i8 16, i8 7
; CHECK-NEXT:    [[AND:%.*]] = and i8 [[S1]], [[S2]]
; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 [[AND]], 0
; CHECK-NEXT:    ret i1 [[CMP]]
;
  %s1 = select i1 %x, i8 16, i8 3
  %s2 = select i1 %y, i8 16, i8 7
  %and = and i8 %s1, %s2
  %cmp = icmp ne i8 %and, 0
  ret i1 %cmp
}

; reduces via FoldOpInstSelect, but this could be a simple 'nor'

define i1 @select_constants_and_icmp_ne0_zero_tval(i1 %x, i1 %y) {
; CHECK-LABEL: @select_constants_and_icmp_ne0_zero_tval(
; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[X:%.*]], i1 true, i1 [[Y:%.*]]
; CHECK-NEXT:    [[NOT_:%.*]] = xor i1 [[TMP1]], true
; CHECK-NEXT:    ret i1 [[NOT_]]
;
  %s1 = select i1 %x, i8 0, i8 12
  %s2 = select i1 %y, i8 0, i8 12
  %and = and i8 %s1, %s2
  %cmp = icmp ne i8 %and, 0
  ret i1 %cmp
}

; reduces via FoldOpInstSelect, but this could be a simple 'and'

define i1 @select_constants_and_icmp_ne0_zero_fval(i1 %x, i1 %y) {
; CHECK-LABEL: @select_constants_and_icmp_ne0_zero_fval(
; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[X:%.*]], i1 [[Y:%.*]], i1 false
; CHECK-NEXT:    ret i1 [[TMP1]]
;
  %s1 = select i1 %x, i8 12, i8 0
  %s2 = select i1 %y, i8 12, i8 0
  %and = and i8 %s1, %s2
  %cmp = icmp ne i8 %and, 0
  ret i1 %cmp
}

; TODO: ~(x & y)

define i1 @select_constants_and_icmp_ne_tval(i1 %x, i1 %y) {
; CHECK-LABEL: @select_constants_and_icmp_ne_tval(
; CHECK-NEXT:    [[S1:%.*]] = select i1 [[X:%.*]], i8 6, i8 1
; CHECK-NEXT:    [[S2:%.*]] = select i1 [[Y:%.*]], i8 6, i8 1
; CHECK-NEXT:    [[AND:%.*]] = and i8 [[S1]], [[S2]]
; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 [[AND]], 6
; CHECK-NEXT:    ret i1 [[CMP]]
;
  %s1 = select i1 %x, i8 6, i8 1
  %s2 = select i1 %y, i8 6, i8 1
  %and = and i8 %s1, %s2
  %cmp = icmp ne i8 %and, 6
  ret i1 %cmp
}

; TODO: (x | y)

define i1 @select_constants_and_icmp_ne_fval(i1 %x, i1 %y) {
; CHECK-LABEL: @select_constants_and_icmp_ne_fval(
; CHECK-NEXT:    [[S1:%.*]] = select i1 [[X:%.*]], i8 12, i8 3
; CHECK-NEXT:    [[S2:%.*]] = select i1 [[Y:%.*]], i8 12, i8 3
; CHECK-NEXT:    [[AND:%.*]] = and i8 [[S1]], [[S2]]
; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 [[AND]], 3
; CHECK-NEXT:    ret i1 [[CMP]]
;
  %s1 = select i1 %x, i8 12, i8 3
  %s2 = select i1 %y, i8 12, i8 3
  %and = and i8 %s1, %s2
  %cmp = icmp ne i8 %and, 3
  ret i1 %cmp
}

define i1 @icmp_eq_select(i1 %cond, i32 %a, i32 %b) {
; CHECK-LABEL: @icmp_eq_select(
; CHECK-NEXT:    [[RES:%.*]] = icmp eq i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT:    ret i1 [[RES]]
;
  %lhs = select i1 %cond, i32 %a, i32 %b
  %rhs = select i1 %cond, i32 %b, i32 %a
  %res = icmp eq i32 %lhs, %rhs
  ret i1 %res
}

define i1 @icmp_slt_select(i1 %cond, i32 %a, i32 %b) {
; CHECK-LABEL: @icmp_slt_select(
; CHECK-NEXT:    [[LHS:%.*]] = select i1 [[COND:%.*]], i32 [[A:%.*]], i32 [[B:%.*]]
; CHECK-NEXT:    [[RHS:%.*]] = select i1 [[COND]], i32 [[B]], i32 [[A]]
; CHECK-NEXT:    [[RES:%.*]] = icmp slt i32 [[LHS]], [[RHS]]
; CHECK-NEXT:    ret i1 [[RES]]
;
  %lhs = select i1 %cond, i32 %a, i32 %b
  %rhs = select i1 %cond, i32 %b, i32 %a
  %res = icmp slt i32 %lhs, %rhs
  ret i1 %res
}