Generalized division via multiplication.
We can now compute the magic numbers for all combinations of 32bit and 64bit (un)signed multiplications. R=bmeurer@chromium.org Review URL: https://codereview.chromium.org/532003004 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23730 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
2a40210a7b
commit
051972d240
2
BUILD.gn
2
BUILD.gn
@ -1171,6 +1171,8 @@ source_set("v8_libbase") {
|
||||
"src/base/build_config.h",
|
||||
"src/base/cpu.cc",
|
||||
"src/base/cpu.h",
|
||||
"src/base/division-by-constant.cc",
|
||||
"src/base/division-by-constant.h",
|
||||
"src/base/flags.h",
|
||||
"src/base/lazy-instance.h",
|
||||
"src/base/logging.cc",
|
||||
|
@ -9,6 +9,7 @@
|
||||
#if V8_TARGET_ARCH_ARM
|
||||
|
||||
#include "src/base/bits.h"
|
||||
#include "src/base/division-by-constant.h"
|
||||
#include "src/bootstrapper.h"
|
||||
#include "src/codegen.h"
|
||||
#include "src/cpu-profiler.h"
|
||||
@ -4093,16 +4094,18 @@ void MacroAssembler::TruncatingDiv(Register result,
|
||||
DCHECK(!dividend.is(result));
|
||||
DCHECK(!dividend.is(ip));
|
||||
DCHECK(!result.is(ip));
|
||||
MultiplierAndShift ms(divisor);
|
||||
mov(ip, Operand(ms.multiplier()));
|
||||
base::MagicNumbersForDivision<uint32_t> mag =
|
||||
base::SignedDivisionByConstant(static_cast<uint32_t>(divisor));
|
||||
mov(ip, Operand(mag.multiplier));
|
||||
smull(ip, result, dividend, ip);
|
||||
if (divisor > 0 && ms.multiplier() < 0) {
|
||||
bool neg = (mag.multiplier & (static_cast<uint32_t>(1) << 31)) != 0;
|
||||
if (divisor > 0 && neg) {
|
||||
add(result, result, Operand(dividend));
|
||||
}
|
||||
if (divisor < 0 && ms.multiplier() > 0) {
|
||||
if (divisor < 0 && !neg && mag.multiplier > 0) {
|
||||
sub(result, result, Operand(dividend));
|
||||
}
|
||||
if (ms.shift() > 0) mov(result, Operand(result, ASR, ms.shift()));
|
||||
if (mag.shift > 0) mov(result, Operand(result, ASR, mag.shift));
|
||||
add(result, result, Operand(dividend, LSR, 31));
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#if V8_TARGET_ARCH_ARM64
|
||||
|
||||
#include "src/base/bits.h"
|
||||
#include "src/base/division-by-constant.h"
|
||||
#include "src/bootstrapper.h"
|
||||
#include "src/codegen.h"
|
||||
#include "src/cpu-profiler.h"
|
||||
@ -5332,13 +5333,15 @@ void MacroAssembler::TruncatingDiv(Register result,
|
||||
int32_t divisor) {
|
||||
DCHECK(!AreAliased(result, dividend));
|
||||
DCHECK(result.Is32Bits() && dividend.Is32Bits());
|
||||
MultiplierAndShift ms(divisor);
|
||||
Mov(result, ms.multiplier());
|
||||
base::MagicNumbersForDivision<uint32_t> mag =
|
||||
base::SignedDivisionByConstant(static_cast<uint32_t>(divisor));
|
||||
Mov(result, mag.multiplier);
|
||||
Smull(result.X(), dividend, result);
|
||||
Asr(result.X(), result.X(), 32);
|
||||
if (divisor > 0 && ms.multiplier() < 0) Add(result, result, dividend);
|
||||
if (divisor < 0 && ms.multiplier() > 0) Sub(result, result, dividend);
|
||||
if (ms.shift() > 0) Asr(result, result, ms.shift());
|
||||
bool neg = (mag.multiplier & (static_cast<uint32_t>(1) << 31)) != 0;
|
||||
if (divisor > 0 && neg) Add(result, result, dividend);
|
||||
if (divisor < 0 && !neg && mag.multiplier > 0) Sub(result, result, dividend);
|
||||
if (mag.shift > 0) Asr(result, result, mag.shift);
|
||||
Add(result, result, Operand(dividend, LSR, 31));
|
||||
}
|
||||
|
||||
|
@ -1571,38 +1571,4 @@ bool PositionsRecorder::WriteRecordedPositions() {
|
||||
return written;
|
||||
}
|
||||
|
||||
|
||||
MultiplierAndShift::MultiplierAndShift(int32_t d) {
|
||||
DCHECK(d <= -2 || 2 <= d);
|
||||
const uint32_t two31 = 0x80000000;
|
||||
uint32_t ad = Abs(d);
|
||||
uint32_t t = two31 + (uint32_t(d) >> 31);
|
||||
uint32_t anc = t - 1 - t % ad; // Absolute value of nc.
|
||||
int32_t p = 31; // Init. p.
|
||||
uint32_t q1 = two31 / anc; // Init. q1 = 2**p/|nc|.
|
||||
uint32_t r1 = two31 - q1 * anc; // Init. r1 = rem(2**p, |nc|).
|
||||
uint32_t q2 = two31 / ad; // Init. q2 = 2**p/|d|.
|
||||
uint32_t r2 = two31 - q2 * ad; // Init. r2 = rem(2**p, |d|).
|
||||
uint32_t delta;
|
||||
do {
|
||||
p++;
|
||||
q1 *= 2; // Update q1 = 2**p/|nc|.
|
||||
r1 *= 2; // Update r1 = rem(2**p, |nc|).
|
||||
if (r1 >= anc) { // Must be an unsigned comparison here.
|
||||
q1++;
|
||||
r1 = r1 - anc;
|
||||
}
|
||||
q2 *= 2; // Update q2 = 2**p/|d|.
|
||||
r2 *= 2; // Update r2 = rem(2**p, |d|).
|
||||
if (r2 >= ad) { // Must be an unsigned comparison here.
|
||||
q2++;
|
||||
r2 = r2 - ad;
|
||||
}
|
||||
delta = ad - r2;
|
||||
} while (q1 < delta || (q1 == delta && r1 == 0));
|
||||
int32_t mul = static_cast<int32_t>(q2 + 1);
|
||||
multiplier_ = (d < 0) ? -mul : mul;
|
||||
shift_ = p - 32;
|
||||
}
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
@ -1110,20 +1110,6 @@ class NullCallWrapper : public CallWrapper {
|
||||
};
|
||||
|
||||
|
||||
// The multiplier and shift for signed division via multiplication, see Warren's
|
||||
// "Hacker's Delight", chapter 10.
|
||||
class MultiplierAndShift {
|
||||
public:
|
||||
explicit MultiplierAndShift(int32_t d);
|
||||
int32_t multiplier() const { return multiplier_; }
|
||||
int32_t shift() const { return shift_; }
|
||||
|
||||
private:
|
||||
int32_t multiplier_;
|
||||
int32_t shift_;
|
||||
};
|
||||
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
||||
#endif // V8_ASSEMBLER_H_
|
||||
|
@ -22,6 +22,7 @@
|
||||
'sources': [ ### gcmole(all) ###
|
||||
'bits-unittest.cc',
|
||||
'cpu-unittest.cc',
|
||||
'division-by-constant-unittest.cc',
|
||||
'flags-unittest.cc',
|
||||
'platform/condition-variable-unittest.cc',
|
||||
'platform/mutex-unittest.cc',
|
||||
|
132
src/base/division-by-constant-unittest.cc
Normal file
132
src/base/division-by-constant-unittest.cc
Normal file
@ -0,0 +1,132 @@
|
||||
// Copyright 2014 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Check all examples from table 10-1 of "Hacker's Delight".
|
||||
|
||||
#include "src/base/division-by-constant.h"
|
||||
|
||||
#include <ostream> // NOLINT
|
||||
|
||||
#include "testing/gtest-support.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace base {
|
||||
|
||||
template <class T>
|
||||
std::ostream& operator<<(std::ostream& os,
|
||||
const MagicNumbersForDivision<T>& mag) {
|
||||
return os << "{ multiplier: " << mag.multiplier << ", shift: " << mag.shift
|
||||
<< ", add: " << mag.add << " }";
|
||||
}
|
||||
|
||||
|
||||
// Some abbreviations...
|
||||
|
||||
typedef MagicNumbersForDivision<uint32_t> M32;
|
||||
typedef MagicNumbersForDivision<uint64_t> M64;
|
||||
|
||||
|
||||
static M32 s32(int32_t d) {
|
||||
return SignedDivisionByConstant<uint32_t>(static_cast<uint32_t>(d));
|
||||
}
|
||||
|
||||
|
||||
static M64 s64(int64_t d) {
|
||||
return SignedDivisionByConstant<uint64_t>(static_cast<uint64_t>(d));
|
||||
}
|
||||
|
||||
|
||||
static M32 u32(uint32_t d) { return UnsignedDivisionByConstant<uint32_t>(d); }
|
||||
static M64 u64(uint64_t d) { return UnsignedDivisionByConstant<uint64_t>(d); }
|
||||
|
||||
|
||||
TEST(DivisionByConstant, Signed32) {
|
||||
EXPECT_EQ(M32(0x99999999U, 1, false), s32(-5));
|
||||
EXPECT_EQ(M32(0x55555555U, 1, false), s32(-3));
|
||||
int32_t d = -1;
|
||||
for (unsigned k = 1; k <= 32 - 1; ++k) {
|
||||
d *= 2;
|
||||
EXPECT_EQ(M32(0x7FFFFFFFU, k - 1, false), s32(d));
|
||||
}
|
||||
for (unsigned k = 1; k <= 32 - 2; ++k) {
|
||||
EXPECT_EQ(M32(0x80000001U, k - 1, false), s32(1 << k));
|
||||
}
|
||||
EXPECT_EQ(M32(0x55555556U, 0, false), s32(3));
|
||||
EXPECT_EQ(M32(0x66666667U, 1, false), s32(5));
|
||||
EXPECT_EQ(M32(0x2AAAAAABU, 0, false), s32(6));
|
||||
EXPECT_EQ(M32(0x92492493U, 2, false), s32(7));
|
||||
EXPECT_EQ(M32(0x38E38E39U, 1, false), s32(9));
|
||||
EXPECT_EQ(M32(0x66666667U, 2, false), s32(10));
|
||||
EXPECT_EQ(M32(0x2E8BA2E9U, 1, false), s32(11));
|
||||
EXPECT_EQ(M32(0x2AAAAAABU, 1, false), s32(12));
|
||||
EXPECT_EQ(M32(0x51EB851FU, 3, false), s32(25));
|
||||
EXPECT_EQ(M32(0x10624DD3U, 3, false), s32(125));
|
||||
EXPECT_EQ(M32(0x68DB8BADU, 8, false), s32(625));
|
||||
}
|
||||
|
||||
|
||||
TEST(DivisionByConstant, Unsigned32) {
|
||||
EXPECT_EQ(M32(0x00000000U, 0, true), u32(1));
|
||||
for (unsigned k = 1; k <= 30; ++k) {
|
||||
EXPECT_EQ(M32(1U << (32 - k), 0, false), u32(1U << k));
|
||||
}
|
||||
EXPECT_EQ(M32(0xAAAAAAABU, 1, false), u32(3));
|
||||
EXPECT_EQ(M32(0xCCCCCCCDU, 2, false), u32(5));
|
||||
EXPECT_EQ(M32(0xAAAAAAABU, 2, false), u32(6));
|
||||
EXPECT_EQ(M32(0x24924925U, 3, true), u32(7));
|
||||
EXPECT_EQ(M32(0x38E38E39U, 1, false), u32(9));
|
||||
EXPECT_EQ(M32(0xCCCCCCCDU, 3, false), u32(10));
|
||||
EXPECT_EQ(M32(0xBA2E8BA3U, 3, false), u32(11));
|
||||
EXPECT_EQ(M32(0xAAAAAAABU, 3, false), u32(12));
|
||||
EXPECT_EQ(M32(0x51EB851FU, 3, false), u32(25));
|
||||
EXPECT_EQ(M32(0x10624DD3U, 3, false), u32(125));
|
||||
EXPECT_EQ(M32(0xD1B71759U, 9, false), u32(625));
|
||||
}
|
||||
|
||||
|
||||
TEST(DivisionByConstant, Signed64) {
|
||||
EXPECT_EQ(M64(0x9999999999999999ULL, 1, false), s64(-5));
|
||||
EXPECT_EQ(M64(0x5555555555555555ULL, 1, false), s64(-3));
|
||||
int64_t d = -1;
|
||||
for (unsigned k = 1; k <= 64 - 1; ++k) {
|
||||
d *= 2;
|
||||
EXPECT_EQ(M64(0x7FFFFFFFFFFFFFFFULL, k - 1, false), s64(d));
|
||||
}
|
||||
for (unsigned k = 1; k <= 64 - 2; ++k) {
|
||||
EXPECT_EQ(M64(0x8000000000000001ULL, k - 1, false), s64(1LL << k));
|
||||
}
|
||||
EXPECT_EQ(M64(0x5555555555555556ULL, 0, false), s64(3));
|
||||
EXPECT_EQ(M64(0x6666666666666667ULL, 1, false), s64(5));
|
||||
EXPECT_EQ(M64(0x2AAAAAAAAAAAAAABULL, 0, false), s64(6));
|
||||
EXPECT_EQ(M64(0x4924924924924925ULL, 1, false), s64(7));
|
||||
EXPECT_EQ(M64(0x1C71C71C71C71C72ULL, 0, false), s64(9));
|
||||
EXPECT_EQ(M64(0x6666666666666667ULL, 2, false), s64(10));
|
||||
EXPECT_EQ(M64(0x2E8BA2E8BA2E8BA3ULL, 1, false), s64(11));
|
||||
EXPECT_EQ(M64(0x2AAAAAAAAAAAAAABULL, 1, false), s64(12));
|
||||
EXPECT_EQ(M64(0xA3D70A3D70A3D70BULL, 4, false), s64(25));
|
||||
EXPECT_EQ(M64(0x20C49BA5E353F7CFULL, 4, false), s64(125));
|
||||
EXPECT_EQ(M64(0x346DC5D63886594BULL, 7, false), s64(625));
|
||||
}
|
||||
|
||||
|
||||
TEST(DivisionByConstant, Unsigned64) {
|
||||
EXPECT_EQ(M64(0x0000000000000000ULL, 0, true), u64(1));
|
||||
for (unsigned k = 1; k <= 64 - 2; ++k) {
|
||||
EXPECT_EQ(M64(1ULL << (64 - k), 0, false), u64(1ULL << k));
|
||||
}
|
||||
EXPECT_EQ(M64(0xAAAAAAAAAAAAAAABULL, 1, false), u64(3));
|
||||
EXPECT_EQ(M64(0xCCCCCCCCCCCCCCCDULL, 2, false), u64(5));
|
||||
EXPECT_EQ(M64(0xAAAAAAAAAAAAAAABULL, 2, false), u64(6));
|
||||
EXPECT_EQ(M64(0x2492492492492493ULL, 3, true), u64(7));
|
||||
EXPECT_EQ(M64(0xE38E38E38E38E38FULL, 3, false), u64(9));
|
||||
EXPECT_EQ(M64(0xCCCCCCCCCCCCCCCDULL, 3, false), u64(10));
|
||||
EXPECT_EQ(M64(0x2E8BA2E8BA2E8BA3ULL, 1, false), u64(11));
|
||||
EXPECT_EQ(M64(0xAAAAAAAAAAAAAAABULL, 3, false), u64(12));
|
||||
EXPECT_EQ(M64(0x47AE147AE147AE15ULL, 5, true), u64(25));
|
||||
EXPECT_EQ(M64(0x0624DD2F1A9FBE77ULL, 7, true), u64(125));
|
||||
EXPECT_EQ(M64(0x346DC5D63886594BULL, 7, false), u64(625));
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
} // namespace v8
|
115
src/base/division-by-constant.cc
Normal file
115
src/base/division-by-constant.cc
Normal file
@ -0,0 +1,115 @@
|
||||
// Copyright 2014 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/base/division-by-constant.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "src/base/logging.h"
|
||||
#include "src/base/macros.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace base {
|
||||
|
||||
template <class T>
|
||||
bool MagicNumbersForDivision<T>::operator==(
|
||||
const MagicNumbersForDivision& rhs) const {
|
||||
return multiplier == rhs.multiplier && shift == rhs.shift && add == rhs.add;
|
||||
}
|
||||
|
||||
|
||||
template <class T>
|
||||
MagicNumbersForDivision<T> SignedDivisionByConstant(T d) {
|
||||
STATIC_ASSERT(static_cast<T>(0) < static_cast<T>(-1));
|
||||
DCHECK(d != static_cast<T>(-1) && d != 0 && d != 1);
|
||||
const unsigned bits = static_cast<unsigned>(sizeof(T)) * 8;
|
||||
const T min = (static_cast<T>(1) << (bits - 1));
|
||||
const bool neg = (min & d) != 0;
|
||||
const T ad = neg ? (0 - d) : d;
|
||||
const T t = min + (d >> (bits - 1));
|
||||
const T anc = t - 1 - t % ad; // Absolute value of nc
|
||||
unsigned p = bits - 1; // Init. p.
|
||||
T q1 = min / anc; // Init. q1 = 2**p/|nc|.
|
||||
T r1 = min - q1 * anc; // Init. r1 = rem(2**p, |nc|).
|
||||
T q2 = min / ad; // Init. q2 = 2**p/|d|.
|
||||
T r2 = min - q2 * ad; // Init. r2 = rem(2**p, |d|).
|
||||
T delta;
|
||||
do {
|
||||
p = p + 1;
|
||||
q1 = 2 * q1; // Update q1 = 2**p/|nc|.
|
||||
r1 = 2 * r1; // Update r1 = rem(2**p, |nc|).
|
||||
if (r1 >= anc) { // Must be an unsigned comparison here.
|
||||
q1 = q1 + 1;
|
||||
r1 = r1 - anc;
|
||||
}
|
||||
q2 = 2 * q2; // Update q2 = 2**p/|d|.
|
||||
r2 = 2 * r2; // Update r2 = rem(2**p, |d|).
|
||||
if (r2 >= ad) { // Must be an unsigned comparison here.
|
||||
q2 = q2 + 1;
|
||||
r2 = r2 - ad;
|
||||
}
|
||||
delta = ad - r2;
|
||||
} while (q1 < delta || (q1 == delta && r1 == 0));
|
||||
T mul = q2 + 1;
|
||||
return {neg ? (0 - mul) : mul, p - bits, false};
|
||||
}
|
||||
|
||||
|
||||
template <class T>
|
||||
MagicNumbersForDivision<T> UnsignedDivisionByConstant(T d,
|
||||
unsigned leading_zeros) {
|
||||
STATIC_ASSERT(static_cast<T>(0) < static_cast<T>(-1));
|
||||
DCHECK(d != 0);
|
||||
const unsigned bits = static_cast<unsigned>(sizeof(T)) * 8;
|
||||
const T ones = ~static_cast<T>(0) >> leading_zeros;
|
||||
const T min = static_cast<T>(1) << (bits - 1);
|
||||
const T max = ~static_cast<T>(0) >> 1;
|
||||
const T nc = ones - (ones - d) % d;
|
||||
bool a = false; // Init. "add" indicator.
|
||||
unsigned p = bits - 1; // Init. p.
|
||||
T q1 = min / nc; // Init. q1 = 2**p/nc
|
||||
T r1 = min - q1 * nc; // Init. r1 = rem(2**p,nc)
|
||||
T q2 = max / d; // Init. q2 = (2**p - 1)/d.
|
||||
T r2 = max - q2 * d; // Init. r2 = rem(2**p - 1, d).
|
||||
T delta;
|
||||
do {
|
||||
p = p + 1;
|
||||
if (r1 >= nc - r1) {
|
||||
q1 = 2 * q1 + 1;
|
||||
r1 = 2 * r1 - nc;
|
||||
} else {
|
||||
q1 = 2 * q1;
|
||||
r1 = 2 * r1;
|
||||
}
|
||||
if (r2 + 1 >= d - r2) {
|
||||
if (q2 >= max) a = true;
|
||||
q2 = 2 * q2 + 1;
|
||||
r2 = 2 * r2 + 1 - d;
|
||||
} else {
|
||||
if (q2 >= min) a = true;
|
||||
q2 = 2 * q2;
|
||||
r2 = 2 * r2 + 1;
|
||||
}
|
||||
delta = d - 1 - r2;
|
||||
} while (p < bits * 2 && (q1 < delta || (q1 == delta && r1 == 0)));
|
||||
return {q2 + 1, p - bits, a};
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Instantiations.
|
||||
|
||||
template struct MagicNumbersForDivision<uint32_t>;
|
||||
template struct MagicNumbersForDivision<uint64_t>;
|
||||
|
||||
template MagicNumbersForDivision<uint32_t> SignedDivisionByConstant(uint32_t d);
|
||||
template MagicNumbersForDivision<uint64_t> SignedDivisionByConstant(uint64_t d);
|
||||
|
||||
template MagicNumbersForDivision<uint32_t> UnsignedDivisionByConstant(
|
||||
uint32_t d, unsigned leading_zeros);
|
||||
template MagicNumbersForDivision<uint64_t> UnsignedDivisionByConstant(
|
||||
uint64_t d, unsigned leading_zeros);
|
||||
|
||||
} // namespace base
|
||||
} // namespace v8
|
45
src/base/division-by-constant.h
Normal file
45
src/base/division-by-constant.h
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright 2014 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef V8_BASE_DIVISION_BY_CONSTANT_H_
|
||||
#define V8_BASE_DIVISION_BY_CONSTANT_H_
|
||||
|
||||
namespace v8 {
|
||||
namespace base {
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// The magic numbers for division via multiplication, see Warren's "Hacker's
|
||||
// Delight", chapter 10. The template parameter must be one of the unsigned
|
||||
// integral types.
|
||||
template <class T>
|
||||
struct MagicNumbersForDivision {
|
||||
MagicNumbersForDivision(T m, unsigned s, bool a)
|
||||
: multiplier(m), shift(s), add(a) {}
|
||||
bool operator==(const MagicNumbersForDivision& rhs) const;
|
||||
|
||||
T multiplier;
|
||||
unsigned shift;
|
||||
bool add;
|
||||
};
|
||||
|
||||
|
||||
// Calculate the multiplier and shift for signed division via multiplication.
|
||||
// The divisor must not be -1, 0 or 1 when interpreted as a signed value.
|
||||
template <class T>
|
||||
MagicNumbersForDivision<T> SignedDivisionByConstant(T d);
|
||||
|
||||
|
||||
// Calculate the multiplier and shift for unsigned division via multiplication,
|
||||
// see Warren's "Hacker's Delight", chapter 10. The divisor must not be 0 and
|
||||
// leading_zeros can be used to speed up the calculation if the given number of
|
||||
// upper bits of the dividend value are known to be zero.
|
||||
template <class T>
|
||||
MagicNumbersForDivision<T> UnsignedDivisionByConstant(
|
||||
T d, unsigned leading_zeros = 0);
|
||||
|
||||
} // namespace base
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_BASE_DIVISION_BY_CONSTANT_H_
|
@ -7,6 +7,7 @@
|
||||
#if V8_TARGET_ARCH_IA32
|
||||
|
||||
#include "src/base/bits.h"
|
||||
#include "src/base/division-by-constant.h"
|
||||
#include "src/bootstrapper.h"
|
||||
#include "src/codegen.h"
|
||||
#include "src/cpu-profiler.h"
|
||||
@ -3423,12 +3424,14 @@ void MacroAssembler::JumpIfDictionaryInPrototypeChain(
|
||||
void MacroAssembler::TruncatingDiv(Register dividend, int32_t divisor) {
|
||||
DCHECK(!dividend.is(eax));
|
||||
DCHECK(!dividend.is(edx));
|
||||
MultiplierAndShift ms(divisor);
|
||||
mov(eax, Immediate(ms.multiplier()));
|
||||
base::MagicNumbersForDivision<uint32_t> mag =
|
||||
base::SignedDivisionByConstant(static_cast<uint32_t>(divisor));
|
||||
mov(eax, Immediate(mag.multiplier));
|
||||
imul(dividend);
|
||||
if (divisor > 0 && ms.multiplier() < 0) add(edx, dividend);
|
||||
if (divisor < 0 && ms.multiplier() > 0) sub(edx, dividend);
|
||||
if (ms.shift() > 0) sar(edx, ms.shift());
|
||||
bool neg = (mag.multiplier & (static_cast<uint32_t>(1) << 31)) != 0;
|
||||
if (divisor > 0 && neg) add(edx, dividend);
|
||||
if (divisor < 0 && !neg && mag.multiplier > 0) sub(edx, dividend);
|
||||
if (mag.shift > 0) sar(edx, mag.shift);
|
||||
mov(eax, dividend);
|
||||
shr(eax, 31);
|
||||
add(edx, eax);
|
||||
|
@ -9,6 +9,7 @@
|
||||
#if V8_TARGET_ARCH_MIPS
|
||||
|
||||
#include "src/base/bits.h"
|
||||
#include "src/base/division-by-constant.h"
|
||||
#include "src/bootstrapper.h"
|
||||
#include "src/codegen.h"
|
||||
#include "src/cpu-profiler.h"
|
||||
@ -6106,16 +6107,18 @@ void MacroAssembler::TruncatingDiv(Register result,
|
||||
DCHECK(!dividend.is(result));
|
||||
DCHECK(!dividend.is(at));
|
||||
DCHECK(!result.is(at));
|
||||
MultiplierAndShift ms(divisor);
|
||||
li(at, Operand(ms.multiplier()));
|
||||
base::MagicNumbersForDivision<uint32_t> mag =
|
||||
base::SignedDivisionByConstant(static_cast<uint32_t>(divisor));
|
||||
li(at, Operand(mag.multiplier));
|
||||
Mulh(result, dividend, Operand(at));
|
||||
if (divisor > 0 && ms.multiplier() < 0) {
|
||||
bool neg = (mag.multiplier & (static_cast<uint32_t>(1) << 31)) != 0;
|
||||
if (divisor > 0 && neg) {
|
||||
Addu(result, result, Operand(dividend));
|
||||
}
|
||||
if (divisor < 0 && ms.multiplier() > 0) {
|
||||
if (divisor < 0 && !neg && mag.multiplier > 0) {
|
||||
Subu(result, result, Operand(dividend));
|
||||
}
|
||||
if (ms.shift() > 0) sra(result, result, ms.shift());
|
||||
if (mag.shift > 0) sra(result, result, mag.shift);
|
||||
srl(at, dividend, 31);
|
||||
Addu(result, result, Operand(at));
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
#if V8_TARGET_ARCH_X64
|
||||
|
||||
#include "src/base/bits.h"
|
||||
#include "src/base/division-by-constant.h"
|
||||
#include "src/bootstrapper.h"
|
||||
#include "src/codegen.h"
|
||||
#include "src/cpu-profiler.h"
|
||||
@ -5368,12 +5369,14 @@ void MacroAssembler::JumpIfDictionaryInPrototypeChain(
|
||||
void MacroAssembler::TruncatingDiv(Register dividend, int32_t divisor) {
|
||||
DCHECK(!dividend.is(rax));
|
||||
DCHECK(!dividend.is(rdx));
|
||||
MultiplierAndShift ms(divisor);
|
||||
movl(rax, Immediate(ms.multiplier()));
|
||||
base::MagicNumbersForDivision<uint32_t> mag =
|
||||
base::SignedDivisionByConstant(static_cast<uint32_t>(divisor));
|
||||
movl(rax, Immediate(mag.multiplier));
|
||||
imull(dividend);
|
||||
if (divisor > 0 && ms.multiplier() < 0) addl(rdx, dividend);
|
||||
if (divisor < 0 && ms.multiplier() > 0) subl(rdx, dividend);
|
||||
if (ms.shift() > 0) sarl(rdx, Immediate(ms.shift()));
|
||||
bool neg = (mag.multiplier & (static_cast<uint32_t>(1) << 31)) != 0;
|
||||
if (divisor > 0 && neg) addl(rdx, dividend);
|
||||
if (divisor < 0 && !neg && mag.multiplier > 0) subl(rdx, dividend);
|
||||
if (mag.shift > 0) sarl(rdx, Immediate(mag.shift));
|
||||
movl(rax, dividend);
|
||||
shrl(rax, Immediate(31));
|
||||
addl(rdx, rax);
|
||||
|
@ -7,6 +7,7 @@
|
||||
#if V8_TARGET_ARCH_X87
|
||||
|
||||
#include "src/base/bits.h"
|
||||
#include "src/base/division-by-constant.h"
|
||||
#include "src/bootstrapper.h"
|
||||
#include "src/codegen.h"
|
||||
#include "src/cpu-profiler.h"
|
||||
@ -3310,12 +3311,14 @@ void MacroAssembler::JumpIfDictionaryInPrototypeChain(
|
||||
void MacroAssembler::TruncatingDiv(Register dividend, int32_t divisor) {
|
||||
DCHECK(!dividend.is(eax));
|
||||
DCHECK(!dividend.is(edx));
|
||||
MultiplierAndShift ms(divisor);
|
||||
mov(eax, Immediate(ms.multiplier()));
|
||||
base::MagicNumbersForDivision<uint32_t> mag =
|
||||
base::SignedDivisionByConstant(static_cast<uint32_t>(divisor));
|
||||
mov(eax, Immediate(mag.multiplier));
|
||||
imul(dividend);
|
||||
if (divisor > 0 && ms.multiplier() < 0) add(edx, dividend);
|
||||
if (divisor < 0 && ms.multiplier() > 0) sub(edx, dividend);
|
||||
if (ms.shift() > 0) sar(edx, ms.shift());
|
||||
bool neg = (mag.multiplier & (static_cast<uint32_t>(1) << 31)) != 0;
|
||||
if (divisor > 0 && neg) add(edx, dividend);
|
||||
if (divisor < 0 && !neg && mag.multiplier > 0) sub(edx, dividend);
|
||||
if (mag.shift > 0) sar(edx, mag.shift);
|
||||
mov(eax, dividend);
|
||||
shr(eax, 31);
|
||||
add(edx, eax);
|
||||
|
@ -1167,6 +1167,8 @@
|
||||
'../../src/base/compiler-specific.h',
|
||||
'../../src/base/cpu.cc',
|
||||
'../../src/base/cpu.h',
|
||||
'../../src/base/division-by-constant.cc',
|
||||
'../../src/base/division-by-constant.h',
|
||||
'../../src/base/flags.h',
|
||||
'../../src/base/lazy-instance.h',
|
||||
'../../src/base/logging.cc',
|
||||
|
Loading…
Reference in New Issue
Block a user