@@ -1687,6 +1687,120 @@ static Value *foldSelectInstWithICmpConst(SelectInst &SI, ICmpInst *ICI,
1687
1687
return nullptr ;
1688
1688
}
1689
1689
1690
+ static Instruction *foldSelectICmpEq (SelectInst &SI, ICmpInst *ICI,
1691
+ InstCombinerImpl &IC) {
1692
+ ICmpInst::Predicate Pred = ICI->getPredicate ();
1693
+ if (!ICmpInst::isEquality (Pred))
1694
+ return nullptr ;
1695
+
1696
+ Value *TrueVal = SI.getTrueValue ();
1697
+ Value *FalseVal = SI.getFalseValue ();
1698
+ Value *CmpLHS = ICI->getOperand (0 );
1699
+ Value *CmpRHS = ICI->getOperand (1 );
1700
+
1701
+ if (Pred == ICmpInst::ICMP_NE)
1702
+ std::swap (TrueVal, FalseVal);
1703
+
1704
+ // Transform (X == C) ? X : Y -> (X == C) ? C : Y
1705
+ // specific handling for Bitwise operation.
1706
+ // https://alive2.llvm.org/ce/z/mW3eYR
1707
+ // x&y -> (x|y) ^ (x^y) or (x|y) & ~(x^y)
1708
+ // x|y -> (x&y) | (x^y) or (x&y) ^ (x^y)
1709
+ // x^y -> (x|y) ^ (x&y) or (x|y) & ~(x&y)
1710
+ Value *X, *Y;
1711
+ if (!(match (CmpLHS, m_BitwiseLogic (m_Value (X), m_Value (Y)))) ||
1712
+ !(match (TrueVal, m_c_BitwiseLogic (m_Specific (X), m_Specific (Y)))))
1713
+ return nullptr ;
1714
+
1715
+ Value *AllOnes = Constant::getAllOnesValue (TrueVal->getType ());
1716
+ Value *Null = Constant::getNullValue (TrueVal->getType ());
1717
+ Instruction *ISI = &cast<Instruction>(SI);
1718
+ const unsigned AndOps = Instruction::And, OrOps = Instruction::Or,
1719
+ XorOps = Instruction::Xor, NoOps = 0 ;
1720
+ enum NotMask { None = 0 , NotInner, NotRHS };
1721
+
1722
+ auto matchFalseVal = [&](unsigned OuterOpc, unsigned InnerOpc,
1723
+ unsigned NotMask) {
1724
+ auto matchInner = m_c_BinOp (InnerOpc, m_Specific (X), m_Specific (Y));
1725
+ if (OuterOpc == NoOps) {
1726
+ if (match (CmpRHS, m_Zero ()))
1727
+ return match (FalseVal, matchInner);
1728
+ else
1729
+ return false ;
1730
+ }
1731
+
1732
+ if (NotMask == NotInner) {
1733
+ return match (FalseVal,
1734
+ m_c_BinOp (OuterOpc, m_Not (matchInner), m_Specific (CmpRHS)));
1735
+ } else if (NotMask == NotRHS) {
1736
+ return match (FalseVal,
1737
+ m_c_BinOp (OuterOpc, matchInner, m_Not (m_Specific (CmpRHS))));
1738
+ } else {
1739
+ return match (FalseVal,
1740
+ m_c_BinOp (OuterOpc, matchInner, m_Specific (CmpRHS)));
1741
+ }
1742
+ };
1743
+
1744
+ // https://alive2.llvm.org/ce/z/rw7XWv
1745
+ // (X&Y)==C ? X|Y : X^Y -> (X^Y)|C : X^Y or (X^Y)^ C : X^Y
1746
+ // (X&Y)==C ? X^Y : X|Y -> (X|Y)^C : X|Y or (X|Y)&~C : X|Y
1747
+ if (match (CmpLHS, m_And (m_Value (X), m_Value (Y)))) {
1748
+ if (match (TrueVal, m_c_Or (m_Specific (X), m_Specific (Y)))) {
1749
+ // (X&Y)==C ? X|Y : (X^Y)|C -> (X^Y)|C : (X^Y)|C -> (X^Y)|C
1750
+ if (matchFalseVal (OrOps, XorOps, None) ||
1751
+ // (X&Y)==C ? X|Y : (X^Y)^C -> (X^Y)^C : (X^Y)^C -> (X^Y)^C
1752
+ matchFalseVal (XorOps, XorOps, None))
1753
+ return IC.replaceInstUsesWith (*ISI, FalseVal);
1754
+ } else if (match (TrueVal, m_c_Xor (m_Specific (X), m_Specific (Y)))) {
1755
+ // (X&Y)==C ? X^Y : (X|Y)^ C -> (X|Y)^ C : (X|Y)^ C -> (X|Y)^ C
1756
+ if (matchFalseVal (XorOps, OrOps, None) ||
1757
+ // (X&Y)==C ? X^Y : (X|Y)&~C -> (X|Y)&~C : (X|Y)&~C -> (X|Y)&~C
1758
+ matchFalseVal (AndOps, OrOps, NotRHS))
1759
+ return IC.replaceInstUsesWith (*ISI, FalseVal);
1760
+ }
1761
+ }
1762
+
1763
+ // https://alive2.llvm.org/ce/z/5yaUzR
1764
+ // (X|Y)==C ? X&Y : X^Y -> (X^Y)^C : X^Y or ~(X^Y)&C : X^Y
1765
+ // (X|Y)==C ? X^Y : X&Y -> (X&Y)^C : X&Y or ~(X&Y)&C : X&Y
1766
+ if (match (CmpLHS, m_Or (m_Value (X), m_Value (Y)))) {
1767
+ if (match (TrueVal, m_c_And (m_Specific (X), m_Specific (Y)))) {
1768
+ // (X|Y)==C ? X&Y: (X^Y)^C -> (X^Y)^C: (X^Y)^C -> (X^Y)^C
1769
+ if (matchFalseVal (XorOps, XorOps, None) ||
1770
+ // (X|Y)==C ? X&Y:~(X^Y)&C ->~(X^Y)&C:~(X^Y)&C -> ~(X^Y)&C
1771
+ matchFalseVal (AndOps, XorOps, NotInner))
1772
+ return IC.replaceInstUsesWith (*ISI, FalseVal);
1773
+ } else if (match (TrueVal, m_c_Xor (m_Specific (X), m_Specific (Y)))) {
1774
+ // (X|Y)==C ? X^Y : (X&Y)^C -> (X&Y)^C : (X&Y)^C -> (X&Y)^C
1775
+ if (matchFalseVal (XorOps, AndOps, None) ||
1776
+ // (X|Y)==C ? X^Y :~(X&Y)&C -> ~(X&Y)&C :~(X&Y)&C -> ~(X&Y)&C
1777
+ matchFalseVal (AndOps, AndOps, NotInner))
1778
+ return IC.replaceInstUsesWith (*ISI, FalseVal);
1779
+ }
1780
+ }
1781
+
1782
+ // https://alive2.llvm.org/ce/z/dA9Hy-
1783
+ // (X^Y)==C ? X&Y : X|Y -> (X|Y)^C : X|Y or (X|Y)&~C : X|Y
1784
+ // (X^Y)==C ? X|Y : X&Y -> (X&Y)|C : X&Y or (X&Y)^ C : X&Y
1785
+ if (match (CmpLHS, m_Xor (m_Value (X), m_Value (Y)))) {
1786
+ if ((match (TrueVal, m_c_And (m_Specific (X), m_Specific (Y))))) {
1787
+ // (X^Y)==C ? X&Y : (X|Y)^C -> (X|Y)^C
1788
+ if (matchFalseVal (XorOps, OrOps, None) ||
1789
+ // (X^Y)==C ? X&Y : (X|Y)&~C -> (X|Y)&~C
1790
+ matchFalseVal (AndOps, OrOps, NotRHS))
1791
+ return IC.replaceInstUsesWith (*ISI, FalseVal);
1792
+ } else if (match (TrueVal, m_c_Or (m_Specific (X), m_Specific (Y)))) {
1793
+ // (X^Y)==C ? (X|Y) : (X&Y)|C -> (X&Y)|C
1794
+ if (matchFalseVal (OrOps, AndOps, None) ||
1795
+ // (X^Y)==C ? (X|Y) : (X&Y)^C -> (X&Y)^C
1796
+ matchFalseVal (XorOps, AndOps, None))
1797
+ return IC.replaceInstUsesWith (*ISI, FalseVal);
1798
+ }
1799
+ }
1800
+
1801
+ return nullptr ;
1802
+ }
1803
+
1690
1804
// / Visit a SelectInst that has an ICmpInst as its first operand.
1691
1805
Instruction *InstCombinerImpl::foldSelectInstWithICmp (SelectInst &SI,
1692
1806
ICmpInst *ICI) {
@@ -1729,6 +1843,9 @@ Instruction *InstCombinerImpl::foldSelectInstWithICmp(SelectInst &SI,
1729
1843
}
1730
1844
}
1731
1845
1846
+ if (Instruction *NewSel = foldSelectICmpEq (SI, ICI, *this ))
1847
+ return NewSel;
1848
+
1732
1849
// Canonicalize a signbit condition to use zero constant by swapping:
1733
1850
// (CmpLHS > -1) ? TV : FV --> (CmpLHS < 0) ? FV : TV
1734
1851
// To avoid conflicts (infinite loops) with other canonicalizations, this is
0 commit comments