Skip to content

Commit 274b243

Browse files
committed
[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.
1 parent 91373bf commit 274b243

File tree

4 files changed

+39
-1
lines changed

4 files changed

+39
-1
lines changed

llvm/include/llvm/IR/ConstantRange.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,11 @@ class LLVM_NODISCARD ConstantRange {
383383
/// treating both this and \p Other as unsigned ranges.
384384
ConstantRange multiply(const ConstantRange &Other) const;
385385

386+
/// Return range of possible values for a signed multiplication of this and
387+
/// \p Other. However, if overflow is possible always return a full range
388+
/// rather than trying to determine a more precise result.
389+
ConstantRange smul_fast(const ConstantRange &Other) const;
390+
386391
/// Return a new range representing the possible values resulting
387392
/// from a signed maximum of a value in this range and a value in \p Other.
388393
ConstantRange smax(const ConstantRange &Other) const;

llvm/lib/Analysis/BasicAliasAnalysis.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1302,7 +1302,7 @@ AliasResult BasicAAResult::aliasGEP(
13021302
computeConstantRange(Var.Val.V, true, &AC, Var.CxtI));
13031303
if (!R.isFullSet() && !R.isEmptySet())
13041304
VarIndexRange = R.sextOrTrunc(Var.Scale.getBitWidth())
1305-
.multiply(ConstantRange(Var.Scale));
1305+
.smul_fast(ConstantRange(Var.Scale));
13061306
} else if (DecompGEP1.VarIndices.size() == 2) {
13071307
// VarIndex = Scale*V0 + (-Scale)*V1.
13081308
// If V0 != V1 then abs(VarIndex) >= abs(Scale).

llvm/lib/IR/ConstantRange.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,6 +1054,25 @@ ConstantRange::multiply(const ConstantRange &Other) const {
10541054
return UR.isSizeStrictlySmallerThan(SR) ? UR : SR;
10551055
}
10561056

1057+
ConstantRange ConstantRange::smul_fast(const ConstantRange &Other) const {
1058+
if (isEmptySet() || Other.isEmptySet())
1059+
return getEmpty();
1060+
1061+
APInt Min = getSignedMin();
1062+
APInt Max = getSignedMax();
1063+
APInt OtherMin = Other.getSignedMin();
1064+
APInt OtherMax = Other.getSignedMax();
1065+
1066+
bool O1, O2, O3, O4;
1067+
auto Muls = {Min.smul_ov(OtherMin, O1), Min.smul_ov(OtherMax, O2),
1068+
Max.smul_ov(OtherMin, O3), Max.smul_ov(OtherMax, O4)};
1069+
if (O1 || O2 || O3 || O4)
1070+
return getFull();
1071+
1072+
auto Compare = [](const APInt &A, const APInt &B) { return A.slt(B); };
1073+
return getNonEmpty(std::min(Muls, Compare), std::max(Muls, Compare) + 1);
1074+
}
1075+
10571076
ConstantRange
10581077
ConstantRange::smax(const ConstantRange &Other) const {
10591078
// X smax Y is: range(smax(X_smin, Y_smin),

llvm/unittests/IR/ConstantRangeTest.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,6 +1081,20 @@ TEST_F(ConstantRangeTest, Multiply) {
10811081
ConstantRange(APInt(8, -2), APInt(8, 1)));
10821082
}
10831083

1084+
TEST_F(ConstantRangeTest, smul_fast) {
1085+
TestBinaryOpExhaustive(
1086+
[](const ConstantRange &CR1, const ConstantRange &CR2) {
1087+
return CR1.smul_fast(CR2);
1088+
},
1089+
[](const APInt &N1, const APInt &N2) {
1090+
return N1 * N2;
1091+
},
1092+
PreferSmallest,
1093+
[](const ConstantRange &, const ConstantRange &) {
1094+
return false; // Check correctness only.
1095+
});
1096+
}
1097+
10841098
TEST_F(ConstantRangeTest, UMax) {
10851099
EXPECT_EQ(Full.umax(Full), Full);
10861100
EXPECT_EQ(Full.umax(Empty), Empty);

0 commit comments

Comments
 (0)