| ; 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 [[Z]], [[Y:%.*]] |
| ; 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 ugt i8 [[Z1]], [[Y:%.*]] |
| ; 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 ule i8 [[Z1]], [[Y:%.*]] |
| ; 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 uge i8 [[Z1]], [[Y:%.*]] |
| ; 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 |
| } |