[llvm] 54ec8bc - Recommit "[InstCombine] Expand `foldSelectICmpAndOr` -> `foldSelectICmpAndBinOp` to work for more binops" (3rd Try)
Noah Goldstein via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 1 15:16:06 PDT 2023
Author: Noah Goldstein
Date: 2023-09-01T17:15:51-05:00
New Revision: 54ec8bcaf85e3a3341c97640331d58e24ac0d2cd
URL: https://github.com/llvm/llvm-project/commit/54ec8bcaf85e3a3341c97640331d58e24ac0d2cd
DIFF: https://github.com/llvm/llvm-project/commit/54ec8bcaf85e3a3341c97640331d58e24ac0d2cd.diff
LOG: Recommit "[InstCombine] Expand `foldSelectICmpAndOr` -> `foldSelectICmpAndBinOp` to work for more binops" (3rd Try)
Fixed bug that assumed binop was commutative.
Was re-reviewed by nikic and chapuni
Differential Revision: https://reviews.llvm.org/D148414
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
llvm/test/Transforms/InstCombine/select-with-bitwise-ops.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index ee248d06373738..33d370690e71a8 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -689,25 +689,32 @@ static Value *foldSelectICmpLshrAshr(const ICmpInst *IC, Value *TrueVal,
}
/// 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 @@ static Value *foldSelectICmpAndOr(const ICmpInst *IC, Value *TrueVal,
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<BinaryOperator>(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<BinaryOperator>(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 @@ static Value *foldSelectICmpAndOr(const ICmpInst *IC, Value *TrueVal,
// 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 @@ static Value *foldSelectICmpAndOr(const ICmpInst *IC, Value *TrueVal,
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 @@ Instruction *InstCombinerImpl::foldSelectInstWithICmp(SelectInst &SI,
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
index b83ac3b92637a4..6e31f9b20e3a96 100644
--- 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 <2 x i32> @select_icmp_eq_and_1_0_or_2_vec(<2 x i32> %x, <2 x i32> %y) {
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 <2 x i32> @select_icmp_eq_and_32_0_or_8_vec(<2 x i32> %x, <2 x i32> %y) {
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 <2 x i32> @select_icmp_ne_0_and_4096_or_4096_vec(<2 x i32> %x, <2 x i32>
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 <2 x i32> @select_icmp_eq_and_4096_0_or_4096_vec(<2 x i32> %x, <2 x i32>
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 <2 x i32> @select_icmp_eq_0_and_1_or_1_vec(<2 x i64> %x, <2 x i32> %y) {
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_or_32(i32 %x, i32 %y) {
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 <2 x i32> @select_icmp_ne_0_and_32_or_4096_vec(<2 x i32> %x, <2 x i32> %y
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 i32 @select_icmp_and_8_eq_0_xor_8(i32 %x) {
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_eq_0_y_xor_8(i32 %x, i64 %y) {
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 <2 x i32> @test68vec(<2 x i32> %x, <2 x i32> %y) {
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 <2 x i32> @test69vec(<2 x i32> %x, <2 x i32> %y) {
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_or(i32 %x, i32 %y) {
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_or(i32 %x, i32 %y) {
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_or(i32 %x, i32 %y) {
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 @@ define i32 @shift_no_xor_multiuse_cmp_with_xor(i32 %x, i32 %y, i32 %z, i32 %w) {
; 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 @@ define i32 @no_shift_no_xor_multiuse_cmp_with_xor(i32 %x, i32 %y, i32 %z, i32 %w
; 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 @@ define i32 @no_shift_xor_multiuse_cmp_with_xor(i32 %x, i32 %y, i32 %z, i32 %w) {
; 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 @@ define i32 @no_shift_no_xor_multiuse_cmp_xor(i32 %x, i32 %y, i32 %z, i32 %w) {
; 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_eq(i8 %x, i64 %y) {
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 @@ define i64 @xor_i8_to_i64_shl_save_and_ne(i8 %x, i64 %y) {
%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
+}
More information about the llvm-commits
mailing list