Changes imported from Abseil "staging" branch:
- b7ac57541b07fadc3ed054cc3d62bc192a2098a7 Redefine arithmetic assign operators in terms of the bina... by Alex Strelnikov <strel@google.com> - bb2bf3fd86eb9f24420376aad1b9fe84068ad7e4 Cmake CI for Ubuntu by Jon Cohen <cohenjon@google.com> - 3ff3e6d6b4d99627f0785cad5b562362bdf1ae37 Fix internal namespace (debug_internal -> debugging_inter... by Derek Mauro <dmauro@google.com> - b50753d757c95a3430cc2d6cfc0272af1e5c219c Internal change. by Alex Strelnikov <strel@google.com> GitOrigin-RevId: b7ac57541b07fadc3ed054cc3d62bc192a2098a7 Change-Id: I7561639e296d1cc5dc7ee75e6645e8dae3f1bf97
This commit is contained in:
parent
bf7fc9986e
commit
3917120a4c
12 changed files with 116 additions and 86 deletions
|
@ -70,6 +70,7 @@ if(NOT ABSL_CCTZ_TARGET)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# commented: used only for standalone test
|
# commented: used only for standalone test
|
||||||
|
# Don't remove these or else CMake CI will break
|
||||||
#add_subdirectory(cctz)
|
#add_subdirectory(cctz)
|
||||||
#add_subdirectory(googletest)
|
#add_subdirectory(googletest)
|
||||||
check_target(${ABSL_CCTZ_TARGET})
|
check_target(${ABSL_CCTZ_TARGET})
|
||||||
|
|
|
@ -20,12 +20,12 @@
|
||||||
#if !defined(__linux__) || defined(__ANDROID__)
|
#if !defined(__linux__) || defined(__ANDROID__)
|
||||||
|
|
||||||
namespace absl {
|
namespace absl {
|
||||||
namespace debug_internal {
|
namespace debugging_internal {
|
||||||
|
|
||||||
// On platforms other than Linux, just return true.
|
// On platforms other than Linux, just return true.
|
||||||
bool AddressIsReadable(const void* /* addr */) { return true; }
|
bool AddressIsReadable(const void* /* addr */) { return true; }
|
||||||
|
|
||||||
} // namespace debug_internal
|
} // namespace debugging_internal
|
||||||
} // namespace absl
|
} // namespace absl
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -40,7 +40,7 @@ bool AddressIsReadable(const void* /* addr */) { return true; }
|
||||||
#include "absl/base/internal/raw_logging.h"
|
#include "absl/base/internal/raw_logging.h"
|
||||||
|
|
||||||
namespace absl {
|
namespace absl {
|
||||||
namespace debug_internal {
|
namespace debugging_internal {
|
||||||
|
|
||||||
// Pack a pid and two file descriptors into a 64-bit word,
|
// Pack a pid and two file descriptors into a 64-bit word,
|
||||||
// using 16, 24, and 24 bits for each respectively.
|
// using 16, 24, and 24 bits for each respectively.
|
||||||
|
@ -127,7 +127,7 @@ bool AddressIsReadable(const void *addr) {
|
||||||
return bytes_written == 1;
|
return bytes_written == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace debug_internal
|
} // namespace debugging_internal
|
||||||
} // namespace absl
|
} // namespace absl
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -17,13 +17,13 @@
|
||||||
#define ABSL_DEBUGGING_INTERNAL_ADDRESS_IS_READABLE_H_
|
#define ABSL_DEBUGGING_INTERNAL_ADDRESS_IS_READABLE_H_
|
||||||
|
|
||||||
namespace absl {
|
namespace absl {
|
||||||
namespace debug_internal {
|
namespace debugging_internal {
|
||||||
|
|
||||||
// Return whether the byte at *addr is readable, without faulting.
|
// Return whether the byte at *addr is readable, without faulting.
|
||||||
// Save and restores errno.
|
// Save and restores errno.
|
||||||
bool AddressIsReadable(const void *addr);
|
bool AddressIsReadable(const void *addr);
|
||||||
|
|
||||||
} // namespace debug_internal
|
} // namespace debugging_internal
|
||||||
} // namespace absl
|
} // namespace absl
|
||||||
|
|
||||||
#endif // ABSL_DEBUGGING_INTERNAL_ADDRESS_IS_READABLE_H_
|
#endif // ABSL_DEBUGGING_INTERNAL_ADDRESS_IS_READABLE_H_
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
#define VERSYM_VERSION 0x7fff
|
#define VERSYM_VERSION 0x7fff
|
||||||
|
|
||||||
namespace absl {
|
namespace absl {
|
||||||
namespace debug_internal {
|
namespace debugging_internal {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -392,7 +392,7 @@ void ElfMemImage::SymbolIterator::Update(int increment) {
|
||||||
info_.symbol = symbol;
|
info_.symbol = symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace debug_internal
|
} // namespace debugging_internal
|
||||||
} // namespace absl
|
} // namespace absl
|
||||||
|
|
||||||
#endif // ABSL_HAVE_ELF_MEM_IMAGE
|
#endif // ABSL_HAVE_ELF_MEM_IMAGE
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
#include <link.h> // for ElfW
|
#include <link.h> // for ElfW
|
||||||
|
|
||||||
namespace absl {
|
namespace absl {
|
||||||
namespace debug_internal {
|
namespace debugging_internal {
|
||||||
|
|
||||||
// An in-memory ELF image (may not exist on disk).
|
// An in-memory ELF image (may not exist on disk).
|
||||||
class ElfMemImage {
|
class ElfMemImage {
|
||||||
|
@ -122,7 +122,7 @@ class ElfMemImage {
|
||||||
ElfW(Addr) link_base_; // Link-time base (p_vaddr of first PT_LOAD).
|
ElfW(Addr) link_base_; // Link-time base (p_vaddr of first PT_LOAD).
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace debug_internal
|
} // namespace debugging_internal
|
||||||
} // namespace absl
|
} // namespace absl
|
||||||
|
|
||||||
#endif // ABSL_HAVE_ELF_MEM_IMAGE
|
#endif // ABSL_HAVE_ELF_MEM_IMAGE
|
||||||
|
|
|
@ -33,9 +33,9 @@ static const unsigned char* GetKernelRtSigreturnAddress() {
|
||||||
address = reinterpret_cast<uintptr_t>(nullptr);
|
address = reinterpret_cast<uintptr_t>(nullptr);
|
||||||
|
|
||||||
#ifdef ABSL_HAVE_VDSO_SUPPORT
|
#ifdef ABSL_HAVE_VDSO_SUPPORT
|
||||||
absl::debug_internal::VDSOSupport vdso;
|
absl::debugging_internal::VDSOSupport vdso;
|
||||||
if (vdso.IsPresent()) {
|
if (vdso.IsPresent()) {
|
||||||
absl::debug_internal::VDSOSupport::SymbolInfo symbol_info;
|
absl::debugging_internal::VDSOSupport::SymbolInfo symbol_info;
|
||||||
if (!vdso.LookupSymbol("__kernel_rt_sigreturn", "LINUX_2.6.39", STT_FUNC,
|
if (!vdso.LookupSymbol("__kernel_rt_sigreturn", "LINUX_2.6.39", STT_FUNC,
|
||||||
&symbol_info) ||
|
&symbol_info) ||
|
||||||
symbol_info.address == nullptr) {
|
symbol_info.address == nullptr) {
|
||||||
|
@ -90,7 +90,7 @@ static void **NextStackFrame(void **old_frame_pointer, const void *uc) {
|
||||||
// Check that alleged frame pointer is actually readable. This is to
|
// Check that alleged frame pointer is actually readable. This is to
|
||||||
// prevent "double fault" in case we hit the first fault due to e.g.
|
// prevent "double fault" in case we hit the first fault due to e.g.
|
||||||
// stack corruption.
|
// stack corruption.
|
||||||
if (!absl::debug_internal::AddressIsReadable(
|
if (!absl::debugging_internal::AddressIsReadable(
|
||||||
pre_signal_frame_pointer))
|
pre_signal_frame_pointer))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
|
|
@ -99,13 +99,13 @@ static void **NextStackFrame(void **old_sp, const void *uc) {
|
||||||
// possibly be there.
|
// possibly be there.
|
||||||
static const unsigned char *kernel_sigtramp_rt64_address = nullptr;
|
static const unsigned char *kernel_sigtramp_rt64_address = nullptr;
|
||||||
if (kernel_symbol_status == kNotInitialized) {
|
if (kernel_symbol_status == kNotInitialized) {
|
||||||
absl::debug_internal::VDSOSupport vdso;
|
absl::debugging_internal::VDSOSupport vdso;
|
||||||
if (vdso.IsPresent()) {
|
if (vdso.IsPresent()) {
|
||||||
absl::debug_internal::VDSOSupport::SymbolInfo
|
absl::debugging_internal::VDSOSupport::SymbolInfo
|
||||||
sigtramp_rt64_symbol_info;
|
sigtramp_rt64_symbol_info;
|
||||||
if (!vdso.LookupSymbol(
|
if (!vdso.LookupSymbol(
|
||||||
"__kernel_sigtramp_rt64", "LINUX_2.6.15",
|
"__kernel_sigtramp_rt64", "LINUX_2.6.15",
|
||||||
absl::debug_internal::VDSOSupport::kVDSOSymbolType,
|
absl::debugging_internal::VDSOSupport::kVDSOSymbolType,
|
||||||
&sigtramp_rt64_symbol_info) ||
|
&sigtramp_rt64_symbol_info) ||
|
||||||
sigtramp_rt64_symbol_info.address == nullptr) {
|
sigtramp_rt64_symbol_info.address == nullptr) {
|
||||||
// Unexpected: VDSO is present, yet the expected symbol is missing
|
// Unexpected: VDSO is present, yet the expected symbol is missing
|
||||||
|
@ -137,7 +137,7 @@ static void **NextStackFrame(void **old_sp, const void *uc) {
|
||||||
// Check that alleged stack pointer is actually readable. This is to
|
// Check that alleged stack pointer is actually readable. This is to
|
||||||
// prevent a "double fault" in case we hit the first fault due to e.g.
|
// prevent a "double fault" in case we hit the first fault due to e.g.
|
||||||
// a stack corruption.
|
// a stack corruption.
|
||||||
if (absl::debug_internal::AddressIsReadable(sp_before_signal)) {
|
if (absl::debugging_internal::AddressIsReadable(sp_before_signal)) {
|
||||||
// Alleged stack pointer is readable, use it for further unwinding.
|
// Alleged stack pointer is readable, use it for further unwinding.
|
||||||
new_sp = sp_before_signal;
|
new_sp = sp_before_signal;
|
||||||
}
|
}
|
||||||
|
|
|
@ -170,11 +170,11 @@ static void **NextStackFrame(void **old_fp, const void *uc) {
|
||||||
static const unsigned char *kernel_rt_sigreturn_address = nullptr;
|
static const unsigned char *kernel_rt_sigreturn_address = nullptr;
|
||||||
static const unsigned char *kernel_vsyscall_address = nullptr;
|
static const unsigned char *kernel_vsyscall_address = nullptr;
|
||||||
if (num_push_instructions == -1) {
|
if (num_push_instructions == -1) {
|
||||||
absl::debug_internal::VDSOSupport vdso;
|
absl::debugging_internal::VDSOSupport vdso;
|
||||||
if (vdso.IsPresent()) {
|
if (vdso.IsPresent()) {
|
||||||
absl::debug_internal::VDSOSupport::SymbolInfo
|
absl::debugging_internal::VDSOSupport::SymbolInfo
|
||||||
rt_sigreturn_symbol_info;
|
rt_sigreturn_symbol_info;
|
||||||
absl::debug_internal::VDSOSupport::SymbolInfo vsyscall_symbol_info;
|
absl::debugging_internal::VDSOSupport::SymbolInfo vsyscall_symbol_info;
|
||||||
if (!vdso.LookupSymbol("__kernel_rt_sigreturn", "LINUX_2.5", STT_FUNC,
|
if (!vdso.LookupSymbol("__kernel_rt_sigreturn", "LINUX_2.5", STT_FUNC,
|
||||||
&rt_sigreturn_symbol_info) ||
|
&rt_sigreturn_symbol_info) ||
|
||||||
!vdso.LookupSymbol("__kernel_vsyscall", "LINUX_2.5", STT_FUNC,
|
!vdso.LookupSymbol("__kernel_vsyscall", "LINUX_2.5", STT_FUNC,
|
||||||
|
@ -221,7 +221,7 @@ static void **NextStackFrame(void **old_fp, const void *uc) {
|
||||||
// "double fault" in case we hit the first fault due to e.g. stack
|
// "double fault" in case we hit the first fault due to e.g. stack
|
||||||
// corruption.
|
// corruption.
|
||||||
void *const reg_esp2 = reg_esp[num_push_instructions - 1];
|
void *const reg_esp2 = reg_esp[num_push_instructions - 1];
|
||||||
if (absl::debug_internal::AddressIsReadable(reg_esp2)) {
|
if (absl::debugging_internal::AddressIsReadable(reg_esp2)) {
|
||||||
// Alleged %esp is readable, use it for further unwinding.
|
// Alleged %esp is readable, use it for further unwinding.
|
||||||
new_fp = reinterpret_cast<void **>(reg_esp2);
|
new_fp = reinterpret_cast<void **>(reg_esp2);
|
||||||
}
|
}
|
||||||
|
@ -273,7 +273,7 @@ static void **NextStackFrame(void **old_fp, const void *uc) {
|
||||||
// Note: NextStackFrame<false>() is only called while the program
|
// Note: NextStackFrame<false>() is only called while the program
|
||||||
// is already on its last leg, so it's ok to be slow here.
|
// is already on its last leg, so it's ok to be slow here.
|
||||||
|
|
||||||
if (!absl::debug_internal::AddressIsReadable(new_fp)) {
|
if (!absl::debugging_internal::AddressIsReadable(new_fp)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,18 +38,18 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace absl {
|
namespace absl {
|
||||||
namespace debug_internal {
|
namespace debugging_internal {
|
||||||
|
|
||||||
ABSL_CONST_INIT
|
ABSL_CONST_INIT
|
||||||
std::atomic<const void *> VDSOSupport::vdso_base_(
|
std::atomic<const void *> VDSOSupport::vdso_base_(
|
||||||
debug_internal::ElfMemImage::kInvalidBase);
|
debugging_internal::ElfMemImage::kInvalidBase);
|
||||||
|
|
||||||
std::atomic<VDSOSupport::GetCpuFn> VDSOSupport::getcpu_fn_(&InitAndGetCPU);
|
std::atomic<VDSOSupport::GetCpuFn> VDSOSupport::getcpu_fn_(&InitAndGetCPU);
|
||||||
VDSOSupport::VDSOSupport()
|
VDSOSupport::VDSOSupport()
|
||||||
// If vdso_base_ is still set to kInvalidBase, we got here
|
// If vdso_base_ is still set to kInvalidBase, we got here
|
||||||
// before VDSOSupport::Init has been called. Call it now.
|
// before VDSOSupport::Init has been called. Call it now.
|
||||||
: image_(vdso_base_.load(std::memory_order_relaxed) ==
|
: image_(vdso_base_.load(std::memory_order_relaxed) ==
|
||||||
debug_internal::ElfMemImage::kInvalidBase
|
debugging_internal::ElfMemImage::kInvalidBase
|
||||||
? Init()
|
? Init()
|
||||||
: vdso_base_.load(std::memory_order_relaxed)) {}
|
: vdso_base_.load(std::memory_order_relaxed)) {}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ VDSOSupport::VDSOSupport()
|
||||||
// Finally, even if there is a race here, it is harmless, because
|
// Finally, even if there is a race here, it is harmless, because
|
||||||
// the operation should be idempotent.
|
// the operation should be idempotent.
|
||||||
const void *VDSOSupport::Init() {
|
const void *VDSOSupport::Init() {
|
||||||
const auto kInvalidBase = debug_internal::ElfMemImage::kInvalidBase;
|
const auto kInvalidBase = debugging_internal::ElfMemImage::kInvalidBase;
|
||||||
#if __GLIBC_PREREQ(2, 16)
|
#if __GLIBC_PREREQ(2, 16)
|
||||||
if (vdso_base_.load(std::memory_order_relaxed) == kInvalidBase) {
|
if (vdso_base_.load(std::memory_order_relaxed) == kInvalidBase) {
|
||||||
errno = 0;
|
errno = 0;
|
||||||
|
@ -120,7 +120,7 @@ const void *VDSOSupport::Init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const void *VDSOSupport::SetBase(const void *base) {
|
const void *VDSOSupport::SetBase(const void *base) {
|
||||||
ABSL_RAW_CHECK(base != debug_internal::ElfMemImage::kInvalidBase,
|
ABSL_RAW_CHECK(base != debugging_internal::ElfMemImage::kInvalidBase,
|
||||||
"internal error");
|
"internal error");
|
||||||
const void *old_base = vdso_base_.load(std::memory_order_relaxed);
|
const void *old_base = vdso_base_.load(std::memory_order_relaxed);
|
||||||
vdso_base_.store(base, std::memory_order_relaxed);
|
vdso_base_.store(base, std::memory_order_relaxed);
|
||||||
|
@ -186,7 +186,7 @@ static class VDSOInitHelper {
|
||||||
VDSOInitHelper() { VDSOSupport::Init(); }
|
VDSOInitHelper() { VDSOSupport::Init(); }
|
||||||
} vdso_init_helper;
|
} vdso_init_helper;
|
||||||
|
|
||||||
} // namespace debug_internal
|
} // namespace debugging_internal
|
||||||
} // namespace absl
|
} // namespace absl
|
||||||
|
|
||||||
#endif // ABSL_HAVE_VDSO_SUPPORT
|
#endif // ABSL_HAVE_VDSO_SUPPORT
|
||||||
|
|
|
@ -52,7 +52,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace absl {
|
namespace absl {
|
||||||
namespace debug_internal {
|
namespace debugging_internal {
|
||||||
|
|
||||||
// NOTE: this class may be used from within tcmalloc, and can not
|
// NOTE: this class may be used from within tcmalloc, and can not
|
||||||
// use any memory allocation routines.
|
// use any memory allocation routines.
|
||||||
|
@ -147,7 +147,7 @@ class VDSOSupport {
|
||||||
// support SYS_getcpu.
|
// support SYS_getcpu.
|
||||||
int GetCPU();
|
int GetCPU();
|
||||||
|
|
||||||
} // namespace debug_internal
|
} // namespace debugging_internal
|
||||||
} // namespace absl
|
} // namespace absl
|
||||||
|
|
||||||
#endif // ABSL_HAVE_ELF_MEM_IMAGE
|
#endif // ABSL_HAVE_ELF_MEM_IMAGE
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <iostream> // NOLINT(readability/streams)
|
#include <iostream> // NOLINT(readability/streams)
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
namespace absl {
|
namespace absl {
|
||||||
|
|
||||||
|
@ -128,19 +129,17 @@ uint128::uint128(float v) : uint128(MakeUint128FromFloat(v)) {}
|
||||||
uint128::uint128(double v) : uint128(MakeUint128FromFloat(v)) {}
|
uint128::uint128(double v) : uint128(MakeUint128FromFloat(v)) {}
|
||||||
uint128::uint128(long double v) : uint128(MakeUint128FromFloat(v)) {}
|
uint128::uint128(long double v) : uint128(MakeUint128FromFloat(v)) {}
|
||||||
|
|
||||||
uint128& uint128::operator/=(uint128 other) {
|
uint128 operator/(uint128 lhs, uint128 rhs) {
|
||||||
uint128 quotient = 0;
|
uint128 quotient = 0;
|
||||||
uint128 remainder = 0;
|
uint128 remainder = 0;
|
||||||
DivModImpl(*this, other, "ient, &remainder);
|
DivModImpl(lhs, rhs, "ient, &remainder);
|
||||||
*this = quotient;
|
return quotient;
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
uint128& uint128::operator%=(uint128 other) {
|
uint128 operator%(uint128 lhs, uint128 rhs) {
|
||||||
uint128 quotient = 0;
|
uint128 quotient = 0;
|
||||||
uint128 remainder = 0;
|
uint128 remainder = 0;
|
||||||
DivModImpl(*this, other, "ient, &remainder);
|
DivModImpl(lhs, rhs, "ient, &remainder);
|
||||||
*this = remainder;
|
return remainder;
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
|
@ -262,21 +262,50 @@ inline uint128& uint128::operator=(unsigned __int128 v) {
|
||||||
}
|
}
|
||||||
#endif // ABSL_HAVE_INTRINSIC_INT128
|
#endif // ABSL_HAVE_INTRINSIC_INT128
|
||||||
|
|
||||||
// Shift and arithmetic operators.
|
// Arithmetic operators.
|
||||||
|
|
||||||
inline uint128 operator<<(uint128 lhs, int amount) { return lhs <<= amount; }
|
uint128 operator<<(uint128 lhs, int amount);
|
||||||
|
uint128 operator>>(uint128 lhs, int amount);
|
||||||
|
uint128 operator+(uint128 lhs, uint128 rhs);
|
||||||
|
uint128 operator-(uint128 lhs, uint128 rhs);
|
||||||
|
uint128 operator*(uint128 lhs, uint128 rhs);
|
||||||
|
uint128 operator/(uint128 lhs, uint128 rhs);
|
||||||
|
uint128 operator%(uint128 lhs, uint128 rhs);
|
||||||
|
|
||||||
inline uint128 operator>>(uint128 lhs, int amount) { return lhs >>= amount; }
|
inline uint128& uint128::operator<<=(int amount) {
|
||||||
|
*this = *this << amount;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
inline uint128 operator+(uint128 lhs, uint128 rhs) { return lhs += rhs; }
|
inline uint128& uint128::operator>>=(int amount) {
|
||||||
|
*this = *this >> amount;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
inline uint128 operator-(uint128 lhs, uint128 rhs) { return lhs -= rhs; }
|
inline uint128& uint128::operator+=(uint128 other) {
|
||||||
|
*this = *this + other;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
inline uint128 operator*(uint128 lhs, uint128 rhs) { return lhs *= rhs; }
|
inline uint128& uint128::operator-=(uint128 other) {
|
||||||
|
*this = *this - other;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
inline uint128 operator/(uint128 lhs, uint128 rhs) { return lhs /= rhs; }
|
inline uint128& uint128::operator*=(uint128 other) {
|
||||||
|
*this = *this * other;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
inline uint128 operator%(uint128 lhs, uint128 rhs) { return lhs %= rhs; }
|
inline uint128& uint128::operator/=(uint128 other) {
|
||||||
|
*this = *this / other;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint128& uint128::operator%=(uint128 other) {
|
||||||
|
*this = *this % other;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
constexpr uint64_t Uint128Low64(uint128 v) { return v.lo_; }
|
constexpr uint64_t Uint128Low64(uint128 v) { return v.lo_; }
|
||||||
|
|
||||||
|
@ -514,9 +543,9 @@ inline uint128& uint128::operator^=(uint128 other) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shift and arithmetic assign operators.
|
// Arithmetic operators.
|
||||||
|
|
||||||
inline uint128& uint128::operator<<=(int amount) {
|
inline uint128 operator<<(uint128 lhs, int amount) {
|
||||||
assert(amount >= 0); // Negative shifts are undefined.
|
assert(amount >= 0); // Negative shifts are undefined.
|
||||||
assert(amount < 128); // Shifts of >= 128 are undefined.
|
assert(amount < 128); // Shifts of >= 128 are undefined.
|
||||||
|
|
||||||
|
@ -524,17 +553,16 @@ inline uint128& uint128::operator<<=(int amount) {
|
||||||
// special-casing.
|
// special-casing.
|
||||||
if (amount < 64) {
|
if (amount < 64) {
|
||||||
if (amount != 0) {
|
if (amount != 0) {
|
||||||
hi_ = (hi_ << amount) | (lo_ >> (64 - amount));
|
return MakeUint128(
|
||||||
lo_ = lo_ << amount;
|
(Uint128High64(lhs) << amount) | (Uint128Low64(lhs) >> (64 - amount)),
|
||||||
|
Uint128Low64(lhs) << amount);
|
||||||
}
|
}
|
||||||
} else {
|
return lhs;
|
||||||
hi_ = lo_ << (amount - 64);
|
|
||||||
lo_ = 0;
|
|
||||||
}
|
}
|
||||||
return *this;
|
return MakeUint128(Uint128Low64(lhs) << (amount - 64), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint128& uint128::operator>>=(int amount) {
|
inline uint128 operator>>(uint128 lhs, int amount) {
|
||||||
assert(amount >= 0); // Negative shifts are undefined.
|
assert(amount >= 0); // Negative shifts are undefined.
|
||||||
assert(amount < 128); // Shifts of >= 128 are undefined.
|
assert(amount < 128); // Shifts of >= 128 are undefined.
|
||||||
|
|
||||||
|
@ -542,49 +570,51 @@ inline uint128& uint128::operator>>=(int amount) {
|
||||||
// special-casing.
|
// special-casing.
|
||||||
if (amount < 64) {
|
if (amount < 64) {
|
||||||
if (amount != 0) {
|
if (amount != 0) {
|
||||||
lo_ = (lo_ >> amount) | (hi_ << (64 - amount));
|
return MakeUint128(Uint128High64(lhs) >> amount,
|
||||||
hi_ = hi_ >> amount;
|
(Uint128Low64(lhs) >> amount) |
|
||||||
|
(Uint128High64(lhs) << (64 - amount)));
|
||||||
}
|
}
|
||||||
} else {
|
return lhs;
|
||||||
lo_ = hi_ >> (amount - 64);
|
|
||||||
hi_ = 0;
|
|
||||||
}
|
}
|
||||||
return *this;
|
return MakeUint128(0, Uint128High64(lhs) >> (amount - 64));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint128& uint128::operator+=(uint128 other) {
|
inline uint128 operator+(uint128 lhs, uint128 rhs) {
|
||||||
hi_ += other.hi_;
|
uint128 result = MakeUint128(Uint128High64(lhs) + Uint128High64(rhs),
|
||||||
uint64_t lolo = lo_ + other.lo_;
|
Uint128Low64(lhs) + Uint128Low64(rhs));
|
||||||
if (lolo < lo_)
|
if (Uint128Low64(result) < Uint128Low64(lhs)) { // check for carry
|
||||||
++hi_;
|
return MakeUint128(Uint128High64(result) + 1, Uint128Low64(result));
|
||||||
lo_ = lolo;
|
}
|
||||||
return *this;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint128& uint128::operator-=(uint128 other) {
|
inline uint128 operator-(uint128 lhs, uint128 rhs) {
|
||||||
hi_ -= other.hi_;
|
uint128 result = MakeUint128(Uint128High64(lhs) - Uint128High64(rhs),
|
||||||
if (other.lo_ > lo_) --hi_;
|
Uint128Low64(lhs) - Uint128Low64(rhs));
|
||||||
lo_ -= other.lo_;
|
if (Uint128Low64(lhs) < Uint128Low64(rhs)) { // check for carry
|
||||||
return *this;
|
return MakeUint128(Uint128High64(result) - 1, Uint128Low64(result));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint128& uint128::operator*=(uint128 other) {
|
inline uint128 operator*(uint128 lhs, uint128 rhs) {
|
||||||
#if defined(ABSL_HAVE_INTRINSIC_INT128)
|
#if defined(ABSL_HAVE_INTRINSIC_INT128)
|
||||||
// TODO(strel) Remove once alignment issues are resolved and unsigned __int128
|
// TODO(strel) Remove once alignment issues are resolved and unsigned __int128
|
||||||
// can be used for uint128 storage.
|
// can be used for uint128 storage.
|
||||||
*this = static_cast<unsigned __int128>(*this) *
|
return static_cast<unsigned __int128>(lhs) *
|
||||||
static_cast<unsigned __int128>(other);
|
static_cast<unsigned __int128>(rhs);
|
||||||
return *this;
|
|
||||||
#else // ABSL_HAVE_INTRINSIC128
|
#else // ABSL_HAVE_INTRINSIC128
|
||||||
uint64_t a32 = lo_ >> 32;
|
uint64_t a32 = Uint128Low64(lhs) >> 32;
|
||||||
uint64_t a00 = lo_ & 0xffffffff;
|
uint64_t a00 = Uint128Low64(lhs) & 0xffffffff;
|
||||||
uint64_t b32 = other.lo_ >> 32;
|
uint64_t b32 = Uint128Low64(rhs) >> 32;
|
||||||
uint64_t b00 = other.lo_ & 0xffffffff;
|
uint64_t b00 = Uint128Low64(rhs) & 0xffffffff;
|
||||||
hi_ = hi_ * other.lo_ + lo_ * other.hi_ + a32 * b32;
|
uint128 result =
|
||||||
lo_ = a00 * b00;
|
MakeUint128(Uint128High64(lhs) * Uint128Low64(rhs) +
|
||||||
*this += uint128(a32 * b00) << 32;
|
Uint128Low64(lhs) * Uint128High64(rhs) + a32 * b32,
|
||||||
*this += uint128(a00 * b32) << 32;
|
a00 * b00);
|
||||||
return *this;
|
result += uint128(a32 * b00) << 32;
|
||||||
|
result += uint128(a00 * b32) << 32;
|
||||||
|
return result;
|
||||||
#endif // ABSL_HAVE_INTRINSIC128
|
#endif // ABSL_HAVE_INTRINSIC128
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue