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 @@ -624,9 +624,9 @@ } /// 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) +/// (binop (shl (and X, C1), C3), Y) /// iff: /// C1 and C2 are both powers of 2 /// where: @@ -636,7 +636,7 @@ /// 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 @@ -648,7 +648,6 @@ Value *CmpLHS = IC->getOperand(0); Value *CmpRHS = IC->getOperand(1); - Value *V; unsigned C1Log; bool IsEqualZero; bool NeedAnd = false; @@ -660,7 +659,6 @@ if (!match(CmpLHS, m_And(m_Value(), m_Power2(C1)))) return nullptr; - V = CmpLHS; C1Log = C1->logBase2(); IsEqualZero = IC->getPredicate() == ICmpInst::ICMP_EQ; } else { @@ -676,16 +674,17 @@ NeedAnd = true; } - Value *Or, *Y; + Value *V = CmpLHS, *Y; + 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 = !IsEqualZero; - } 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 = IsEqualZero; } else { return nullptr; @@ -699,7 +698,7 @@ // Make sure we don't create more instructions than we save. if ((NeedShift + NeedXor + NeedZExtTrunc) > - (IC->hasOneUse() + Or->hasOneUse())) + (IC->hasOneUse() + BinOp->hasOneUse())) return nullptr; if (NeedAnd) { @@ -720,7 +719,7 @@ if (NeedXor) V = Builder.CreateXor(V, *C2); - return Builder.CreateOr(V, Y); + return Builder.CreateBinOp(BinOp->getOpcode(), V, Y); } /// Canonicalize a set or clear of a masked set of constant bits to @@ -1813,7 +1812,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 @@ -745,10 +738,10 @@ define i32 @test69_and(i32 %x, i32 %y) { ; CHECK-LABEL: @test69_and( -; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], 128 -; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp eq i32 [[AND]], 0 -; CHECK-NEXT: [[AND2:%.*]] = and i32 [[Y:%.*]], 2 -; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP_NOT]], i32 [[AND2]], i32 [[Y]] +; CHECK-NEXT: [[AND:%.*]] = lshr i32 [[X:%.*]], 6 +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[AND]], 2 +; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP1]], 2 +; CHECK-NEXT: [[SELECT:%.*]] = and i32 [[TMP2]], [[Y:%.*]] ; CHECK-NEXT: ret i32 [[SELECT]] ; %and = and i32 %x, 128 @@ -790,10 +783,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]] ; @@ -841,9 +834,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]] ; @@ -892,9 +884,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]] ; @@ -997,8 +989,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]] @@ -1053,8 +1045,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]] @@ -1110,8 +1101,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]] @@ -1290,7 +1281,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]] @@ -1591,10 +1582,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