Index: include/llvm/IR/ConstantRange.h =================================================================== --- include/llvm/IR/ConstantRange.h +++ include/llvm/IR/ConstantRange.h @@ -208,8 +208,7 @@ ConstantRange sub(const ConstantRange &Other) const; /// Return a new range representing the possible values resulting - /// from a multiplication of a value in this range and a value in \p Other. - /// TODO: This isn't fully implemented yet. + /// from a multiplication of a value in this range and a value in \p Other. ConstantRange multiply(const ConstantRange &Other) const; /// Return a new range representing the possible values resulting Index: lib/IR/ConstantRange.cpp =================================================================== --- lib/IR/ConstantRange.cpp +++ lib/IR/ConstantRange.cpp @@ -587,6 +587,13 @@ if (isEmptySet() || Other.isEmptySet()) return ConstantRange(getBitWidth(), /*isFullSet=*/false); + // Multiplication is signedness-independent. However different ranges can be + // obtained depending on how the input ranges are treated. These different + // ranges are all conservatively correct, but one might be better than the + // other. We calculate two ranges; one treating the inputs as unsigned + // and the other signed, then return the smallest of these ranges. + + // Unsigned range first. APInt this_min = getUnsignedMin().zext(getBitWidth() * 2); APInt this_max = getUnsignedMax().zext(getBitWidth() * 2); APInt Other_min = Other.getUnsignedMin().zext(getBitWidth() * 2); @@ -594,7 +601,26 @@ ConstantRange Result_zext = ConstantRange(this_min * Other_min, this_max * Other_max + 1); - return Result_zext.truncate(getBitWidth()); + ConstantRange UR = Result_zext.truncate(getBitWidth()); + + // Now the signed range. Because we could be dealing with negative numbers + // here, the lower bound is the smallest of the cartesian product of the + // lower and upper ranges; for example: + // [-1,4) * [-2,3) = min(-1*-2, -1*3, 4*-2, 4*3) = -8. + // Similarly for the upper bound, swapping min for max. + + this_min = getSignedMin().sext(getBitWidth() * 2); + this_max = getSignedMax().sext(getBitWidth() * 2); + Other_min = Other.getSignedMin().sext(getBitWidth() * 2); + Other_max = Other.getSignedMax().sext(getBitWidth() * 2); + + auto L = {this_min * Other_min, this_min * Other_max, + this_max * Other_min, this_max * Other_max}; + auto Compare = [](const APInt &A, const APInt &B) { return A.slt(B); }; + ConstantRange Result_sext(std::min(L, Compare), std::max(L, Compare) + 1); + ConstantRange SR = Result_sext.truncate(getBitWidth()); + + return UR.getSetSize().ult(SR.getSetSize()) ? UR : SR; } ConstantRange Index: unittests/IR/ConstantRangeTest.cpp =================================================================== --- unittests/IR/ConstantRangeTest.cpp +++ unittests/IR/ConstantRangeTest.cpp @@ -400,6 +400,13 @@ EXPECT_EQ(ConstantRange(APInt(4, 1), APInt(4, 6)).multiply( ConstantRange(APInt(4, 6), APInt(4, 2))), ConstantRange(4, /*isFullSet=*/true)); + + EXPECT_EQ(ConstantRange(APInt(8, 254), APInt(8, 0)).multiply( + ConstantRange(APInt(8, 252), APInt(8, 4))), + ConstantRange(APInt(8, 250), APInt(8, 9))); + EXPECT_EQ(ConstantRange(APInt(8, 254), APInt(8, 255)).multiply( + ConstantRange(APInt(8, 2), APInt(8, 4))), + ConstantRange(APInt(8, 250), APInt(8, 253))); } TEST_F(ConstantRangeTest, UMax) {