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