diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -689,25 +689,32 @@ } /// We want to turn: -/// (select (icmp eq (and X, C1), 0), Y, (or Y, C2)) +/// (select (icmp eq (and X, C1), 0), Y, (BinOp Y, C2)) /// into: -/// (or (shl (and X, C1), C3), Y) +/// IF C2 u>= C1 +/// (BinOp Y, (shl (and X, C1), C3)) +/// ELSE +/// (BinOp Y, (lshr (and X, C1), C3)) /// iff: +/// 0 on the RHS is the identity value (i.e add, xor, shl, etc...) /// C1 and C2 are both powers of 2 /// where: -/// C3 = Log(C2) - Log(C1) +/// IF C2 u>= C1 +/// C3 = Log(C2) - Log(C1) +/// ELSE +/// C3 = Log(C1) - Log(C2) /// /// This transform handles cases where: /// 1. The icmp predicate is inverted /// 2. The select operands are reversed /// 3. The magnitude of C2 and C1 are flipped -static Value *foldSelectICmpAndOr(const ICmpInst *IC, Value *TrueVal, +static Value *foldSelectICmpAndBinOp(const ICmpInst *IC, Value *TrueVal, Value *FalseVal, InstCombiner::BuilderTy &Builder) { // Only handle integer compares. Also, if this is a vector select, we need a // vector compare. if (!TrueVal->getType()->isIntOrIntVectorTy() || - TrueVal->getType()->isVectorTy() != IC->getType()->isVectorTy()) + TrueVal->getType()->isVectorTy() != IC->getType()->isVectorTy()) return nullptr; Value *CmpLHS = IC->getOperand(0); @@ -735,21 +742,29 @@ NeedAnd = true; } - Value *Or, *Y, *V = CmpLHS; + Value *Y, *V = CmpLHS; + BinaryOperator *BinOp; const APInt *C2; bool NeedXor; - if (match(FalseVal, m_Or(m_Specific(TrueVal), m_Power2(C2)))) { + if (match(FalseVal, m_BinOp(m_Specific(TrueVal), m_Power2(C2)))) { Y = TrueVal; - Or = FalseVal; + BinOp = cast(FalseVal); NeedXor = Pred == ICmpInst::ICMP_NE; - } else if (match(TrueVal, m_Or(m_Specific(FalseVal), m_Power2(C2)))) { + } else if (match(TrueVal, m_BinOp(m_Specific(FalseVal), m_Power2(C2)))) { Y = FalseVal; - Or = TrueVal; + BinOp = cast(TrueVal); NeedXor = Pred == ICmpInst::ICMP_EQ; } else { return nullptr; } + // Check that 0 on RHS is identity value for this binop. + auto *IdentityC = + ConstantExpr::getBinOpIdentity(BinOp->getOpcode(), BinOp->getType(), + /*AllowRHSConstant*/ true); + if (IdentityC == nullptr || !IdentityC->isNullValue()) + return nullptr; + unsigned C2Log = C2->logBase2(); bool NeedShift = C1Log != C2Log; @@ -758,7 +773,7 @@ // Make sure we don't create more instructions than we save. if ((NeedShift + NeedXor + NeedZExtTrunc + NeedAnd) > - (IC->hasOneUse() + Or->hasOneUse())) + (IC->hasOneUse() + BinOp->hasOneUse())) return nullptr; if (NeedAnd) { @@ -779,7 +794,7 @@ if (NeedXor) V = Builder.CreateXor(V, *C2); - return Builder.CreateOr(V, Y); + return Builder.CreateBinOp(BinOp->getOpcode(), Y, V); } /// Canonicalize a set or clear of a masked set of constant bits to @@ -1788,7 +1803,7 @@ if (Instruction *V = foldSelectZeroOrOnes(ICI, TrueVal, FalseVal, Builder)) return V; - if (Value *V = foldSelectICmpAndOr(ICI, TrueVal, FalseVal, Builder)) + if (Value *V = foldSelectICmpAndBinOp(ICI, TrueVal, FalseVal, Builder)) return replaceInstUsesWith(SI, V); if (Value *V = foldSelectICmpLshrAshr(ICI, TrueVal, FalseVal, Builder)) diff --git a/llvm/test/Transforms/InstCombine/select-with-bitwise-ops.ll b/llvm/test/Transforms/InstCombine/select-with-bitwise-ops.ll --- a/llvm/test/Transforms/InstCombine/select-with-bitwise-ops.ll +++ b/llvm/test/Transforms/InstCombine/select-with-bitwise-ops.ll @@ -36,10 +36,9 @@ define i32 @select_icmp_eq_and_1_0_xor_2(i32 %x, i32 %y) { ; CHECK-LABEL: @select_icmp_eq_and_1_0_xor_2( -; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 1 -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0 -; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], 2 -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], i32 [[Y]], i32 [[XOR]] +; CHECK-NEXT: [[AND:%.*]] = shl i32 [[X:%.*]], 1 +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[AND]], 2 +; CHECK-NEXT: [[SELECT:%.*]] = xor i32 [[TMP1]], [[Y:%.*]] ; CHECK-NEXT: ret i32 [[SELECT]] ; %and = and i32 %x, 1 @@ -94,10 +93,9 @@ define i32 @select_icmp_eq_and_32_0_xor_8(i32 %x, i32 %y) { ; CHECK-LABEL: @select_icmp_eq_and_32_0_xor_8( -; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 32 -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0 -; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], 8 -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], i32 [[Y]], i32 [[XOR]] +; CHECK-NEXT: [[AND:%.*]] = lshr i32 [[X:%.*]], 2 +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[AND]], 8 +; CHECK-NEXT: [[SELECT:%.*]] = xor i32 [[TMP1]], [[Y:%.*]] ; CHECK-NEXT: ret i32 [[SELECT]] ; %and = and i32 %x, 32 @@ -153,9 +151,8 @@ define i32 @select_icmp_ne_0_and_4096_xor_4096(i32 %x, i32 %y) { ; CHECK-LABEL: @select_icmp_ne_0_and_4096_xor_4096( ; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 4096 -; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i32 [[AND]], 0 -; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], 4096 -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP_NOT]], i32 [[XOR]], i32 [[Y]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[AND]], [[Y:%.*]] +; CHECK-NEXT: [[SELECT:%.*]] = xor i32 [[TMP1]], 4096 ; CHECK-NEXT: ret i32 [[SELECT]] ; %and = and i32 %x, 4096 @@ -209,9 +206,7 @@ define i32 @select_icmp_eq_and_4096_0_xor_4096(i32 %x, i32 %y) { ; CHECK-LABEL: @select_icmp_eq_and_4096_0_xor_4096( ; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 4096 -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0 -; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], 4096 -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], i32 [[Y]], i32 [[XOR]] +; CHECK-NEXT: [[SELECT:%.*]] = xor i32 [[AND]], [[Y:%.*]] ; CHECK-NEXT: ret i32 [[SELECT]] ; %and = and i32 %x, 4096 @@ -267,8 +262,8 @@ define i32 @select_icmp_eq_0_and_1_xor_1(i64 %x, i32 %y) { ; CHECK-LABEL: @select_icmp_eq_0_and_1_xor_1( ; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[X:%.*]] to i32 -; CHECK-NEXT: [[XOR:%.*]] = and i32 [[TMP1]], 1 -; CHECK-NEXT: [[SELECT:%.*]] = xor i32 [[XOR]], [[Y:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 1 +; CHECK-NEXT: [[SELECT:%.*]] = xor i32 [[TMP2]], [[Y:%.*]] ; CHECK-NEXT: ret i32 [[SELECT]] ; %and = and i64 %x, 1 @@ -310,10 +305,10 @@ define i32 @select_icmp_ne_0_and_4096_xor_32(i32 %x, i32 %y) { ; CHECK-LABEL: @select_icmp_ne_0_and_4096_xor_32( -; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 4096 -; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i32 [[AND]], 0 -; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], 32 -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP_NOT]], i32 [[XOR]], i32 [[Y]] +; CHECK-NEXT: [[AND:%.*]] = lshr i32 [[X:%.*]], 7 +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[AND]], 32 +; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP1]], [[Y:%.*]] +; CHECK-NEXT: [[SELECT:%.*]] = xor i32 [[TMP2]], 32 ; CHECK-NEXT: ret i32 [[SELECT]] ; %and = and i32 %x, 4096 @@ -370,10 +365,10 @@ define i32 @select_icmp_ne_0_and_32_xor_4096(i32 %x, i32 %y) { ; CHECK-LABEL: @select_icmp_ne_0_and_32_xor_4096( -; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 32 -; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i32 [[AND]], 0 -; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], 4096 -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP_NOT]], i32 [[XOR]], i32 [[Y]] +; CHECK-NEXT: [[AND:%.*]] = shl i32 [[X:%.*]], 7 +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[AND]], 4096 +; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP1]], [[Y:%.*]] +; CHECK-NEXT: [[SELECT:%.*]] = xor i32 [[TMP2]], 4096 ; CHECK-NEXT: ret i32 [[SELECT]] ; %and = and i32 %x, 32 @@ -532,9 +527,8 @@ define i64 @select_icmp_x_and_8_eq_0_y_xor_8(i32 %x, i64 %y) { ; CHECK-LABEL: @select_icmp_x_and_8_eq_0_y_xor_8( ; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 8 -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0 -; CHECK-NEXT: [[XOR:%.*]] = xor i64 [[Y:%.*]], 8 -; CHECK-NEXT: [[Y_XOR:%.*]] = select i1 [[CMP]], i64 [[Y]], i64 [[XOR]] +; CHECK-NEXT: [[TMP1:%.*]] = zext i32 [[AND]] to i64 +; CHECK-NEXT: [[Y_XOR:%.*]] = xor i64 [[TMP1]], [[Y:%.*]] ; CHECK-NEXT: ret i64 [[Y_XOR]] ; %and = and i32 %x, 8 @@ -547,9 +541,9 @@ define i64 @select_icmp_x_and_8_ne_0_y_xor_8(i32 %x, i64 %y) { ; CHECK-LABEL: @select_icmp_x_and_8_ne_0_y_xor_8( ; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 8 -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0 -; CHECK-NEXT: [[XOR:%.*]] = xor i64 [[Y:%.*]], 8 -; CHECK-NEXT: [[XOR_Y:%.*]] = select i1 [[CMP]], i64 [[XOR]], i64 [[Y]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[AND]], 8 +; CHECK-NEXT: [[TMP2:%.*]] = zext i32 [[TMP1]] to i64 +; CHECK-NEXT: [[XOR_Y:%.*]] = xor i64 [[TMP2]], [[Y:%.*]] ; CHECK-NEXT: ret i64 [[XOR_Y]] ; %and = and i32 %x, 8 @@ -670,10 +664,9 @@ define i32 @test68_xor(i32 %x, i32 %y) { ; CHECK-LABEL: @test68_xor( -; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 128 -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0 -; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], 2 -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], i32 [[Y]], i32 [[XOR]] +; CHECK-NEXT: [[AND:%.*]] = lshr i32 [[X:%.*]], 6 +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[AND]], 2 +; CHECK-NEXT: [[SELECT:%.*]] = xor i32 [[TMP1]], [[Y:%.*]] ; CHECK-NEXT: ret i32 [[SELECT]] ; %and = and i32 %x, 128 @@ -730,10 +723,10 @@ define i32 @test69_xor(i32 %x, i32 %y) { ; CHECK-LABEL: @test69_xor( -; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 128 -; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i32 [[AND]], 0 -; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], 2 -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP_NOT]], i32 [[XOR]], i32 [[Y]] +; CHECK-NEXT: [[AND:%.*]] = lshr i32 [[X:%.*]], 6 +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[AND]], 2 +; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP1]], [[Y:%.*]] +; CHECK-NEXT: [[SELECT:%.*]] = xor i32 [[TMP2]], 2 ; CHECK-NEXT: ret i32 [[SELECT]] ; %and = and i32 %x, 128 @@ -805,10 +798,10 @@ define i32 @shift_no_xor_multiuse_xor(i32 %x, i32 %y) { ; CHECK-LABEL: @shift_no_xor_multiuse_xor( -; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 1 -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0 ; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], 2 -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], i32 [[Y]], i32 [[XOR]] +; CHECK-NEXT: [[AND:%.*]] = shl i32 [[X:%.*]], 1 +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[AND]], 2 +; CHECK-NEXT: [[SELECT:%.*]] = xor i32 [[TMP1]], [[Y]] ; CHECK-NEXT: [[RES:%.*]] = mul i32 [[SELECT]], [[XOR]] ; CHECK-NEXT: ret i32 [[RES]] ; @@ -856,9 +849,8 @@ define i32 @no_shift_no_xor_multiuse_xor(i32 %x, i32 %y) { ; CHECK-LABEL: @no_shift_no_xor_multiuse_xor( ; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 4096 -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0 ; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], 4096 -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], i32 [[Y]], i32 [[XOR]] +; CHECK-NEXT: [[SELECT:%.*]] = xor i32 [[AND]], [[Y]] ; CHECK-NEXT: [[RES:%.*]] = mul i32 [[SELECT]], [[XOR]] ; CHECK-NEXT: ret i32 [[RES]] ; @@ -907,9 +899,9 @@ define i32 @no_shift_xor_multiuse_xor(i32 %x, i32 %y) { ; CHECK-LABEL: @no_shift_xor_multiuse_xor( ; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 4096 -; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i32 [[AND]], 0 ; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], 4096 -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP_NOT]], i32 [[XOR]], i32 [[Y]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[AND]], [[Y]] +; CHECK-NEXT: [[SELECT:%.*]] = xor i32 [[TMP1]], 4096 ; CHECK-NEXT: [[RES:%.*]] = mul i32 [[SELECT]], [[XOR]] ; CHECK-NEXT: ret i32 [[RES]] ; @@ -1012,8 +1004,8 @@ ; CHECK-LABEL: @shift_no_xor_multiuse_cmp_with_xor( ; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 1 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0 -; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], 2 -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], i32 [[Y]], i32 [[XOR]] +; CHECK-NEXT: [[TMP1:%.*]] = shl nuw nsw i32 [[AND]], 1 +; CHECK-NEXT: [[SELECT:%.*]] = xor i32 [[TMP1]], [[Y:%.*]] ; CHECK-NEXT: [[SELECT2:%.*]] = select i1 [[CMP]], i32 [[Z:%.*]], i32 [[W:%.*]] ; CHECK-NEXT: [[RES:%.*]] = mul i32 [[SELECT]], [[SELECT2]] ; CHECK-NEXT: ret i32 [[RES]] @@ -1068,8 +1060,7 @@ ; CHECK-LABEL: @no_shift_no_xor_multiuse_cmp_with_xor( ; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 4096 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0 -; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], 4096 -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], i32 [[Y]], i32 [[XOR]] +; CHECK-NEXT: [[SELECT:%.*]] = xor i32 [[AND]], [[Y:%.*]] ; CHECK-NEXT: [[SELECT2:%.*]] = select i1 [[CMP]], i32 [[Z:%.*]], i32 [[W:%.*]] ; CHECK-NEXT: [[RES:%.*]] = mul i32 [[SELECT]], [[SELECT2]] ; CHECK-NEXT: ret i32 [[RES]] @@ -1125,8 +1116,8 @@ ; CHECK-LABEL: @no_shift_xor_multiuse_cmp_with_xor( ; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 4096 ; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i32 [[AND]], 0 -; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], 4096 -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP_NOT]], i32 [[XOR]], i32 [[Y]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[AND]], [[Y:%.*]] +; CHECK-NEXT: [[SELECT:%.*]] = xor i32 [[TMP1]], 4096 ; CHECK-NEXT: [[SELECT2:%.*]] = select i1 [[CMP_NOT]], i32 [[W:%.*]], i32 [[Z:%.*]] ; CHECK-NEXT: [[RES:%.*]] = mul i32 [[SELECT]], [[SELECT2]] ; CHECK-NEXT: ret i32 [[RES]] @@ -1305,7 +1296,7 @@ ; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 4096 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0 ; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], 4096 -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], i32 [[Y]], i32 [[XOR]] +; CHECK-NEXT: [[SELECT:%.*]] = xor i32 [[AND]], [[Y]] ; CHECK-NEXT: [[SELECT2:%.*]] = select i1 [[CMP]], i32 [[Z:%.*]], i32 [[W:%.*]] ; CHECK-NEXT: [[RES:%.*]] = mul i32 [[SELECT]], [[SELECT2]] ; CHECK-NEXT: [[RES2:%.*]] = mul i32 [[RES]], [[XOR]] @@ -1606,10 +1597,9 @@ define i64 @xor_i8_to_i64_shl_save_and_ne(i8 %x, i64 %y) { ; CHECK-LABEL: @xor_i8_to_i64_shl_save_and_ne( -; CHECK-NEXT: [[XX:%.*]] = and i8 [[X:%.*]], 1 -; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i8 [[XX]], 0 -; CHECK-NEXT: [[Z:%.*]] = xor i64 [[Y:%.*]], -9223372036854775808 -; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP_NOT]], i64 [[Y]], i64 [[Z]] +; CHECK-NEXT: [[TMP1:%.*]] = zext i8 [[X:%.*]] to i64 +; CHECK-NEXT: [[TMP2:%.*]] = shl i64 [[TMP1]], 63 +; CHECK-NEXT: [[R:%.*]] = xor i64 [[TMP2]], [[Y:%.*]] ; CHECK-NEXT: ret i64 [[R]] ; %xx = and i8 %x, 1 @@ -1618,3 +1608,62 @@ %r = select i1 %cmp, i64 %z, i64 %y ret i64 %r } + +define i32 @select_icmp_eq_and_1_0_srem_2_fail_null_identity(i32 %x, i32 %y) { +; CHECK-LABEL: @select_icmp_eq_and_1_0_srem_2_fail_null_identity( +; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 1 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0 +; CHECK-NEXT: [[XOR:%.*]] = srem i32 [[Y:%.*]], 2 +; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], i32 [[Y]], i32 [[XOR]] +; CHECK-NEXT: ret i32 [[SELECT]] +; + %and = and i32 %x, 1 + %cmp = icmp eq i32 %and, 0 + %xor = srem i32 %y, 2 + %select = select i1 %cmp, i32 %y, i32 %xor + ret i32 %select +} + + +define i32 @select_icmp_eq_and_1_0_sdiv_2_fail_null_1_identity(i32 %x, i32 %y) { +; CHECK-LABEL: @select_icmp_eq_and_1_0_sdiv_2_fail_null_1_identity( +; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 1 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0 +; CHECK-NEXT: [[XOR:%.*]] = sdiv i32 [[Y:%.*]], 2 +; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], i32 [[Y]], i32 [[XOR]] +; CHECK-NEXT: ret i32 [[SELECT]] +; + %and = and i32 %x, 1 + %cmp = icmp eq i32 %and, 0 + %xor = sdiv i32 %y, 2 + %select = select i1 %cmp, i32 %y, i32 %xor + ret i32 %select +} + +define i8 @select_icmp_eq_and_1_0_lshr_fv(i8 %x, i8 %y) { +; CHECK-LABEL: @select_icmp_eq_and_1_0_lshr_fv( +; CHECK-NEXT: [[AND:%.*]] = shl i8 [[X:%.*]], 1 +; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[AND]], 2 +; CHECK-NEXT: [[SELECT:%.*]] = lshr i8 [[Y:%.*]], [[TMP1]] +; CHECK-NEXT: ret i8 [[SELECT]] +; + %and = and i8 %x, 1 + %cmp = icmp eq i8 %and, 0 + %blshr = lshr i8 %y, 2 + %select = select i1 %cmp, i8 %y, i8 %blshr + ret i8 %select +} + +define i8 @select_icmp_eq_and_1_0_lshr_tv(i8 %x, i8 %y) { +; CHECK-LABEL: @select_icmp_eq_and_1_0_lshr_tv( +; CHECK-NEXT: [[AND:%.*]] = shl i8 [[X:%.*]], 1 +; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[AND]], 2 +; CHECK-NEXT: [[SELECT:%.*]] = lshr i8 [[Y:%.*]], [[TMP1]] +; CHECK-NEXT: ret i8 [[SELECT]] +; + %and = and i8 %x, 1 + %cmp = icmp ne i8 %and, 0 + %blshr = lshr i8 %y, 2 + %select = select i1 %cmp, i8 %blshr, i8 %y + ret i8 %select +}