@@ -514,7 +514,8 @@ static Value *foldLogOpOfMaskedICmpsAsymmetric(
514
514
// / into a single (icmp(A & X) ==/!= Y).
515
515
static Value *foldLogOpOfMaskedICmps (ICmpInst *LHS, ICmpInst *RHS, bool IsAnd,
516
516
bool IsLogical,
517
- InstCombiner::BuilderTy &Builder) {
517
+ InstCombiner::BuilderTy &Builder,
518
+ const SimplifyQuery &Q) {
518
519
Value *A = nullptr , *B = nullptr , *C = nullptr , *D = nullptr , *E = nullptr ;
519
520
ICmpInst::Predicate PredL = LHS->getPredicate (), PredR = RHS->getPredicate ();
520
521
std::optional<std::pair<unsigned , unsigned >> MaskPair =
@@ -587,93 +588,107 @@ static Value *foldLogOpOfMaskedICmps(ICmpInst *LHS, ICmpInst *RHS, bool IsAnd,
587
588
return Builder.CreateICmp (NewCC, NewAnd2, A);
588
589
}
589
590
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.
593
591
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
+ }
653
605
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
+ }
656
617
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)))
658
643
return nullptr ;
659
644
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
+ }
672
676
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);
677
692
}
678
693
return nullptr ;
679
694
}
@@ -776,46 +791,6 @@ foldAndOrOfICmpsWithPow2AndWithZero(InstCombiner::BuilderTy &Builder,
776
791
return Builder.CreateICmp (Pred, And, Op);
777
792
}
778
793
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
-
819
794
// / General pattern:
820
795
// / X & Y
821
796
// /
@@ -3327,12 +3302,6 @@ Value *InstCombinerImpl::foldAndOrOfICmps(ICmpInst *LHS, ICmpInst *RHS,
3327
3302
bool IsLogical) {
3328
3303
const SimplifyQuery Q = SQ.getWithInstruction (&I);
3329
3304
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
-
3336
3305
ICmpInst::Predicate PredL = LHS->getPredicate (), PredR = RHS->getPredicate ();
3337
3306
Value *LHS0 = LHS->getOperand (0 ), *RHS0 = RHS->getOperand (0 );
3338
3307
Value *LHS1 = LHS->getOperand (1 ), *RHS1 = RHS->getOperand (1 );
@@ -3359,7 +3328,7 @@ Value *InstCombinerImpl::foldAndOrOfICmps(ICmpInst *LHS, ICmpInst *RHS,
3359
3328
// handle (roughly):
3360
3329
// (icmp ne (A & B), C) | (icmp ne (A & D), E)
3361
3330
// (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 ))
3363
3332
return V;
3364
3333
3365
3334
if (Value *V =
0 commit comments