13
0

int62_t: use explicit memory order for all loads and stores

Also, improve implementation of CAS loops for operator <X>=.

Ideally, we ought to test this on ARM, both before and after.
This commit is contained in:
Paul Davis 2023-02-22 13:11:00 -07:00
parent fe17b98079
commit 4137271188

View File

@ -59,7 +59,7 @@ class alignas(16) int62_t {
int62_t () : v (0) {} int62_t () : v (0) {}
int62_t (bool bc, int64_t vc) : v (build (bc, vc)) {} int62_t (bool bc, int64_t vc) : v (build (bc, vc)) {}
int62_t (int62_t const & other) { v.store (other.v.load()); } int62_t (int62_t const & other) { v.store (other.v.load(std::memory_order_acquire), std::memory_order_release); }
static const int64_t max = 4611686018427387903; /* 2^62 - 1 */ static const int64_t max = 4611686018427387903; /* 2^62 - 1 */
static const int64_t min = -2305843009213693952; static const int64_t min = -2305843009213693952;
@ -67,8 +67,8 @@ class alignas(16) int62_t {
bool flagged() const { return flagged (v); } bool flagged() const { return flagged (v); }
int64_t val() const { return int62(v); } int64_t val() const { return int62(v); }
int62_t& operator= (int64_t n) { v.store (build (flagged (v.load()), n)); return *this; } int62_t& operator= (int64_t n) { v.store (build (flagged (v.load(std::memory_order_acquire)), n), std::memory_order_release); return *this; }
int62_t& operator= (int62_t const & other) { v.store (other.v.load()); return *this; } int62_t& operator= (int62_t const & other) { v.store (other.v.load(std::memory_order_acquire), std::memory_order_release); return *this; }
/* there's a pattern to many of these operators: /* there's a pattern to many of these operators:
@ -85,19 +85,19 @@ class alignas(16) int62_t {
rather than two separate loads for each "part". rather than two separate loads for each "part".
*/ */
int62_t operator- () const { const int64_t vv = v.load(); return int62_t (flagged (vv), -int62(vv)); } int62_t operator- () const { const int64_t vv = v.load(std::memory_order_acquire); return int62_t (flagged (vv), -int62(vv)); }
int62_t operator+ (int64_t n) const { const int64_t vv = v.load(); return int62_t (flagged (vv), int62 (vv) + n); } int62_t operator+ (int64_t n) const { const int64_t vv = v.load(std::memory_order_acquire); return int62_t (flagged (vv), int62 (vv) + n); }
int62_t operator- (int64_t n) const { const int64_t vv = v.load(); return int62_t (flagged (vv), int62 (vv) - n); } int62_t operator- (int64_t n) const { const int64_t vv = v.load(std::memory_order_acquire); return int62_t (flagged (vv), int62 (vv) - n); }
int62_t operator* (int64_t n) const { const int64_t vv = v.load(); return int62_t (flagged (vv), int62 (vv) * n); } int62_t operator* (int64_t n) const { const int64_t vv = v.load(std::memory_order_acquire); return int62_t (flagged (vv), int62 (vv) * n); }
int62_t operator/ (int64_t n) const { const int64_t vv = v.load(); return int62_t (flagged (vv), int62 (vv) / n); } int62_t operator/ (int64_t n) const { const int64_t vv = v.load(std::memory_order_acquire); return int62_t (flagged (vv), int62 (vv) / n); }
int62_t operator% (int64_t n) const { const int64_t vv = v.load(); return int62_t (flagged (vv), int62 (vv) % n); } int62_t operator% (int64_t n) const { const int64_t vv = v.load(std::memory_order_acquire); return int62_t (flagged (vv), int62 (vv) % n); }
int62_t operator+ (int62_t n) const { const int64_t vv = v.load(); return int62_t (flagged (vv), int62 (vv) + n.val()); } int62_t operator+ (int62_t n) const { const int64_t vv = v.load(std::memory_order_acquire); return int62_t (flagged (vv), int62 (vv) + n.val()); }
int62_t operator- (int62_t n) const { const int64_t vv = v.load(); return int62_t (flagged (vv), int62 (vv) - n.val()); } int62_t operator- (int62_t n) const { const int64_t vv = v.load(std::memory_order_acquire); return int62_t (flagged (vv), int62 (vv) - n.val()); }
int62_t operator* (int62_t n) const { const int64_t vv = v.load(); return int62_t (flagged (vv), int62 (vv) * n.val()); } int62_t operator* (int62_t n) const { const int64_t vv = v.load(std::memory_order_acquire); return int62_t (flagged (vv), int62 (vv) * n.val()); }
int62_t operator/ (int62_t n) const { const int64_t vv = v.load(); return int62_t (flagged (vv), int62 (vv) / n.val()); } int62_t operator/ (int62_t n) const { const int64_t vv = v.load(std::memory_order_acquire); return int62_t (flagged (vv), int62 (vv) / n.val()); }
int62_t operator% (int62_t n) const { const int64_t vv = v.load(); return int62_t (flagged (vv), int62 (vv) % n.val()); } int62_t operator% (int62_t n) const { const int64_t vv = v.load(std::memory_order_acquire); return int62_t (flagged (vv), int62 (vv) % n.val()); }
/* comparison operators .. will throw if the two objects have different /* comparison operators .. will throw if the two objects have different
* flag settings (which is assumed to indicate that they differ in some * flag settings (which is assumed to indicate that they differ in some
@ -118,8 +118,8 @@ class alignas(16) int62_t {
* the semantics are well defined and the computation cost is trivial * the semantics are well defined and the computation cost is trivial
*/ */
bool operator!= (int62_t const & other) const { const int64_t vv = v.load(); if (flagged (vv) != other.flagged()) return true; return int62 (vv) != other.val(); } bool operator!= (int62_t const & other) const { const int64_t vv = v.load(std::memory_order_acquire); if (flagged (vv) != other.flagged()) return true; return int62 (vv) != other.val(); }
bool operator== (int62_t const & other) const { const int64_t vv = v.load(); if (flagged (vv) != other.flagged()) return false; return int62 (vv) == other.val(); } bool operator== (int62_t const & other) const { const int64_t vv = v.load(std::memory_order_acquire); if (flagged (vv) != other.flagged()) return false; return int62 (vv) == other.val(); }
explicit operator int64_t() const { return int62(v); } explicit operator int64_t() const { return int62(v); }
@ -133,103 +133,83 @@ class alignas(16) int62_t {
int62_t abs() const { const int64_t tmp = v; return int62_t (flagged(tmp), ::llabs(int62(tmp))); } int62_t abs() const { const int64_t tmp = v; return int62_t (flagged(tmp), ::llabs(int62(tmp))); }
int62_t& operator+= (int64_t n) { int62_t& operator+= (int64_t n) {
while (1) { int64_t oldval = v.load (std::memory_order_acquire);
int64_t oldval = v.load (std::memory_order_relaxed); int64_t newval = build (flagged (oldval), int62 (oldval) + n);
int64_t newval = build (flagged (oldval), int62 (oldval) + n); while (!v.compare_exchange_weak (oldval, newval, std::memory_order_release, std::memory_order_relaxed)) {
if (v.compare_exchange_weak (oldval, newval)) { newval = build (flagged (oldval), int62 (oldval) + n);
break;
}
} }
return *this; return *this;
} }
int62_t& operator-= (int64_t n) { int62_t& operator-= (int64_t n) {
while (1) { int64_t oldval = v.load (std::memory_order_acquire);
int64_t oldval = v.load (std::memory_order_relaxed); int64_t newval = build (flagged (oldval), int62 (oldval) - n);
int64_t newval = build (flagged (oldval), int62 (oldval) - n); while (!v.compare_exchange_weak (oldval, newval, std::memory_order_release, std::memory_order_relaxed)) {
if (v.compare_exchange_weak (oldval, newval)) { newval = build (flagged (oldval), int62 (oldval) - n);
break;
}
} }
return *this; return *this;
} }
int62_t& operator*= (int64_t n) { int62_t& operator*= (int64_t n) {
while (1) { int64_t oldval = v.load (std::memory_order_acquire);
int64_t oldval = v.load (std::memory_order_relaxed); int64_t newval = build (flagged (oldval), int62 (oldval) * n);
int64_t newval = build (flagged (oldval), int62 (oldval) * n); while (!v.compare_exchange_weak (oldval, newval, std::memory_order_release, std::memory_order_relaxed)) {
if (v.compare_exchange_weak (oldval, newval)) { newval = build (flagged (oldval), int62 (oldval) * n);
break;
}
} }
return *this; return *this;
} }
int62_t& operator/= (int64_t n) { int62_t& operator/= (int64_t n) {
while (1) { int64_t oldval = v.load (std::memory_order_acquire);
int64_t oldval = v.load (std::memory_order_relaxed); int64_t newval = build (flagged (oldval), int62 (oldval) / n);
int64_t newval = build (flagged (oldval), int62 (oldval) / n); while (!v.compare_exchange_weak (oldval, newval, std::memory_order_release, std::memory_order_relaxed)) {
if (v.compare_exchange_weak (oldval, newval)) { newval = build (flagged (oldval), int62 (oldval) / n);
break;
}
} }
return *this; return *this;
} }
int62_t& operator%= (int64_t n) { int62_t& operator%= (int64_t n) {
while (1) { int64_t oldval = v.load (std::memory_order_acquire);
int64_t oldval = v.load (std::memory_order_relaxed); int64_t newval = build (flagged (oldval), int62 (oldval) % n);
int64_t newval = build (flagged (oldval), int62 (oldval) % n); while (!v.compare_exchange_weak (oldval, newval, std::memory_order_release, std::memory_order_relaxed)) {
if (v.compare_exchange_weak (oldval, newval)) { newval = build (flagged (oldval), int62 (oldval) % n);
break;
}
} }
return *this; return *this;
} }
int62_t& operator+= (int62_t n) { int62_t& operator+= (int62_t n) {
while (1) { int64_t oldval = v.load (std::memory_order_acquire);
int64_t oldval = v.load (std::memory_order_relaxed); int64_t newval = build (flagged (oldval), int62 (oldval) + n.val());
int64_t newval = build (flagged (oldval), int62 (oldval) + n.val()); while (!v.compare_exchange_weak (oldval, newval, std::memory_order_release, std::memory_order_relaxed)) {
if (v.compare_exchange_weak (oldval, newval)) { newval = build (flagged (oldval), int62 (oldval) + n.val());
break;
}
} }
return *this; return *this;
} }
int62_t& operator-= (int62_t n) { int62_t& operator-= (int62_t n) {
while (1) { int64_t oldval = v.load (std::memory_order_acquire);
int64_t oldval = v.load (std::memory_order_relaxed); int64_t newval = build (flagged (oldval), int62 (oldval) - n.val());
int64_t newval = build (flagged (oldval), int62 (oldval) - n.val()); while (!v.compare_exchange_weak (oldval, newval, std::memory_order_release, std::memory_order_relaxed)) {
if (v.compare_exchange_weak (oldval, newval)) { newval = build (flagged (oldval), int62 (oldval) - n.val());
break;
}
} }
return *this; return *this;
} }
int62_t& operator*= (int62_t n) { int62_t& operator*= (int62_t n) {
while (1) { int64_t oldval = v.load (std::memory_order_acquire);
int64_t oldval = v.load (std::memory_order_relaxed); int64_t newval = build (flagged (oldval), int62 (oldval) * n.val());
int64_t newval = build (flagged (oldval), int62 (oldval) * n.val()); while (!v.compare_exchange_weak (oldval, newval, std::memory_order_release, std::memory_order_relaxed)) {
if (v.compare_exchange_weak (oldval, newval)) { newval = build (flagged (oldval), int62 (oldval) * n.val());
break;
}
} }
return *this; return *this;
} }
int62_t& operator/= (int62_t n) { int62_t& operator/= (int62_t n) {
while (1) { int64_t oldval = v.load (std::memory_order_acquire);
int64_t oldval = v.load (std::memory_order_relaxed); int64_t newval = build (flagged (oldval), int62 (oldval) / n.val());
int64_t newval = build (flagged (oldval), int62 (oldval) / n.val()); while (!v.compare_exchange_weak (oldval, newval, std::memory_order_release, std::memory_order_relaxed)) {
if (v.compare_exchange_weak (oldval, newval)) { newval = build (flagged (oldval), int62 (oldval) / n.val());
break;
}
} }
return *this; return *this;
} }
int62_t& operator%= (int62_t n) { int62_t& operator%= (int62_t n) {
while (1) { int64_t oldval = v.load (std::memory_order_acquire);
int64_t oldval = v.load (std::memory_order_relaxed); int64_t newval = build (flagged (oldval), int62 (oldval) % n.val());
int64_t newval = build (flagged (oldval), int62 (oldval) % n.val()); while (!v.compare_exchange_weak (oldval, newval, std::memory_order_release, std::memory_order_relaxed)) {
if (v.compare_exchange_weak (oldval, newval)) { newval = build (flagged (oldval), int62 (oldval) % n.val());
break;
}
} }
return *this; return *this;
} }