forked from OSchip/llvm-project
[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.
This commit is contained in:
parent
91373bf12e
commit
274b2439f8
|
@ -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;
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue