@@ -1790,6 +1790,158 @@ static Instruction *foldSelectICmpEq(SelectInst &SI, ICmpInst *ICI,
1790
1790
return nullptr ;
1791
1791
}
1792
1792
1793
+ // ICmpInst of SelectInst is not included in the calculation of KnownBits
1794
+ // so we are missing the opportunity to optimize the Value of the True or
1795
+ // False Condition via ICmpInst with KnownBits.
1796
+ //
1797
+ // Consider:
1798
+ // %or = or i32 %x, %y
1799
+ // %or0 = icmp eq i32 %or, 0
1800
+ // %and = and i32 %x, %y
1801
+ // %cond = select i1 %or0, i32 %and, i32 %or
1802
+ // ret i32 %cond
1803
+ //
1804
+ // Expect:
1805
+ // %or = or i32 %x, %y
1806
+ // ret i32 %or
1807
+ //
1808
+ // We could know what bit was enabled for %x, %y by ICmpInst in SelectInst.
1809
+ static Instruction *foldSelectICmpBinOp (SelectInst &SI, ICmpInst *ICI,
1810
+ Value *CmpLHS, Value *CmpRHS,
1811
+ Value *TVal, Value *FVal,
1812
+ InstCombinerImpl &IC) {
1813
+ Value *X, *Y;
1814
+ const APInt *C;
1815
+
1816
+ if (!((match (CmpLHS, m_BinOp (m_Value (X), m_Value (Y))) &&
1817
+ match (CmpRHS, m_APInt (C))) &&
1818
+ (match (TVal, m_c_BinOp (m_Specific (X), m_Value ())) ||
1819
+ match (TVal, m_c_BinOp (m_Specific (Y), m_Value ())))))
1820
+ return nullptr ;
1821
+
1822
+ enum SpecialKnownBits {
1823
+ NothingSpecial = 0 ,
1824
+ NoCommonBits = 1 << 1 ,
1825
+ AllCommonBits = 1 << 2 ,
1826
+ AllBitsEnabled = 1 << 3 ,
1827
+ };
1828
+
1829
+ // We cannot know exactly what bits is known in X Y.
1830
+ // Instead, we just know what relationship exist for.
1831
+ auto isSpecialKnownBitsFor = [&](const Instruction *CmpLHS,
1832
+ const APInt *CmpRHS) -> unsigned {
1833
+ unsigned Opc = CmpLHS->getOpcode ();
1834
+ if (Opc == Instruction::And) {
1835
+ if (CmpRHS->isZero ())
1836
+ return NoCommonBits;
1837
+ } else if (Opc == Instruction::Xor) {
1838
+ if (CmpRHS->isAllOnes ())
1839
+ return NoCommonBits | AllBitsEnabled;
1840
+ if (CmpRHS->isZero ())
1841
+ return AllCommonBits;
1842
+ }
1843
+
1844
+ return NothingSpecial;
1845
+ };
1846
+
1847
+ auto hasOperandAt = [&](Instruction *I, Value *Op) -> int {
1848
+ for (unsigned Idx = 0 ; Idx < I->getNumOperands (); Idx++) {
1849
+ if (I->getOperand (Idx) == Op)
1850
+ return Idx + 1 ;
1851
+ }
1852
+ return 0 ;
1853
+ };
1854
+
1855
+ Type *TValTy = TVal->getType ();
1856
+ unsigned BitWidth = TVal->getType ()->getScalarSizeInBits ();
1857
+ auto TValBop = cast<BinaryOperator>(TVal);
1858
+ auto CmpLHSBop = cast<BinaryOperator>(CmpLHS);
1859
+ unsigned XOrder = hasOperandAt (TValBop, X);
1860
+ unsigned YOrder = hasOperandAt (TValBop, Y);
1861
+ unsigned SKB = isSpecialKnownBitsFor (CmpLHSBop, C);
1862
+
1863
+ KnownBits Known;
1864
+ if (TValBop->isBitwiseLogicOp ()) {
1865
+ if (SKB != SpecialKnownBits::NothingSpecial && XOrder && YOrder) {
1866
+ if (SKB & SpecialKnownBits::NoCommonBits) {
1867
+ if (SKB & (SpecialKnownBits::AllBitsEnabled)) {
1868
+ if (TValBop->getOpcode () == Instruction::Xor)
1869
+ Known = KnownBits::makeConstant (APInt (BitWidth, -1 ));
1870
+ }
1871
+ if (TValBop->getOpcode () == Instruction::And)
1872
+ Known = KnownBits::makeConstant (APInt (BitWidth, 0 ));
1873
+ else if ((match (TVal, m_c_Or (m_Specific (X), m_Specific (Y))) &&
1874
+ match (FVal, m_c_Xor (m_Specific (X), m_Specific (Y)))) ||
1875
+ (match (TVal, m_c_Xor (m_Specific (X), m_Specific (Y))) &&
1876
+ match (FVal, m_c_Or (m_Specific (X), m_Specific (Y)))))
1877
+ return IC.replaceInstUsesWith (SI, FVal);
1878
+ } else if (SKB & SpecialKnownBits::AllCommonBits) {
1879
+ if (TValBop->getOpcode () == Instruction::And ||
1880
+ TValBop->getOpcode () == Instruction::Or)
1881
+ if (TValBop->hasOneUse ())
1882
+ return IC.replaceOperand (SI, 1 , X);
1883
+ } else if (SKB & SpecialKnownBits::AllBitsEnabled) {
1884
+ if (TValBop->getOpcode () == Instruction::Or)
1885
+ Known = KnownBits::makeConstant (APInt (BitWidth, -1 ));
1886
+ }
1887
+ } else {
1888
+ KnownBits XKnown, YKnown, Temp;
1889
+ KnownBits TValBop0KB, TValBop1KB;
1890
+ XKnown = IC.computeKnownBits (X, 0 , &SI);
1891
+ IC.computeKnownBitsFromCond (X, ICI, XKnown, 0 , &SI, false );
1892
+ YKnown = IC.computeKnownBits (Y, 0 , &SI);
1893
+ IC.computeKnownBitsFromCond (Y, ICI, YKnown, 0 , &SI, false );
1894
+
1895
+ // Estimate additional KnownBits from the relationship between X and Y
1896
+ CmpInst::Predicate Pred = ICI->getPredicate ();
1897
+ if (Pred == ICmpInst::ICMP_EQ) {
1898
+ if (CmpLHSBop->getOpcode () == Instruction::And) {
1899
+ XKnown.Zero |= ~*C & YKnown.One ;
1900
+ YKnown.Zero |= ~*C & XKnown.One ;
1901
+ }
1902
+ if (CmpLHSBop->getOpcode () == Instruction::Or) {
1903
+ XKnown.One |= *C & YKnown.Zero ;
1904
+ YKnown.One |= *C & XKnown.Zero ;
1905
+ }
1906
+ if (CmpLHSBop->getOpcode () == Instruction::Xor) {
1907
+ XKnown.One |= *C & YKnown.Zero ;
1908
+ XKnown.Zero |= *C & YKnown.One ;
1909
+ YKnown.One |= *C & XKnown.Zero ;
1910
+ YKnown.Zero |= *C & XKnown.One ;
1911
+ XKnown.Zero |= ~*C & YKnown.Zero ;
1912
+ XKnown.One |= ~*C & YKnown.One ;
1913
+ YKnown.Zero |= ~*C & XKnown.Zero ;
1914
+ YKnown.One |= ~*C & XKnown.One ;
1915
+ }
1916
+ }
1917
+
1918
+ auto getTValBopKB = [&](unsigned OpNum) -> KnownBits {
1919
+ unsigned Order = OpNum + 1 ;
1920
+ if (Order == XOrder)
1921
+ return XKnown;
1922
+ else if (Order == YOrder)
1923
+ return YKnown;
1924
+
1925
+ Value *V = TValBop->getOperand (OpNum);
1926
+ KnownBits Known = IC.computeKnownBits (V, 0 , &SI);
1927
+ return Known;
1928
+ };
1929
+ TValBop0KB = getTValBopKB (0 );
1930
+ TValBop1KB = getTValBopKB (1 );
1931
+ Known = analyzeKnownBitsFromAndXorOr (
1932
+ cast<Operator>(TValBop), TValBop0KB, TValBop1KB, 0 ,
1933
+ IC.getSimplifyQuery ().getWithInstruction (&SI));
1934
+ }
1935
+ }
1936
+
1937
+ if (Known.isConstant ()) {
1938
+ auto Const = ConstantInt::get (TValTy, Known.getConstant ());
1939
+ return IC.replaceOperand (SI, 1 , Const);
1940
+ }
1941
+
1942
+ return nullptr ;
1943
+ }
1944
+
1793
1945
// / Visit a SelectInst that has an ICmpInst as its first operand.
1794
1946
Instruction *InstCombinerImpl::foldSelectInstWithICmp (SelectInst &SI,
1795
1947
ICmpInst *ICI) {
@@ -1932,6 +2084,10 @@ Instruction *InstCombinerImpl::foldSelectInstWithICmp(SelectInst &SI,
1932
2084
if (Value *V = foldAbsDiff (ICI, TrueVal, FalseVal, Builder))
1933
2085
return replaceInstUsesWith (SI, V);
1934
2086
2087
+ if (Instruction *NewSel = foldSelectICmpBinOp (SI, ICI, CmpLHS, CmpRHS,
2088
+ TrueVal, FalseVal, *this ))
2089
+ return NewSel;
2090
+
1935
2091
return Changed ? &SI : nullptr ;
1936
2092
}
1937
2093
0 commit comments