diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2021-10-16 21:02:04 +0200 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2021-10-17 16:41:49 +0200 |
commit | 274b2439f8392796e04e366ce5ff47434bd077e1 (patch) | |
tree | 25777a8a6bd5cad799642c036ce758d297305b63 /llvm/lib/IR/ConstantRange.cpp | |
parent | 91373bf12ec66591addf56b9f447ec9befd6ddae (diff) | |
download | llvm-274b2439f8392796e04e366ce5ff47434bd077e1.zip llvm-274b2439f8392796e04e366ce5ff47434bd077e1.tar.gz llvm-274b2439f8392796e04e366ce5ff47434bd077e1.tar.bz2 |
[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.
Diffstat (limited to 'llvm/lib/IR/ConstantRange.cpp')
-rw-r--r-- | llvm/lib/IR/ConstantRange.cpp | 19 |
1 files changed, 19 insertions, 0 deletions
diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp index d8b4262..6877a5d 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), |