; 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: [[Y:%.*]] = freeze i8 [[Y1:%.*]] ; CHECK-NEXT: [[CMP21:%.*]] = icmp ule i8 [[X:%.*]], [[Y]] ; CHECK-NEXT: ret i1 [[CMP21]] ; %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> , <2 x i9> %s2 = select <2 x i1> %y, <2 x i9> , <2 x i9> %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: [[CMP:%.*]] = xor i1 [[X:%.*]], [[Y:%.*]] ; 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: [[CMP:%.*]] = xor i1 [[X:%.*]], [[Y:%.*]] ; 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 } define i1 @select_constants_and_icmp_eq_tval(i1 %x, i1 %y) { ; CHECK-LABEL: @select_constants_and_icmp_eq_tval( ; CHECK-NEXT: [[CMP:%.*]] = and i1 [[X:%.*]], [[Y:%.*]] ; 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 } define i1 @select_constants_and_icmp_eq_fval(i1 %x, i1 %y) { ; CHECK-LABEL: @select_constants_and_icmp_eq_fval( ; CHECK-NEXT: [[TMP1:%.*]] = or i1 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: [[CMP:%.*]] = xor i1 [[TMP1]], true ; 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]], splat (i1 true) ; CHECK-NEXT: ret <2 x i1> [[CMP]] ; %s1 = select <2 x i1> %x, <2 x i9> , <2 x i9> %s2 = select <2 x i1> %y, <2 x i9> , <2 x i9> %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: [[TMP1:%.*]] = xor i1 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: [[CMP:%.*]] = xor i1 [[TMP1]], true ; 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: [[TMP1:%.*]] = xor i1 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: [[CMP:%.*]] = xor i1 [[TMP1]], true ; 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 } define i1 @select_constants_and_icmp_ne_tval(i1 %x, i1 %y) { ; CHECK-LABEL: @select_constants_and_icmp_ne_tval( ; CHECK-NEXT: [[TMP1:%.*]] = and i1 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: [[CMP:%.*]] = xor i1 [[TMP1]], true ; 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 } define i1 @select_constants_and_icmp_ne_fval(i1 %x, i1 %y) { ; CHECK-LABEL: @select_constants_and_icmp_ne_fval( ; CHECK-NEXT: [[CMP:%.*]] = or i1 [[X:%.*]], [[Y:%.*]] ; 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 } define i1 @discr_eq(i8 %a, i8 %b) { ; CHECK-LABEL: @discr_eq( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i8 [[A:%.*]], 1 ; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i8 [[B:%.*]], 1 ; CHECK-NEXT: [[TMP0:%.*]] = select i1 [[CMP1]], i8 [[A]], i8 3 ; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[CMP2]], i8 [[B]], i8 3 ; CHECK-NEXT: [[RES:%.*]] = icmp eq i8 [[TMP0]], [[TMP1]] ; CHECK-NEXT: ret i1 [[RES]] ; entry: %add1 = add i8 %a, -2 %cmp1 = icmp ugt i8 %a, 1 %sel1 = select i1 %cmp1, i8 %add1, i8 1 %add2 = add i8 %b, -2 %cmp2 = icmp ugt i8 %b, 1 %sel2 = select i1 %cmp2, i8 %add2, i8 1 %res = icmp eq i8 %sel1, %sel2 ret i1 %res } define i1 @discr_ne(i8 %a, i8 %b) { ; CHECK-LABEL: @discr_ne( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i8 [[A:%.*]], 1 ; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i8 [[B:%.*]], 1 ; CHECK-NEXT: [[TMP0:%.*]] = select i1 [[CMP1]], i8 [[A]], i8 3 ; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[CMP2]], i8 [[B]], i8 3 ; CHECK-NEXT: [[RES:%.*]] = icmp ne i8 [[TMP0]], [[TMP1]] ; CHECK-NEXT: ret i1 [[RES]] ; entry: %add1 = add i8 %a, -2 %cmp1 = icmp ugt i8 %a, 1 %sel1 = select i1 %cmp1, i8 %add1, i8 1 %add2 = add i8 %b, -2 %cmp2 = icmp ugt i8 %b, 1 %sel2 = select i1 %cmp2, i8 %add2, i8 1 %res = icmp ne i8 %sel1, %sel2 ret i1 %res } define i1 @discr_xor_eq(i8 %a, i8 %b) { ; CHECK-LABEL: @discr_xor_eq( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i8 [[A:%.*]], 1 ; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i8 [[B:%.*]], 1 ; CHECK-NEXT: [[TMP0:%.*]] = select i1 [[CMP1]], i8 [[A]], i8 -4 ; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[CMP2]], i8 [[B]], i8 -4 ; CHECK-NEXT: [[RES:%.*]] = icmp eq i8 [[TMP0]], [[TMP1]] ; CHECK-NEXT: ret i1 [[RES]] ; entry: %xor1 = xor i8 %a, -3 %cmp1 = icmp ugt i8 %a, 1 %sel1 = select i1 %cmp1, i8 %xor1, i8 1 %xor2 = xor i8 %b, -3 %cmp2 = icmp ugt i8 %b, 1 %sel2 = select i1 %cmp2, i8 %xor2, i8 1 %res = icmp eq i8 %sel1, %sel2 ret i1 %res } define i1 @discr_eq_simple(i8 %a, i8 %b) { ; CHECK-LABEL: @discr_eq_simple( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i8 [[A:%.*]], 1 ; CHECK-NEXT: [[TMP0:%.*]] = select i1 [[CMP1]], i8 [[A]], i8 3 ; CHECK-NEXT: [[RES:%.*]] = icmp eq i8 [[TMP0]], [[B:%.*]] ; CHECK-NEXT: ret i1 [[RES]] ; entry: %add1 = add i8 %a, -2 %cmp1 = icmp ugt i8 %a, 1 %sel1 = select i1 %cmp1, i8 %add1, i8 1 %add2 = add i8 %b, -2 %res = icmp eq i8 %sel1, %add2 ret i1 %res } define i1 @discr_eq_add_commuted(i8 noundef %a, i8 %b, i8 %c, i1 %cond1, i1 %cond2) { ; CHECK-LABEL: @discr_eq_add_commuted( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP0:%.*]] = select i1 [[COND1:%.*]], i8 [[B:%.*]], i8 0 ; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[COND2:%.*]], i8 [[C:%.*]], i8 [[B]] ; CHECK-NEXT: [[RES:%.*]] = icmp eq i8 [[TMP0]], [[TMP1]] ; CHECK-NEXT: ret i1 [[RES]] ; entry: %add1 = add i8 %a, %b %sel1 = select i1 %cond1, i8 %add1, i8 %a %add2 = add i8 %c, %a %sel2 = select i1 %cond2, i8 %add2, i8 %add1 %res = icmp eq i8 %sel1, %sel2 ret i1 %res } define i1 @discr_eq_add_commuted_implies_poison(i8 %a, i8 %b, i8 %c, i1 %cond1, i1 %cond2) { ; CHECK-LABEL: @discr_eq_add_commuted_implies_poison( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP0:%.*]] = select i1 [[COND1:%.*]], i8 [[B:%.*]], i8 0 ; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[COND2:%.*]], i8 [[C:%.*]], i8 [[B]] ; CHECK-NEXT: [[RES:%.*]] = icmp eq i8 [[TMP0]], [[TMP1]] ; CHECK-NEXT: ret i1 [[RES]] ; entry: %add1 = add i8 %a, %b %sel1 = select i1 %cond1, i8 %add1, i8 %a %add2 = add i8 %c, %a %sel2 = select i1 %cond2, i8 %add2, i8 %add1 %res = icmp eq i8 %sel1, %sel2 ret i1 %res } define i1 @discr_eq_sub(i8 noundef %a, i8 %b, i8 %c, i1 %cond1, i1 %cond2) { ; CHECK-LABEL: @discr_eq_sub( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP0:%.*]] = select i1 [[COND1:%.*]], i8 [[B:%.*]], i8 0 ; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[COND2:%.*]], i8 [[C:%.*]], i8 0 ; CHECK-NEXT: [[RES:%.*]] = icmp eq i8 [[TMP0]], [[TMP1]] ; CHECK-NEXT: ret i1 [[RES]] ; entry: %neg = sub i8 0, %a %sub1 = sub i8 %b, %a %sel1 = select i1 %cond1, i8 %sub1, i8 %neg %sub2 = sub i8 %c, %a %sel2 = select i1 %cond2, i8 %sub2, i8 %neg %res = icmp eq i8 %sel1, %sel2 ret i1 %res } ; Negative tests define i1 @discr_eq_multi_use(i8 %a, i8 %b) { ; CHECK-LABEL: @discr_eq_multi_use( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ADD1:%.*]] = add i8 [[A:%.*]], -2 ; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i8 [[A]], 1 ; CHECK-NEXT: [[SEL1:%.*]] = select i1 [[CMP1]], i8 [[ADD1]], i8 1 ; CHECK-NEXT: call void @use(i8 [[SEL1]]) ; CHECK-NEXT: [[ADD2:%.*]] = add i8 [[B:%.*]], -2 ; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i8 [[B]], 1 ; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[CMP2]], i8 [[ADD2]], i8 1 ; CHECK-NEXT: [[RES:%.*]] = icmp eq i8 [[SEL1]], [[SEL2]] ; CHECK-NEXT: ret i1 [[RES]] ; entry: %add1 = add i8 %a, -2 %cmp1 = icmp ugt i8 %a, 1 %sel1 = select i1 %cmp1, i8 %add1, i8 1 call void @use(i8 %sel1) %add2 = add i8 %b, -2 %cmp2 = icmp ugt i8 %b, 1 %sel2 = select i1 %cmp2, i8 %add2, i8 1 %res = icmp eq i8 %sel1, %sel2 ret i1 %res } define i1 @discr_eq_failed_to_simplify(i8 %a, i8 %b) { ; CHECK-LABEL: @discr_eq_failed_to_simplify( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ADD1:%.*]] = add i8 [[A:%.*]], -3 ; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i8 [[A]], 1 ; CHECK-NEXT: [[SEL1:%.*]] = select i1 [[CMP1]], i8 [[ADD1]], i8 1 ; CHECK-NEXT: [[ADD2:%.*]] = add i8 [[B:%.*]], -2 ; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i8 [[B]], 1 ; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[CMP2]], i8 [[ADD2]], i8 1 ; CHECK-NEXT: [[RES:%.*]] = icmp eq i8 [[SEL1]], [[SEL2]] ; CHECK-NEXT: ret i1 [[RES]] ; entry: %add1 = add i8 %a, -3 %cmp1 = icmp ugt i8 %a, 1 %sel1 = select i1 %cmp1, i8 %add1, i8 1 %add2 = add i8 %b, -2 %cmp2 = icmp ugt i8 %b, 1 %sel2 = select i1 %cmp2, i8 %add2, i8 1 %res = icmp eq i8 %sel1, %sel2 ret i1 %res } define <2 x i1> @discr_eq_simple_vec(<2 x i8> %a, <2 x i8> %b, i1 %cond) { ; CHECK-LABEL: @discr_eq_simple_vec( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ADD1:%.*]] = add <2 x i8> [[A:%.*]], ; CHECK-NEXT: [[SEL1:%.*]] = select i1 [[COND:%.*]], <2 x i8> [[ADD1]], <2 x i8> splat (i8 1) ; CHECK-NEXT: [[ADD2:%.*]] = add <2 x i8> [[B:%.*]], ; CHECK-NEXT: [[RES:%.*]] = icmp eq <2 x i8> [[SEL1]], [[ADD2]] ; CHECK-NEXT: ret <2 x i1> [[RES]] ; entry: %add1 = add <2 x i8> %a, %sel1 = select i1 %cond, <2 x i8> %add1, <2 x i8> splat(i8 1) %add2 = add <2 x i8> %b, %res = icmp eq <2 x i8> %sel1, %add2 ret <2 x i1> %res } define i1 @discr_eq_sub_commuted(i8 noundef %a, i8 %b, i8 %c, i1 %cond1, i1 %cond2) { ; CHECK-LABEL: @discr_eq_sub_commuted( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[NEG:%.*]] = sub i8 0, [[A:%.*]] ; CHECK-NEXT: [[SUB1:%.*]] = sub i8 [[A]], [[B:%.*]] ; CHECK-NEXT: [[SEL1:%.*]] = select i1 [[COND1:%.*]], i8 [[SUB1]], i8 [[NEG]] ; CHECK-NEXT: [[SUB2:%.*]] = sub i8 [[A]], [[C:%.*]] ; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[COND2:%.*]], i8 [[SUB2]], i8 [[NEG]] ; CHECK-NEXT: [[RES:%.*]] = icmp eq i8 [[SEL1]], [[SEL2]] ; CHECK-NEXT: ret i1 [[RES]] ; entry: %neg = sub i8 0, %a %sub1 = sub i8 %a, %b %sel1 = select i1 %cond1, i8 %sub1, i8 %neg %sub2 = sub i8 %a, %c %sel2 = select i1 %cond2, i8 %sub2, i8 %neg %res = icmp eq i8 %sel1, %sel2 ret i1 %res } @g = external global i8 ; Do not introduce constant expressions. define i1 @discr_eq_constantexpr(ptr %p) { ; CHECK-LABEL: @discr_eq_constantexpr( ; CHECK-NEXT: [[I:%.*]] = ptrtoint ptr [[P:%.*]] to i64 ; CHECK-NEXT: [[SUB:%.*]] = sub i64 [[I]], ptrtoint (ptr @g to i64) ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[SUB]], -1 ; CHECK-NEXT: ret i1 [[CMP]] ; %i = ptrtoint ptr %p to i64 %sub = sub i64 %i, ptrtoint (ptr @g to i64) %cmp = icmp eq i64 %sub, -1 ret i1 %cmp }