Index: llvm/include/llvm/IR/ConstantRange.h =================================================================== --- llvm/include/llvm/IR/ConstantRange.h +++ llvm/include/llvm/IR/ConstantRange.h @@ -277,7 +277,8 @@ /// elements of both sets, but may contain more. For example, [3, 9) union /// [12,15) is [3, 15), which includes 9, 10, and 11, which were not included /// in either set before. - ConstantRange unionWith(const ConstantRange &CR) const; + ConstantRange unionWith(const ConstantRange &CR, + PreferredRangeType Type = Smallest) const; /// Return a new range representing the possible values resulting /// from an application of the specified cast operator to this range. \p Index: llvm/lib/IR/ConstantRange.cpp =================================================================== --- llvm/lib/IR/ConstantRange.cpp +++ llvm/lib/IR/ConstantRange.cpp @@ -593,23 +593,26 @@ return getPreferredRange(*this, CR, Type); } -ConstantRange ConstantRange::unionWith(const ConstantRange &CR) const { +ConstantRange ConstantRange::unionWith(const ConstantRange &CR, + PreferredRangeType Type) const { assert(getBitWidth() == CR.getBitWidth() && "ConstantRange types don't agree!"); if ( isFullSet() || CR.isEmptySet()) return *this; if (CR.isFullSet() || isEmptySet()) return CR; - if (!isUpperWrapped() && CR.isUpperWrapped()) return CR.unionWith(*this); + if (!isUpperWrapped() && CR.isUpperWrapped()) + return CR.unionWith(*this, Type); if (!isUpperWrapped() && !CR.isUpperWrapped()) { - if (CR.Upper.ult(Lower) || Upper.ult(CR.Lower)) { - // If the two ranges are disjoint, find the smaller gap and bridge it. - APInt d1 = CR.Lower - Upper, d2 = Lower - CR.Upper; - if (d1.ult(d2)) - return ConstantRange(Lower, CR.Upper); - return ConstantRange(CR.Lower, Upper); - } + // L---U and L---U : this + // L---U L---U : CR + // result in one of + // L---------U + // -----U L----- + if (CR.Upper.ult(Lower) || Upper.ult(CR.Lower)) + return getPreferredRange( + ConstantRange(Lower, CR.Upper), ConstantRange(CR.Lower, Upper), Type); APInt L = CR.Lower.ult(Lower) ? CR.Lower : Lower; APInt U = (CR.Upper - 1).ugt(Upper - 1) ? CR.Upper : Upper; @@ -633,22 +636,21 @@ // ----U L---- : this // L---U : CR - // - if (Upper.ule(CR.Lower) && CR.Upper.ule(Lower)) { - APInt d1 = CR.Lower - Upper, d2 = Lower - CR.Upper; - if (d1.ult(d2)) - return ConstantRange(Lower, CR.Upper); - return ConstantRange(CR.Lower, Upper); - } + // results in one of + // ----------U L---- + // ----U L---------- + if (Upper.ult(CR.Lower) && CR.Upper.ult(Lower)) + return getPreferredRange( + ConstantRange(Lower, CR.Upper), ConstantRange(CR.Lower, Upper), Type); // ----U L----- : this // L----U : CR - if (Upper.ult(CR.Lower) && Lower.ult(CR.Upper)) + if (Upper.ult(CR.Lower) && Lower.ule(CR.Upper)) return ConstantRange(CR.Lower, Upper); // ------U L---- : this // L-----U : CR - assert(CR.Lower.ult(Upper) && CR.Upper.ult(Lower) && + assert(CR.Lower.ule(Upper) && CR.Upper.ult(Lower) && "ConstantRange::unionWith missed a case with one range wrapped"); return ConstantRange(Lower, CR.Upper); } Index: llvm/unittests/IR/ConstantRangeTest.cpp =================================================================== --- llvm/unittests/IR/ConstantRangeTest.cpp +++ llvm/unittests/IR/ConstantRangeTest.cpp @@ -501,6 +501,17 @@ }); } +TEST_F(ConstantRangeTest, UnionWithExhaustive) { + testBinarySetOperationExhaustive( + [](const ConstantRange &CR1, const ConstantRange &CR2, + ConstantRange::PreferredRangeType Type) { + return CR1.unionWith(CR2, Type); + }, + [](const ConstantRange &CR1, const ConstantRange &CR2, const APInt &N) { + return CR1.contains(N) || CR2.contains(N); + }); +} + TEST_F(ConstantRangeTest, UnionWith) { EXPECT_EQ(Wrap.unionWith(One), ConstantRange(APInt(16, 0xaaa), APInt(16, 0xb)));