// 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/bits.h"
|
|
#include <limits>
|
|
#include "src/base/logging.h"
|
#include "src/base/safe_math.h"
|
|
namespace v8 {
|
namespace base {
|
namespace bits {
|
|
uint32_t RoundUpToPowerOfTwo32(uint32_t value) {
|
DCHECK_LE(value, uint32_t{1} << 31);
|
if (value) --value;
|
// Use computation based on leading zeros if we have compiler support for that.
|
#if V8_HAS_BUILTIN_CLZ || V8_CC_MSVC
|
return 1u << (32 - CountLeadingZeros(value));
|
#else
|
value |= value >> 1;
|
value |= value >> 2;
|
value |= value >> 4;
|
value |= value >> 8;
|
value |= value >> 16;
|
return value + 1;
|
#endif
|
}
|
|
uint64_t RoundUpToPowerOfTwo64(uint64_t value) {
|
DCHECK_LE(value, uint64_t{1} << 63);
|
if (value) --value;
|
// Use computation based on leading zeros if we have compiler support for that.
|
#if V8_HAS_BUILTIN_CLZ
|
return uint64_t{1} << (64 - CountLeadingZeros(value));
|
#else
|
value |= value >> 1;
|
value |= value >> 2;
|
value |= value >> 4;
|
value |= value >> 8;
|
value |= value >> 16;
|
value |= value >> 32;
|
return value + 1;
|
#endif
|
}
|
|
|
int32_t SignedMulHigh32(int32_t lhs, int32_t rhs) {
|
int64_t const value = static_cast<int64_t>(lhs) * static_cast<int64_t>(rhs);
|
return bit_cast<int32_t, uint32_t>(bit_cast<uint64_t>(value) >> 32u);
|
}
|
|
|
int32_t SignedMulHighAndAdd32(int32_t lhs, int32_t rhs, int32_t acc) {
|
return bit_cast<int32_t>(bit_cast<uint32_t>(acc) +
|
bit_cast<uint32_t>(SignedMulHigh32(lhs, rhs)));
|
}
|
|
|
int32_t SignedDiv32(int32_t lhs, int32_t rhs) {
|
if (rhs == 0) return 0;
|
if (rhs == -1) return -lhs;
|
return lhs / rhs;
|
}
|
|
|
int32_t SignedMod32(int32_t lhs, int32_t rhs) {
|
if (rhs == 0 || rhs == -1) return 0;
|
return lhs % rhs;
|
}
|
|
|
int64_t FromCheckedNumeric(const internal::CheckedNumeric<int64_t> value) {
|
if (value.IsValid())
|
return value.ValueUnsafe();
|
|
// We could return max/min but we don't really expose what the maximum delta
|
// is. Instead, return max/(-max), which is something that clients can reason
|
// about.
|
// TODO(rvargas) crbug.com/332611: don't use internal values.
|
int64_t limit = std::numeric_limits<int64_t>::max();
|
if (value.validity() == internal::RANGE_UNDERFLOW)
|
limit = -limit;
|
return value.ValueOrDefault(limit);
|
}
|
|
|
int64_t SignedSaturatedAdd64(int64_t lhs, int64_t rhs) {
|
internal::CheckedNumeric<int64_t> rv(lhs);
|
rv += rhs;
|
return FromCheckedNumeric(rv);
|
}
|
|
|
int64_t SignedSaturatedSub64(int64_t lhs, int64_t rhs) {
|
internal::CheckedNumeric<int64_t> rv(lhs);
|
rv -= rhs;
|
return FromCheckedNumeric(rv);
|
}
|
|
bool SignedMulOverflow32(int32_t lhs, int32_t rhs, int32_t* val) {
|
internal::CheckedNumeric<int32_t> rv(lhs);
|
rv *= rhs;
|
int32_t limit = std::numeric_limits<int32_t>::max();
|
*val = rv.ValueOrDefault(limit);
|
return !rv.IsValid();
|
}
|
|
bool SignedMulOverflow64(int64_t lhs, int64_t rhs, int64_t* val) {
|
internal::CheckedNumeric<int64_t> rv(lhs);
|
rv *= rhs;
|
int64_t limit = std::numeric_limits<int64_t>::max();
|
*val = rv.ValueOrDefault(limit);
|
return !rv.IsValid();
|
}
|
|
} // namespace bits
|
} // namespace base
|
} // namespace v8
|