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
parent 2a40210a
......@@ -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',
......
// 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
// 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
// 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',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment