From 7cf567d46121f4aa8f659554b5e8584cd0fac056 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 23 Jun 2023 12:15:02 +0200 Subject: [PATCH] [ConstantRange] Calculate precise range for multiply by -1 These are pretty common in SCEV, so make sure we get a precise result by mapping to the sub() operation. --- llvm/lib/IR/ConstantRange.cpp | 14 ++++++++++++++ llvm/unittests/IR/ConstantRangeTest.cpp | 20 ++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp index 74cc097..e9344a8 100644 --- a/llvm/lib/IR/ConstantRange.cpp +++ b/llvm/lib/IR/ConstantRange.cpp @@ -1095,6 +1095,20 @@ ConstantRange::multiply(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) return getEmpty(); + if (const APInt *C = getSingleElement()) { + if (C->isOne()) + return Other; + if (C->isAllOnes()) + return ConstantRange(APInt::getZero(getBitWidth())).sub(Other); + } + + if (const APInt *C = Other.getSingleElement()) { + if (C->isOne()) + return *this; + if (C->isAllOnes()) + return ConstantRange(APInt::getZero(getBitWidth())).sub(*this); + } + // 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 diff --git a/llvm/unittests/IR/ConstantRangeTest.cpp b/llvm/unittests/IR/ConstantRangeTest.cpp index f405283..38d1119 100644 --- a/llvm/unittests/IR/ConstantRangeTest.cpp +++ b/llvm/unittests/IR/ConstantRangeTest.cpp @@ -997,6 +997,26 @@ TEST_F(ConstantRangeTest, Multiply) { EXPECT_EQ(ConstantRange(APInt(8, -2)).multiply( ConstantRange(APInt(8, 0), APInt(8, 2))), ConstantRange(APInt(8, -2), APInt(8, 1))); + + // Multiplication by -1 should give precise results. + EXPECT_EQ(ConstantRange(APInt(8, 3), APInt(8, -11)) + .multiply(ConstantRange(APInt(8, -1))), + ConstantRange(APInt(8, 12), APInt(8, -2))); + EXPECT_EQ(ConstantRange(APInt(8, -1)) + .multiply(ConstantRange(APInt(8, 3), APInt(8, -11))), + ConstantRange(APInt(8, 12), APInt(8, -2))); + + TestBinaryOpExhaustive( + [](const ConstantRange &CR1, const ConstantRange &CR2) { + return CR1.multiply(CR2); + }, + [](const APInt &N1, const APInt &N2) { + return N1 * N2; + }, + PreferSmallest, + [](const ConstantRange &, const ConstantRange &) { + return false; // Check correctness only. + }); } TEST_F(ConstantRangeTest, smul_fast) { -- 2.7.4