|
35 | 35 | #include "llvm/Analysis/TargetLibraryInfo.h" |
36 | 36 | #include "llvm/Analysis/ValueTracking.h" |
37 | 37 | #include "llvm/Analysis/VectorUtils.h" |
| 38 | +#include "llvm/IR/ConstantFPRange.h" |
38 | 39 | #include "llvm/IR/ConstantRange.h" |
39 | 40 | #include "llvm/IR/DataLayout.h" |
40 | 41 | #include "llvm/IR/Dominators.h" |
@@ -1812,6 +1813,61 @@ static Value *simplifyOrOfICmps(ICmpInst *Op0, ICmpInst *Op1, |
1812 | 1813 | return nullptr; |
1813 | 1814 | } |
1814 | 1815 |
|
| 1816 | +/// Test if a pair of compares with a shared operand and 2 constants has an |
| 1817 | +/// empty set intersection, full set union, or if one compare is a superset of |
| 1818 | +/// the other. |
| 1819 | +static Value *simplifyAndOrOfFCmpsWithConstants(FCmpInst *Cmp0, FCmpInst *Cmp1, |
| 1820 | + bool IsAnd) { |
| 1821 | + // Look for this pattern: {and/or} (fcmp X, C0), (fcmp X, C1)). |
| 1822 | + if (Cmp0->getOperand(0) != Cmp1->getOperand(0)) |
| 1823 | + return nullptr; |
| 1824 | + |
| 1825 | + const APFloat *C0, *C1; |
| 1826 | + if (!match(Cmp0->getOperand(1), m_APFloat(C0)) || |
| 1827 | + !match(Cmp1->getOperand(1), m_APFloat(C1))) |
| 1828 | + return nullptr; |
| 1829 | + |
| 1830 | + auto Range0 = ConstantFPRange::makeExactFCmpRegion(Cmp0->getPredicate(), *C0); |
| 1831 | + auto Range1 = ConstantFPRange::makeExactFCmpRegion(Cmp1->getPredicate(), *C1); |
| 1832 | + |
| 1833 | + if (!Range0 || !Range1) |
| 1834 | + return nullptr; |
| 1835 | + |
| 1836 | + // For and-of-compares, check if the intersection is empty: |
| 1837 | + // (fcmp X, C0) && (fcmp X, C1) --> empty set --> false |
| 1838 | + if (IsAnd && (*Range0).intersectWith(*Range1).isEmptySet()) |
| 1839 | + return getFalse(Cmp0->getType()); |
| 1840 | + |
| 1841 | + // For or-of-compares, check if the union is full: |
| 1842 | + // (fcmp X, C0) || (fcmp X, C1) --> full set --> true |
| 1843 | + // |
| 1844 | + // TODO: `unionWith` is not precise at the moment, so |
| 1845 | + // we can invert the predicate and check: |
| 1846 | + // inv(fcmp X, C0) && inv(fcmp X, C1) --> empty set --> false |
| 1847 | + if (!IsAnd) { |
| 1848 | + auto Range0Inv = ConstantFPRange::makeExactFCmpRegion( |
| 1849 | + FCmpInst::getInversePredicate(Cmp0->getPredicate()), *C0); |
| 1850 | + auto Range1Inv = ConstantFPRange::makeExactFCmpRegion( |
| 1851 | + FCmpInst::getInversePredicate(Cmp1->getPredicate()), *C1); |
| 1852 | + if (Range0Inv && Range1Inv) { |
| 1853 | + if ((*Range0Inv).intersectWith(*Range1Inv).isEmptySet()) |
| 1854 | + return getFalse(Cmp0->getType()); |
| 1855 | + } |
| 1856 | + } |
| 1857 | + |
| 1858 | + // Is one range a superset of the other? |
| 1859 | + // If this is and-of-compares, take the smaller set: |
| 1860 | + // (fcmp ogt X, 4) && (fcmp ogt X, 42) --> fcmp ogt X, 42 |
| 1861 | + // If this is or-of-compares, take the larger set: |
| 1862 | + // (fcmp ogt X, 4) || (fcmp ogt X, 42) --> fcmp ogt X, 4 |
| 1863 | + if ((*Range0).contains(*Range1)) |
| 1864 | + return IsAnd ? Cmp1 : Cmp0; |
| 1865 | + if ((*Range1).contains(*Range0)) |
| 1866 | + return IsAnd ? Cmp0 : Cmp1; |
| 1867 | + |
| 1868 | + return nullptr; |
| 1869 | +} |
| 1870 | + |
1815 | 1871 | static Value *simplifyAndOrOfFCmps(const SimplifyQuery &Q, FCmpInst *LHS, |
1816 | 1872 | FCmpInst *RHS, bool IsAnd) { |
1817 | 1873 | Value *LHS0 = LHS->getOperand(0), *LHS1 = LHS->getOperand(1); |
@@ -1850,34 +1906,8 @@ static Value *simplifyAndOrOfFCmps(const SimplifyQuery &Q, FCmpInst *LHS, |
1850 | 1906 | : ConstantInt::getBool(LHS->getType(), !IsAnd); |
1851 | 1907 | } |
1852 | 1908 |
|
1853 | | - Value *V0; |
1854 | | - const APFloat *V0Op1, *V1Op1; |
1855 | | - // (fcmp olt V0, V0Op1) || (fcmp olt V0, V1Op1) |
1856 | | - // --> fcmp olt V0, max(V0Op1, V1Op1) |
1857 | | - // (fcmp ogt V0, V0Op1) || (fcmp ogt V0, V1Op1) |
1858 | | - // --> fcmp ogt V0, max(V0Op1, V1Op1) |
1859 | | - // |
1860 | | - // (fcmp olt V0, V0Op1) && (fcmp olt V0, V1Op1) |
1861 | | - // --> fcmp olt V0, min(V0Op1, V1Op1) |
1862 | | - // (fcmp ogt V0, V0Op1) && (fcmp ogt V0, V1Op1) |
1863 | | - // --> fcmp ogt V0, min(V0Op1, V1Op1) |
1864 | | - if (match(LHS, m_SpecificFCmp(FCmpInst::FCMP_OLT, m_Value(V0), |
1865 | | - m_APFloat(V0Op1))) && |
1866 | | - match(RHS, m_SpecificFCmp(FCmpInst::FCMP_OLT, m_Specific(V0), |
1867 | | - m_APFloat(V1Op1)))) { |
1868 | | - if (*V0Op1 > *V1Op1) |
1869 | | - return IsAnd ? RHS : LHS; |
1870 | | - if (*V1Op1 > *V0Op1) |
1871 | | - return IsAnd ? LHS : RHS; |
1872 | | - } else if (match(LHS, m_SpecificFCmp(FCmpInst::FCMP_OGT, m_Value(V0), |
1873 | | - m_APFloat(V0Op1))) && |
1874 | | - match(RHS, m_SpecificFCmp(FCmpInst::FCMP_OGT, m_Specific(V0), |
1875 | | - m_APFloat(V1Op1)))) { |
1876 | | - if (*V0Op1 < *V1Op1) |
1877 | | - return IsAnd ? RHS : LHS; |
1878 | | - if (*V1Op1 < *V0Op1) |
1879 | | - return IsAnd ? LHS : RHS; |
1880 | | - } |
| 1909 | + if (auto *V = simplifyAndOrOfFCmpsWithConstants(LHS, RHS, IsAnd)) |
| 1910 | + return V; |
1881 | 1911 |
|
1882 | 1912 | return nullptr; |
1883 | 1913 | } |
|
0 commit comments