summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2021-10-16 21:02:04 +0200
committerNikita Popov <nikita.ppv@gmail.com>2021-10-17 16:41:49 +0200
commit274b2439f8392796e04e366ce5ff47434bd077e1 (patch)
tree25777a8a6bd5cad799642c036ce758d297305b63
parent91373bf12ec66591addf56b9f447ec9befd6ddae (diff)
downloadllvm-274b2439f8392796e04e366ce5ff47434bd077e1.tar.gz
[ConstantRange] Add fast signed multiply
The multiply() implementation is very slow -- it performs six multiplications in double the bitwidth, which means that it will typically work on allocated APInts and bypass fast-path implementations. Add an additional implementation that doesn't try to produce anything better than a full range if overflow is possible. At least for the BasicAA use-case, we really don't care about more precise modeling of overflow behavior. The current use of multiply() is fine while the implementation is limited to a single index, but extending it to the multiple-index case makes the compile-time impact untenable.
-rw-r--r--llvm/include/llvm/IR/ConstantRange.h5
-rw-r--r--llvm/lib/Analysis/BasicAliasAnalysis.cpp2
-rw-r--r--llvm/lib/IR/ConstantRange.cpp19
-rw-r--r--llvm/unittests/IR/ConstantRangeTest.cpp14
4 files changed, 39 insertions, 1 deletions
diff --git a/llvm/include/llvm/IR/ConstantRange.h b/llvm/include/llvm/IR/ConstantRange.h
index 44b8c395c89e..e464d29afdac 100644
--- a/llvm/include/llvm/IR/ConstantRange.h
+++ b/llvm/include/llvm/IR/ConstantRange.h
@@ -383,6 +383,11 @@ public:
/// treating both this and \p Other as unsigned ranges.
ConstantRange multiply(const ConstantRange &Other) const;
+ /// Return range of possible values for a signed multiplication of this and
+ /// \p Other. However, if overflow is possible always return a full range
+ /// rather than trying to determine a more precise result.
+ ConstantRange smul_fast(const ConstantRange &Other) const;
+
/// Return a new range representing the possible values resulting
/// from a signed maximum of a value in this range and a value in \p Other.
ConstantRange smax(const ConstantRange &Other) const;
diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
index 3129da27053f..865db9f79832 100644
--- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
@@ -1302,7 +1302,7 @@ AliasResult BasicAAResult::aliasGEP(
computeConstantRange(Var.Val.V, true, &AC, Var.CxtI));
if (!R.isFullSet() && !R.isEmptySet())
VarIndexRange = R.sextOrTrunc(Var.Scale.getBitWidth())
- .multiply(ConstantRange(Var.Scale));
+ .smul_fast(ConstantRange(Var.Scale));
} else if (DecompGEP1.VarIndices.size() == 2) {
// VarIndex = Scale*V0 + (-Scale)*V1.
// If V0 != V1 then abs(VarIndex) >= abs(Scale).
diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp
index d8b4262a8114..6877a5d278ac 100644
--- a/llvm/lib/IR/ConstantRange.cpp
+++ b/llvm/lib/IR/ConstantRange.cpp
@@ -1054,6 +1054,25 @@ ConstantRange::multiply(const ConstantRange &Other) const {
return UR.isSizeStrictlySmallerThan(SR) ? UR : SR;
}
+ConstantRange ConstantRange::smul_fast(const ConstantRange &Other) const {
+ if (isEmptySet() || Other.isEmptySet())
+ return getEmpty();
+
+ APInt Min = getSignedMin();
+ APInt Max = getSignedMax();
+ APInt OtherMin = Other.getSignedMin();
+ APInt OtherMax = Other.getSignedMax();
+
+ bool O1, O2, O3, O4;
+ auto Muls = {Min.smul_ov(OtherMin, O1), Min.smul_ov(OtherMax, O2),
+ Max.smul_ov(OtherMin, O3), Max.smul_ov(OtherMax, O4)};
+ if (O1 || O2 || O3 || O4)
+ return getFull();
+
+ auto Compare = [](const APInt &A, const APInt &B) { return A.slt(B); };
+ return getNonEmpty(std::min(Muls, Compare), std::max(Muls, Compare) + 1);
+}
+
ConstantRange
ConstantRange::smax(const ConstantRange &Other) const {
// X smax Y is: range(smax(X_smin, Y_smin),
diff --git a/llvm/unittests/IR/ConstantRangeTest.cpp b/llvm/unittests/IR/ConstantRangeTest.cpp
index bc78869f9c54..21533652b11c 100644
--- a/llvm/unittests/IR/ConstantRangeTest.cpp
+++ b/llvm/unittests/IR/ConstantRangeTest.cpp
@@ -1081,6 +1081,20 @@ TEST_F(ConstantRangeTest, Multiply) {
ConstantRange(APInt(8, -2), APInt(8, 1)));
}
+TEST_F(ConstantRangeTest, smul_fast) {
+ TestBinaryOpExhaustive(
+ [](const ConstantRange &CR1, const ConstantRange &CR2) {
+ return CR1.smul_fast(CR2);
+ },
+ [](const APInt &N1, const APInt &N2) {
+ return N1 * N2;
+ },
+ PreferSmallest,
+ [](const ConstantRange &, const ConstantRange &) {
+ return false; // Check correctness only.
+ });
+}
+
TEST_F(ConstantRangeTest, UMax) {
EXPECT_EQ(Full.umax(Full), Full);
EXPECT_EQ(Full.umax(Empty), Empty);