@@ -514,7 +514,8 @@ static Value *foldLogOpOfMaskedICmpsAsymmetric(
514514// / into a single (icmp(A & X) ==/!= Y).
515515static Value *foldLogOpOfMaskedICmps (ICmpInst *LHS, ICmpInst *RHS, bool IsAnd,
516516 bool IsLogical,
517- InstCombiner::BuilderTy &Builder) {
517+ InstCombiner::BuilderTy &Builder,
518+ const SimplifyQuery &Q) {
518519 Value *A = nullptr , *B = nullptr , *C = nullptr , *D = nullptr , *E = nullptr ;
519520 ICmpInst::Predicate PredL = LHS->getPredicate (), PredR = RHS->getPredicate ();
520521 std::optional<std::pair<unsigned , unsigned >> MaskPair =
@@ -587,93 +588,107 @@ static Value *foldLogOpOfMaskedICmps(ICmpInst *LHS, ICmpInst *RHS, bool IsAnd,
587588 return Builder.CreateICmp (NewCC, NewAnd2, A);
588589 }
589590
590- // Remaining cases assume at least that B and D are constant, and depend on
591- // their actual values. This isn't strictly necessary, just a "handle the
592- // easy cases for now" decision.
593591 const APInt *ConstB, *ConstD;
594- if (!match (B, m_APInt (ConstB)) || !match (D, m_APInt (ConstD)))
595- return nullptr ;
596-
597- if (Mask & (Mask_NotAllZeros | BMask_NotAllOnes)) {
598- // (icmp ne (A & B), 0) & (icmp ne (A & D), 0) and
599- // (icmp ne (A & B), B) & (icmp ne (A & D), D)
600- // -> (icmp ne (A & B), 0) or (icmp ne (A & D), 0)
601- // Only valid if one of the masks is a superset of the other (check "B&D" is
602- // the same as either B or D).
603- APInt NewMask = *ConstB & *ConstD;
604- if (NewMask == *ConstB)
605- return LHS;
606- else if (NewMask == *ConstD)
607- return RHS;
608- }
609-
610- if (Mask & AMask_NotAllOnes) {
611- // (icmp ne (A & B), B) & (icmp ne (A & D), D)
612- // -> (icmp ne (A & B), A) or (icmp ne (A & D), A)
613- // Only valid if one of the masks is a superset of the other (check "B|D" is
614- // the same as either B or D).
615- APInt NewMask = *ConstB | *ConstD;
616- if (NewMask == *ConstB)
617- return LHS;
618- else if (NewMask == *ConstD)
619- return RHS;
620- }
621-
622- if (Mask & (BMask_Mixed | BMask_NotMixed)) {
623- // Mixed:
624- // (icmp eq (A & B), C) & (icmp eq (A & D), E)
625- // We already know that B & C == C && D & E == E.
626- // If we can prove that (B & D) & (C ^ E) == 0, that is, the bits of
627- // C and E, which are shared by both the mask B and the mask D, don't
628- // contradict, then we can transform to
629- // -> (icmp eq (A & (B|D)), (C|E))
630- // Currently, we only handle the case of B, C, D, and E being constant.
631- // We can't simply use C and E because we might actually handle
632- // (icmp ne (A & B), B) & (icmp eq (A & D), D)
633- // with B and D, having a single bit set.
634-
635- // NotMixed:
636- // (icmp ne (A & B), C) & (icmp ne (A & D), E)
637- // -> (icmp ne (A & (B & D)), (C & E))
638- // Check the intersection (B & D) for inequality.
639- // Assume that (B & D) == B || (B & D) == D, i.e B/D is a subset of D/B
640- // and (B & D) & (C ^ E) == 0, bits of C and E, which are shared by both the
641- // B and the D, don't contradict.
642- // Note that we can assume (~B & C) == 0 && (~D & E) == 0, previous
643- // operation should delete these icmps if it hadn't been met.
644-
645- const APInt *OldConstC, *OldConstE;
646- if (!match (C, m_APInt (OldConstC)) || !match (E, m_APInt (OldConstE)))
647- return nullptr ;
648-
649- auto FoldBMixed = [&](ICmpInst::Predicate CC, bool IsNot) -> Value * {
650- CC = IsNot ? CmpInst::getInversePredicate (CC) : CC;
651- const APInt ConstC = PredL != CC ? *ConstB ^ *OldConstC : *OldConstC;
652- const APInt ConstE = PredR != CC ? *ConstD ^ *OldConstE : *OldConstE;
592+ if (match (B, m_APInt (ConstB)) && match (D, m_APInt (ConstD))) {
593+ if (Mask & (Mask_NotAllZeros | BMask_NotAllOnes)) {
594+ // (icmp ne (A & B), 0) & (icmp ne (A & D), 0) and
595+ // (icmp ne (A & B), B) & (icmp ne (A & D), D)
596+ // -> (icmp ne (A & B), 0) or (icmp ne (A & D), 0)
597+ // Only valid if one of the masks is a superset of the other (check "B&D"
598+ // is the same as either B or D).
599+ APInt NewMask = *ConstB & *ConstD;
600+ if (NewMask == *ConstB)
601+ return LHS;
602+ if (NewMask == *ConstD)
603+ return RHS;
604+ }
653605
654- if (((*ConstB & *ConstD) & (ConstC ^ ConstE)).getBoolValue ())
655- return IsNot ? nullptr : ConstantInt::get (LHS->getType (), !IsAnd);
606+ if (Mask & AMask_NotAllOnes) {
607+ // (icmp ne (A & B), B) & (icmp ne (A & D), D)
608+ // -> (icmp ne (A & B), A) or (icmp ne (A & D), A)
609+ // Only valid if one of the masks is a superset of the other (check "B|D"
610+ // is the same as either B or D).
611+ APInt NewMask = *ConstB | *ConstD;
612+ if (NewMask == *ConstB)
613+ return LHS;
614+ if (NewMask == *ConstD)
615+ return RHS;
616+ }
656617
657- if (IsNot && !ConstB->isSubsetOf (*ConstD) && !ConstD->isSubsetOf (*ConstB))
618+ if (Mask & (BMask_Mixed | BMask_NotMixed)) {
619+ // Mixed:
620+ // (icmp eq (A & B), C) & (icmp eq (A & D), E)
621+ // We already know that B & C == C && D & E == E.
622+ // If we can prove that (B & D) & (C ^ E) == 0, that is, the bits of
623+ // C and E, which are shared by both the mask B and the mask D, don't
624+ // contradict, then we can transform to
625+ // -> (icmp eq (A & (B|D)), (C|E))
626+ // Currently, we only handle the case of B, C, D, and E being constant.
627+ // We can't simply use C and E because we might actually handle
628+ // (icmp ne (A & B), B) & (icmp eq (A & D), D)
629+ // with B and D, having a single bit set.
630+
631+ // NotMixed:
632+ // (icmp ne (A & B), C) & (icmp ne (A & D), E)
633+ // -> (icmp ne (A & (B & D)), (C & E))
634+ // Check the intersection (B & D) for inequality.
635+ // Assume that (B & D) == B || (B & D) == D, i.e B/D is a subset of D/B
636+ // and (B & D) & (C ^ E) == 0, bits of C and E, which are shared by both
637+ // the B and the D, don't contradict. Note that we can assume (~B & C) ==
638+ // 0 && (~D & E) == 0, previous operation should delete these icmps if it
639+ // hadn't been met.
640+
641+ const APInt *OldConstC, *OldConstE;
642+ if (!match (C, m_APInt (OldConstC)) || !match (E, m_APInt (OldConstE)))
658643 return nullptr ;
659644
660- APInt BD, CE;
661- if (IsNot) {
662- BD = *ConstB & *ConstD;
663- CE = ConstC & ConstE;
664- } else {
665- BD = *ConstB | *ConstD;
666- CE = ConstC | ConstE;
667- }
668- Value *NewAnd = Builder.CreateAnd (A, BD);
669- Value *CEVal = ConstantInt::get (A->getType (), CE);
670- return Builder.CreateICmp (CC, CEVal, NewAnd);
671- };
645+ auto FoldBMixed = [&](ICmpInst::Predicate CC, bool IsNot) -> Value * {
646+ CC = IsNot ? CmpInst::getInversePredicate (CC) : CC;
647+ const APInt ConstC = PredL != CC ? *ConstB ^ *OldConstC : *OldConstC;
648+ const APInt ConstE = PredR != CC ? *ConstD ^ *OldConstE : *OldConstE;
649+
650+ if (((*ConstB & *ConstD) & (ConstC ^ ConstE)).getBoolValue ())
651+ return IsNot ? nullptr : ConstantInt::get (LHS->getType (), !IsAnd);
652+
653+ if (IsNot && !ConstB->isSubsetOf (*ConstD) &&
654+ !ConstD->isSubsetOf (*ConstB))
655+ return nullptr ;
656+
657+ APInt BD, CE;
658+ if (IsNot) {
659+ BD = *ConstB & *ConstD;
660+ CE = ConstC & ConstE;
661+ } else {
662+ BD = *ConstB | *ConstD;
663+ CE = ConstC | ConstE;
664+ }
665+ Value *NewAnd = Builder.CreateAnd (A, BD);
666+ Value *CEVal = ConstantInt::get (A->getType (), CE);
667+ return Builder.CreateICmp (CC, CEVal, NewAnd);
668+ };
669+
670+ if (Mask & BMask_Mixed)
671+ return FoldBMixed (NewCC, false );
672+ if (Mask & BMask_NotMixed) // can be else also
673+ return FoldBMixed (NewCC, true );
674+ }
675+ }
672676
673- if (Mask & BMask_Mixed)
674- return FoldBMixed (NewCC, false );
675- if (Mask & BMask_NotMixed) // can be else also
676- return FoldBMixed (NewCC, true );
677+ // (icmp eq (A & B), 0) | (icmp eq (A & D), 0)
678+ // -> (icmp ne (A & (B|D)), (B|D))
679+ // (icmp ne (A & B), 0) & (icmp ne (A & D), 0)
680+ // -> (icmp eq (A & (B|D)), (B|D))
681+ // iff B and D is known to be a power of two
682+ if (Mask & Mask_NotAllZeros &&
683+ isKnownToBeAPowerOfTwo (B, /* OrZero=*/ false , /* Depth=*/ 0 , Q) &&
684+ isKnownToBeAPowerOfTwo (D, /* OrZero=*/ false , /* Depth=*/ 0 , Q)) {
685+ // If this is a logical and/or, then we must prevent propagation of a
686+ // poison value from the RHS by inserting freeze.
687+ if (IsLogical)
688+ D = Builder.CreateFreeze (D);
689+ Value *Mask = Builder.CreateOr (B, D);
690+ Value *Masked = Builder.CreateAnd (A, Mask);
691+ return Builder.CreateICmp (NewCC, Masked, Mask);
677692 }
678693 return nullptr ;
679694}
@@ -776,46 +791,6 @@ foldAndOrOfICmpsWithPow2AndWithZero(InstCombiner::BuilderTy &Builder,
776791 return Builder.CreateICmp (Pred, And, Op);
777792}
778793
779- // Fold (iszero(A & K1) | iszero(A & K2)) -> (A & (K1 | K2)) != (K1 | K2)
780- // Fold (!iszero(A & K1) & !iszero(A & K2)) -> (A & (K1 | K2)) == (K1 | K2)
781- Value *InstCombinerImpl::foldAndOrOfICmpsOfAndWithPow2 (ICmpInst *LHS,
782- ICmpInst *RHS,
783- Instruction *CxtI,
784- bool IsAnd,
785- bool IsLogical) {
786- CmpInst::Predicate Pred = IsAnd ? CmpInst::ICMP_NE : CmpInst::ICMP_EQ;
787- if (LHS->getPredicate () != Pred || RHS->getPredicate () != Pred)
788- return nullptr ;
789-
790- if (!match (LHS->getOperand (1 ), m_Zero ()) ||
791- !match (RHS->getOperand (1 ), m_Zero ()))
792- return nullptr ;
793-
794- Value *L1, *L2, *R1, *R2;
795- if (match (LHS->getOperand (0 ), m_And (m_Value (L1), m_Value (L2))) &&
796- match (RHS->getOperand (0 ), m_And (m_Value (R1), m_Value (R2)))) {
797- if (L1 == R2 || L2 == R2)
798- std::swap (R1, R2);
799- if (L2 == R1)
800- std::swap (L1, L2);
801-
802- if (L1 == R1 &&
803- isKnownToBeAPowerOfTwo (L2, false , 0 , CxtI) &&
804- isKnownToBeAPowerOfTwo (R2, false , 0 , CxtI)) {
805- // If this is a logical and/or, then we must prevent propagation of a
806- // poison value from the RHS by inserting freeze.
807- if (IsLogical)
808- R2 = Builder.CreateFreeze (R2);
809- Value *Mask = Builder.CreateOr (L2, R2);
810- Value *Masked = Builder.CreateAnd (L1, Mask);
811- auto NewPred = IsAnd ? CmpInst::ICMP_EQ : CmpInst::ICMP_NE;
812- return Builder.CreateICmp (NewPred, Masked, Mask);
813- }
814- }
815-
816- return nullptr ;
817- }
818-
819794// / General pattern:
820795// / X & Y
821796// /
@@ -3327,12 +3302,6 @@ Value *InstCombinerImpl::foldAndOrOfICmps(ICmpInst *LHS, ICmpInst *RHS,
33273302 bool IsLogical) {
33283303 const SimplifyQuery Q = SQ.getWithInstruction (&I);
33293304
3330- // Fold (iszero(A & K1) | iszero(A & K2)) -> (A & (K1 | K2)) != (K1 | K2)
3331- // Fold (!iszero(A & K1) & !iszero(A & K2)) -> (A & (K1 | K2)) == (K1 | K2)
3332- // if K1 and K2 are a one-bit mask.
3333- if (Value *V = foldAndOrOfICmpsOfAndWithPow2 (LHS, RHS, &I, IsAnd, IsLogical))
3334- return V;
3335-
33363305 ICmpInst::Predicate PredL = LHS->getPredicate (), PredR = RHS->getPredicate ();
33373306 Value *LHS0 = LHS->getOperand (0 ), *RHS0 = RHS->getOperand (0 );
33383307 Value *LHS1 = LHS->getOperand (1 ), *RHS1 = RHS->getOperand (1 );
@@ -3359,7 +3328,7 @@ Value *InstCombinerImpl::foldAndOrOfICmps(ICmpInst *LHS, ICmpInst *RHS,
33593328 // handle (roughly):
33603329 // (icmp ne (A & B), C) | (icmp ne (A & D), E)
33613330 // (icmp eq (A & B), C) & (icmp eq (A & D), E)
3362- if (Value *V = foldLogOpOfMaskedICmps (LHS, RHS, IsAnd, IsLogical, Builder))
3331+ if (Value *V = foldLogOpOfMaskedICmps (LHS, RHS, IsAnd, IsLogical, Builder, Q ))
33633332 return V;
33643333
33653334 if (Value *V =
0 commit comments