Index: lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -316,11 +316,6 @@ ICmpInst *RHS, ICmpInst::Predicate &PredL, ICmpInst::Predicate &PredR) { - // vectors are not (yet?) supported. Don't support pointers either. - if (!LHS->getOperand(0)->getType()->isIntegerTy() || - !RHS->getOperand(0)->getType()->isIntegerTy()) - return None; - // Here comes the tricky part: // LHS might be of the form L11 & L12 == X, X == L21 & L22, // and L11 & L12 == L21 & L22. The same goes for RHS. @@ -604,18 +599,64 @@ return nullptr; } -/// Try to fold (icmp(A & B) ==/!= C) &/| (icmp(A & D) ==/!= E) -/// into a single (icmp(A & X) ==/!= Y). +/// Try to fold (icmp(_ & _) ==/!= _) &/| _ static Value *foldLogOpOfMaskedICmps(ICmpInst *LHS, ICmpInst *RHS, bool IsAnd, llvm::InstCombiner::BuilderTy &Builder) { Value *A = nullptr, *B = nullptr, *C = nullptr, *D = nullptr, *E = nullptr; + // We only handle logical operations ICmpInst::Predicate PredL = LHS->getPredicate(), PredR = RHS->getPredicate(); + if (!(ICmpInst::isEquality(PredL) && ICmpInst::isEquality(PredR))) + return nullptr; + bool LIsEq = (PredL == ICmpInst::ICMP_EQ); + bool RIsEq = (PredR == ICmpInst::ICMP_EQ); + + // vectors are not (yet) supported. Don't support pointers either. + if (!LHS->getOperand(0)->getType()->isIntegerTy() || + !RHS->getOperand(0)->getType()->isIntegerTy()) + return nullptr; + + ConstantInt *BCst, *CCst; + + // Dead code elimination + // i.e. (icmp eq (A & B), C), where (A & C) == 0 or (B & C) == 0 + // or (icmp ne (A & B), C), where (A & C) == 0 or (B & C) == 0 and C != 0 + if (match(LHS, m_c_ICmp(PredL, + m_c_And(m_Value(), m_ConstantInt(BCst)), m_ConstantInt(CCst)))) { + if ((BCst->getValue() & CCst->getValue()) == 0) { + if ((PredL == ICmpInst::ICMP_NE) && (C == 0)) + ; + else if (IsAnd && LIsEq) + return ConstantInt::get(LHS->getType(), false); + else if (IsAnd && !LIsEq) + return RHS; + else if (!IsAnd && LIsEq) + return RHS; + else if (!IsAnd && !LIsEq) + return ConstantInt::get(LHS->getType(), true); + } + } + if (match(RHS, m_c_ICmp(PredR, + m_c_And(m_Value(), m_ConstantInt(BCst)), m_ConstantInt(CCst)))) { + if ((BCst->getValue() & CCst->getValue()) == 0) { + if ((PredR == ICmpInst::ICMP_NE) && (C == 0)) + ; + else if (IsAnd && RIsEq) + return ConstantInt::get(RHS->getType(), false); + else if (IsAnd && !RIsEq) + return LHS; + else if (!IsAnd && RIsEq) + return LHS; + else if (!IsAnd && !RIsEq) + return ConstantInt::get(RHS->getType(), true); + } + } + +/// Try to fold (icmp(A & B) ==/!= C) &/| (icmp(A & D) ==/!= E) +/// into a single (icmp(A & X) ==/!= Y). Optional> MaskPair = getMaskedTypeForICmpPair(A, B, C, D, E, LHS, RHS, PredL, PredR); if (!MaskPair) return nullptr; - assert(ICmpInst::isEquality(PredL) && ICmpInst::isEquality(PredR) && - "Expected equality predicates for masked type of icmps."); unsigned LHSMask = MaskPair->first; unsigned RHSMask = MaskPair->second; unsigned Mask = LHSMask & RHSMask; @@ -677,7 +718,7 @@ // Remaining cases assume at least that B and D are constant, and depend on // their actual values. This isn't strictly necessary, just a "handle the // easy cases for now" decision. - ConstantInt *BCst = dyn_cast(B); + BCst = dyn_cast(B); if (!BCst) return nullptr; ConstantInt *DCst = dyn_cast(D); @@ -722,7 +763,7 @@ // We can't simply use C and E because we might actually handle // (icmp ne (A & B), B) & (icmp eq (A & D), D) // with B and D, having a single bit set. - ConstantInt *CCst = dyn_cast(C); + CCst = dyn_cast(C); if (!CCst) return nullptr; ConstantInt *ECst = dyn_cast(E); @@ -1046,7 +1087,7 @@ } } - // handle (roughly): (icmp eq (A & B), C) & (icmp eq (A & D), E) + // handle: (icmp eq/ne (A & B), C) & D if (Value *V = foldLogOpOfMaskedICmps(LHS, RHS, true, Builder)) return V; Index: test/Transforms/InstCombine/and-or-icmps.ll =================================================================== --- test/Transforms/InstCombine/and-or-icmps.ll +++ test/Transforms/InstCombine/and-or-icmps.ll @@ -3,7 +3,7 @@ define i1 @PR1817_1(i32 %X) { ; CHECK-LABEL: @PR1817_1( -; CHECK-NEXT: [[B:%.*]] = icmp ult i32 %X, 10 +; CHECK-NEXT: [[B:%.*]] = icmp ult i32 [[X:%.*]], 10 ; CHECK-NEXT: ret i1 [[B]] ; %A = icmp slt i32 %X, 10 @@ -14,7 +14,7 @@ define i1 @PR1817_2(i32 %X) { ; CHECK-LABEL: @PR1817_2( -; CHECK-NEXT: [[A:%.*]] = icmp slt i32 %X, 10 +; CHECK-NEXT: [[A:%.*]] = icmp slt i32 [[X:%.*]], 10 ; CHECK-NEXT: ret i1 [[A]] ; %A = icmp slt i32 %X, 10 @@ -25,7 +25,7 @@ define i1 @PR2330(i32 %a, i32 %b) { ; CHECK-LABEL: @PR2330( -; CHECK-NEXT: [[TMP1:%.*]] = or i32 %b, %a +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[B:%.*]], [[A:%.*]] ; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 [[TMP1]], 8 ; CHECK-NEXT: ret i1 [[TMP2]] ; @@ -41,7 +41,7 @@ define i1 @or_eq_with_one_bit_diff_constants1(i32 %x) { ; CHECK-LABEL: @or_eq_with_one_bit_diff_constants1( -; CHECK-NEXT: [[TMP1:%.*]] = or i32 %x, 1 +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[X:%.*]], 1 ; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 51 ; CHECK-NEXT: ret i1 [[TMP2]] ; @@ -55,7 +55,7 @@ define i1 @and_ne_with_one_bit_diff_constants1(i32 %x) { ; CHECK-LABEL: @and_ne_with_one_bit_diff_constants1( -; CHECK-NEXT: [[TMP1:%.*]] = or i32 %x, 1 +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[X:%.*]], 1 ; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i32 [[TMP1]], 51 ; CHECK-NEXT: ret i1 [[TMP2]] ; @@ -69,7 +69,7 @@ define i1 @or_eq_with_one_bit_diff_constants2(i32 %x) { ; CHECK-LABEL: @or_eq_with_one_bit_diff_constants2( -; CHECK-NEXT: [[TMP1:%.*]] = or i32 %x, 32 +; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[X:%.*]], 32 ; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 97 ; CHECK-NEXT: ret i1 [[TMP2]] ; @@ -81,7 +81,7 @@ define i1 @and_ne_with_one_bit_diff_constants2(i19 %x) { ; CHECK-LABEL: @and_ne_with_one_bit_diff_constants2( -; CHECK-NEXT: [[TMP1:%.*]] = or i19 %x, 128 +; CHECK-NEXT: [[TMP1:%.*]] = or i19 [[X:%.*]], 128 ; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i19 [[TMP1]], 193 ; CHECK-NEXT: ret i1 [[TMP2]] ; @@ -95,7 +95,7 @@ define i1 @or_eq_with_one_bit_diff_constants3(i8 %x) { ; CHECK-LABEL: @or_eq_with_one_bit_diff_constants3( -; CHECK-NEXT: [[TMP1:%.*]] = or i8 %x, -128 +; CHECK-NEXT: [[TMP1:%.*]] = or i8 [[X:%.*]], -128 ; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i8 [[TMP1]], -2 ; CHECK-NEXT: ret i1 [[TMP2]] ; @@ -107,7 +107,7 @@ define i1 @and_ne_with_one_bit_diff_constants3(i8 %x) { ; CHECK-LABEL: @and_ne_with_one_bit_diff_constants3( -; CHECK-NEXT: [[TMP1:%.*]] = or i8 %x, -128 +; CHECK-NEXT: [[TMP1:%.*]] = or i8 [[X:%.*]], -128 ; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i8 [[TMP1]], -63 ; CHECK-NEXT: ret i1 [[TMP2]] ; @@ -122,7 +122,7 @@ define i1 @or_eq_with_diff_one(i8 %x) { ; CHECK-LABEL: @or_eq_with_diff_one( -; CHECK-NEXT: [[TMP1:%.*]] = add i8 %x, -13 +; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[X:%.*]], -13 ; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i8 [[TMP1]], 2 ; CHECK-NEXT: ret i1 [[TMP2]] ; @@ -136,7 +136,7 @@ define i1 @and_ne_with_diff_one(i32 %x) { ; CHECK-LABEL: @and_ne_with_diff_one( -; CHECK-NEXT: [[TMP1:%.*]] = add i32 %x, -39 +; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], -39 ; CHECK-NEXT: [[TMP2:%.*]] = icmp ugt i32 [[TMP1]], 1 ; CHECK-NEXT: ret i1 [[TMP2]] ; @@ -151,7 +151,7 @@ define i1 @or_eq_with_diff_one_signed(i32 %x) { ; CHECK-LABEL: @or_eq_with_diff_one_signed( -; CHECK-NEXT: [[TMP1:%.*]] = add i32 %x, 1 +; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], 1 ; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i32 [[TMP1]], 2 ; CHECK-NEXT: ret i1 [[TMP2]] ; @@ -163,7 +163,7 @@ define i1 @and_ne_with_diff_one_signed(i64 %x) { ; CHECK-LABEL: @and_ne_with_diff_one_signed( -; CHECK-NEXT: [[TMP1:%.*]] = add i64 %x, 1 +; CHECK-NEXT: [[TMP1:%.*]] = add i64 [[X:%.*]], 1 ; CHECK-NEXT: [[TMP2:%.*]] = icmp ugt i64 [[TMP1]], 1 ; CHECK-NEXT: ret i1 [[TMP2]] ; @@ -177,7 +177,7 @@ define <2 x i1> @or_eq_with_one_bit_diff_constants2_splatvec(<2 x i32> %x) { ; CHECK-LABEL: @or_eq_with_one_bit_diff_constants2_splatvec( -; CHECK-NEXT: [[TMP1:%.*]] = or <2 x i32> %x, +; CHECK-NEXT: [[TMP1:%.*]] = or <2 x i32> [[X:%.*]], ; CHECK-NEXT: [[TMP2:%.*]] = icmp eq <2 x i32> [[TMP1]], ; CHECK-NEXT: ret <2 x i1> [[TMP2]] ; @@ -189,7 +189,7 @@ define <2 x i1> @and_ne_with_diff_one_splatvec(<2 x i32> %x) { ; CHECK-LABEL: @and_ne_with_diff_one_splatvec( -; CHECK-NEXT: [[TMP1:%.*]] = add <2 x i32> %x, +; CHECK-NEXT: [[TMP1:%.*]] = add <2 x i32> [[X:%.*]], ; CHECK-NEXT: [[TMP2:%.*]] = icmp ugt <2 x i32> [[TMP1]], ; CHECK-NEXT: ret <2 x i1> [[TMP2]] ; @@ -253,3 +253,25 @@ ret void } +define i1 @dce(i32 %a) { +; CHECK-LABEL: @dce( +; CHECK-NEXT: ret i1 true +; + %tmp3 = and i32 %a, 8 + %tmp4 = icmp ne i32 %tmp3, 2 + ret i1 %tmp4 +} + +define i1 @dce2(i32 %a) { +; CHECK-LABEL: @dce2( +; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[A:%.*]], 16 +; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i32 [[TMP1]], 0 +; CHECK-NEXT: ret i1 [[TMP2]] +; + %tmp1 = and i32 %a, 16 + %tmp2 = icmp eq i32 %tmp1, 16 + %tmp3 = and i32 %a, 8 + %tmp4 = icmp ne i32 %tmp3, 2 + %tmp5 = and i1 %tmp2, %tmp4 + ret i1 %tmp5 +}