summaryrefslogtreecommitdiff
path: root/absl/numeric/int128_no_intrinsic.inc
diff options
context:
space:
mode:
Diffstat (limited to 'absl/numeric/int128_no_intrinsic.inc')
-rw-r--r--absl/numeric/int128_no_intrinsic.inc77
1 files changed, 47 insertions, 30 deletions
diff --git a/absl/numeric/int128_no_intrinsic.inc b/absl/numeric/int128_no_intrinsic.inc
index 8834804c..6f5d8377 100644
--- a/absl/numeric/int128_no_intrinsic.inc
+++ b/absl/numeric/int128_no_intrinsic.inc
@@ -23,8 +23,7 @@ constexpr int64_t Int128High64(int128 v) { return v.hi_; }
#if defined(ABSL_IS_LITTLE_ENDIAN)
-constexpr int128::int128(int64_t high, uint64_t low) :
- lo_(low), hi_(high) {}
+constexpr int128::int128(int64_t high, uint64_t low) : lo_(low), hi_(high) {}
constexpr int128::int128(int v)
: lo_{static_cast<uint64_t>(v)}, hi_{v < 0 ? ~int64_t{0} : 0} {}
@@ -44,8 +43,7 @@ constexpr int128::int128(uint128 v)
#elif defined(ABSL_IS_BIG_ENDIAN)
-constexpr int128::int128(int64_t high, uint64_t low) :
- hi_{high}, lo_{low} {}
+constexpr int128::int128(int64_t high, uint64_t low) : hi_{high}, lo_{low} {}
constexpr int128::int128(int v)
: hi_{v < 0 ? ~int64_t{0} : 0}, lo_{static_cast<uint64_t>(v)} {}
@@ -279,33 +277,52 @@ constexpr int128 operator^(int128 lhs, int128 rhs) {
}
constexpr int128 operator<<(int128 lhs, int amount) {
- // int64_t shifts of >= 64 are undefined, so we need some special-casing.
- return amount >= 64
- ? MakeInt128(
- static_cast<int64_t>(Int128Low64(lhs) << (amount - 64)), 0)
- : amount == 0
- ? lhs
- : MakeInt128(
- (Int128High64(lhs) << amount) |
- static_cast<int64_t>(Int128Low64(lhs) >> (64 - amount)),
- Int128Low64(lhs) << amount);
+ // int64_t shifts of >= 63 are undefined, so we need some special-casing.
+ assert(amount >= 0 && amount < 127);
+ if (amount <= 0) {
+ return lhs;
+ } else if (amount < 63) {
+ return MakeInt128(
+ (Int128High64(lhs) << amount) |
+ static_cast<int64_t>(Int128Low64(lhs) >> (64 - amount)),
+ Int128Low64(lhs) << amount);
+ } else if (amount == 63) {
+ return MakeInt128(((Int128High64(lhs) << 32) << 31) |
+ static_cast<int64_t>(Int128Low64(lhs) >> 1),
+ (Int128Low64(lhs) << 32) << 31);
+ } else if (amount == 127) {
+ return MakeInt128(static_cast<int64_t>(Int128Low64(lhs) << 63), 0);
+ } else if (amount > 127) {
+ return MakeInt128(0, 0);
+ } else {
+ // amount >= 64 && amount < 127
+ return MakeInt128(static_cast<int64_t>(Int128Low64(lhs) << (amount - 64)),
+ 0);
+ }
}
constexpr int128 operator>>(int128 lhs, int amount) {
- // int64_t shifts of >= 64 are undefined, so we need some special-casing.
- // The (Int128High64(lhs) >> 32) >> 32 "trick" causes the the most significant
- // int64 to be inititialized with all zeros or all ones correctly. It takes
- // into account whether the number is negative or positive, and whether the
- // current architecture does arithmetic or logical right shifts for negative
- // numbers.
- return amount >= 64
- ? MakeInt128(
- (Int128High64(lhs) >> 32) >> 32,
- static_cast<uint64_t>(Int128High64(lhs) >> (amount - 64)))
- : amount == 0
- ? lhs
- : MakeInt128(Int128High64(lhs) >> amount,
- (Int128Low64(lhs) >> amount) |
- (static_cast<uint64_t>(Int128High64(lhs))
- << (64 - amount)));
+ // int64_t shifts of >= 63 are undefined, so we need some special-casing.
+ assert(amount >= 0 && amount < 127);
+ if (amount <= 0) {
+ return lhs;
+ } else if (amount < 63) {
+ return MakeInt128(
+ Int128High64(lhs) >> amount,
+ Int128Low64(lhs) >> amount | static_cast<uint64_t>(Int128High64(lhs))
+ << (64 - amount));
+ } else if (amount == 63) {
+ return MakeInt128((Int128High64(lhs) >> 32) >> 31,
+ static_cast<uint64_t>(Int128High64(lhs) << 1) |
+ (Int128Low64(lhs) >> 32) >> 31);
+
+ } else if (amount >= 127) {
+ return MakeInt128((Int128High64(lhs) >> 32) >> 31,
+ static_cast<uint64_t>((Int128High64(lhs) >> 32) >> 31));
+ } else {
+ // amount >= 64 && amount < 127
+ return MakeInt128(
+ (Int128High64(lhs) >> 32) >> 31,
+ static_cast<uint64_t>(Int128High64(lhs) >> (amount - 64)));
+ }
}