|
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