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
1 changed files with 56 additions and 76 deletions

View File

@ -59,7 +59,7 @@ class alignas(16) int62_t {
int62_t () : v (0) {}
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 min = -2305843009213693952;
@ -67,8 +67,8 @@ class alignas(16) int62_t {
bool flagged() const { return flagged (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= (int62_t const & other) { v.store (other.v.load()); 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(std::memory_order_acquire), std::memory_order_release); return *this; }
/* 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".
*/
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(); 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(); 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(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(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(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(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(); 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(); 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(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(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(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(std::memory_order_acquire); return int62_t (flagged (vv), int62 (vv) % n.val()); }
/* comparison operators .. will throw if the two objects have different
* 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
*/
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(); 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 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 false; return int62 (vv) == other.val(); }
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& operator+= (int64_t n) {
while (1) {
int64_t oldval = v.load (std::memory_order_relaxed);
int64_t newval = build (flagged (oldval), int62 (oldval) + n);
if (v.compare_exchange_weak (oldval, newval)) {
break;
}
int64_t oldval = v.load (std::memory_order_acquire);
int64_t newval = build (flagged (oldval), int62 (oldval) + n);
while (!v.compare_exchange_weak (oldval, newval, std::memory_order_release, std::memory_order_relaxed)) {
newval = build (flagged (oldval), int62 (oldval) + n);
}
return *this;
}
int62_t& operator-= (int64_t n) {
while (1) {
int64_t oldval = v.load (std::memory_order_relaxed);
int64_t newval = build (flagged (oldval), int62 (oldval) - n);
if (v.compare_exchange_weak (oldval, newval)) {
break;
}
int64_t oldval = v.load (std::memory_order_acquire);
int64_t newval = build (flagged (oldval), int62 (oldval) - n);
while (!v.compare_exchange_weak (oldval, newval, std::memory_order_release, std::memory_order_relaxed)) {
newval = build (flagged (oldval), int62 (oldval) - n);
}
return *this;
}
int62_t& operator*= (int64_t n) {
while (1) {
int64_t oldval = v.load (std::memory_order_relaxed);
int64_t newval = build (flagged (oldval), int62 (oldval) * n);
if (v.compare_exchange_weak (oldval, newval)) {
break;
}
int64_t oldval = v.load (std::memory_order_acquire);
int64_t newval = build (flagged (oldval), int62 (oldval) * n);
while (!v.compare_exchange_weak (oldval, newval, std::memory_order_release, std::memory_order_relaxed)) {
newval = build (flagged (oldval), int62 (oldval) * n);
}
return *this;
}
int62_t& operator/= (int64_t n) {
while (1) {
int64_t oldval = v.load (std::memory_order_relaxed);
int64_t newval = build (flagged (oldval), int62 (oldval) / n);
if (v.compare_exchange_weak (oldval, newval)) {
break;
}
int64_t oldval = v.load (std::memory_order_acquire);
int64_t newval = build (flagged (oldval), int62 (oldval) / n);
while (!v.compare_exchange_weak (oldval, newval, std::memory_order_release, std::memory_order_relaxed)) {
newval = build (flagged (oldval), int62 (oldval) / n);
}
return *this;
}
int62_t& operator%= (int64_t n) {
while (1) {
int64_t oldval = v.load (std::memory_order_relaxed);
int64_t newval = build (flagged (oldval), int62 (oldval) % n);
if (v.compare_exchange_weak (oldval, newval)) {
break;
}
int64_t oldval = v.load (std::memory_order_acquire);
int64_t newval = build (flagged (oldval), int62 (oldval) % n);
while (!v.compare_exchange_weak (oldval, newval, std::memory_order_release, std::memory_order_relaxed)) {
newval = build (flagged (oldval), int62 (oldval) % n);
}
return *this;
}
int62_t& operator+= (int62_t n) {
while (1) {
int64_t oldval = v.load (std::memory_order_relaxed);
int64_t newval = build (flagged (oldval), int62 (oldval) + n.val());
if (v.compare_exchange_weak (oldval, newval)) {
break;
}
int64_t oldval = v.load (std::memory_order_acquire);
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)) {
newval = build (flagged (oldval), int62 (oldval) + n.val());
}
return *this;
}
int62_t& operator-= (int62_t n) {
while (1) {
int64_t oldval = v.load (std::memory_order_relaxed);
int64_t newval = build (flagged (oldval), int62 (oldval) - n.val());
if (v.compare_exchange_weak (oldval, newval)) {
break;
}
int64_t oldval = v.load (std::memory_order_acquire);
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)) {
newval = build (flagged (oldval), int62 (oldval) - n.val());
}
return *this;
}
int62_t& operator*= (int62_t n) {
while (1) {
int64_t oldval = v.load (std::memory_order_relaxed);
int64_t newval = build (flagged (oldval), int62 (oldval) * n.val());
if (v.compare_exchange_weak (oldval, newval)) {
break;
}
int64_t oldval = v.load (std::memory_order_acquire);
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)) {
newval = build (flagged (oldval), int62 (oldval) * n.val());
}
return *this;
}
int62_t& operator/= (int62_t n) {
while (1) {
int64_t oldval = v.load (std::memory_order_relaxed);
int64_t newval = build (flagged (oldval), int62 (oldval) / n.val());
if (v.compare_exchange_weak (oldval, newval)) {
break;
}
int64_t oldval = v.load (std::memory_order_acquire);
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)) {
newval = build (flagged (oldval), int62 (oldval) / n.val());
}
return *this;
}
int62_t& operator%= (int62_t n) {
while (1) {
int64_t oldval = v.load (std::memory_order_relaxed);
int64_t newval = build (flagged (oldval), int62 (oldval) % n.val());
if (v.compare_exchange_weak (oldval, newval)) {
break;
}
int64_t oldval = v.load (std::memory_order_acquire);
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)) {
newval = build (flagged (oldval), int62 (oldval) % n.val());
}
return *this;
}