From: Yap Zhi Heng <[email protected]>
Similar to rustc_codegen_gcc and libstdc++, we just generate a compare-exchange
loop for these functions as there is no equivalent implemented in gcc backend.
gcc/rust/ChangeLog:
* util/rust-intrinsic-values.h (Intrinsics): Add new entries for atomic
min/max function
names.
* backend/rust-intrinsic-handlers.h (inner::atomic_minmax): New
function for compiling
atomic min/max intrinsics.
(atomic_minmax): New function to handle atomic_min/max and their
variants.
* backend/rust-intrinsic-handlers.cc (inner:atomic_minmax): Implement.
(atomic_minmax): Implement.
* backend/rust-compile-intrinsic.cc (generic_intrinsics): Add entries
for the new atomic
min/max intrinsics.
* typecheck/rust-hir-type-check-intrinsic.cc (intrinsic_rules):
Likewise, but for type
checking.
Assisted-by: GPT-6.1 Sol (for testcases)
Signed-off-by: Yap Zhi Heng <[email protected]>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.
Commit on github:
https://github.com/Rust-GCC/gccrs/commit/21c66fcfebed0516403a5af99e3fea42986bfbf6
The commit has NOT been mentioned in any issue.
The commit has been mentioned in the following pull-request(s):
- https://github.com/Rust-GCC/gccrs/pull/4993
gcc/rust/backend/rust-compile-intrinsic.cc | 60 +++++
gcc/rust/backend/rust-intrinsic-handlers.cc | 96 ++++++++
gcc/rust/backend/rust-intrinsic-handlers.h | 11 +
.../rust-hir-type-check-intrinsic.cc | 41 ++++
gcc/rust/util/rust-intrinsic-values.h | 21 ++
gcc/testsuite/rust/compile/atomic_minmax.rs | 78 ++++++
.../rust/execute/torture/atomic_minmax.rs | 226 ++++++++++++++++++
7 files changed, 533 insertions(+)
create mode 100644 gcc/testsuite/rust/compile/atomic_minmax.rs
create mode 100644 gcc/testsuite/rust/execute/torture/atomic_minmax.rs
diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc
b/gcc/rust/backend/rust-compile-intrinsic.cc
index 151bda26f..5ebcec660 100644
--- a/gcc/rust/backend/rust-compile-intrinsic.cc
+++ b/gcc/rust/backend/rust-compile-intrinsic.cc
@@ -120,6 +120,66 @@ static const std::map<std::string, Intrinsic::CompileFn>
intrinsics = {
{IValue::ATOMIC_CXCHGWEAK_RELAXED,
handlers::atomic_compare_exchange (true, __ATOMIC_RELAXED,
__ATOMIC_RELAXED)},
+ {IValue::ATOMIC_MAX,
+ handlers::atomic_minmax (handlers::AtomicMinMaxKind::SignedMax,
+ __ATOMIC_SEQ_CST)},
+ {IValue::ATOMIC_MAX_ACQ,
+ handlers::atomic_minmax (handlers::AtomicMinMaxKind::SignedMax,
+ __ATOMIC_ACQUIRE)},
+ {IValue::ATOMIC_MAX_REL,
+ handlers::atomic_minmax (handlers::AtomicMinMaxKind::SignedMax,
+ __ATOMIC_RELEASE)},
+ {IValue::ATOMIC_MAX_ACQREL,
+ handlers::atomic_minmax (handlers::AtomicMinMaxKind::SignedMax,
+ __ATOMIC_ACQ_REL)},
+ {IValue::ATOMIC_MAX_RELAXED,
+ handlers::atomic_minmax (handlers::AtomicMinMaxKind::SignedMax,
+ __ATOMIC_RELAXED)},
+ {IValue::ATOMIC_UMAX,
+ handlers::atomic_minmax (handlers::AtomicMinMaxKind::UnsignedMax,
+ __ATOMIC_SEQ_CST)},
+ {IValue::ATOMIC_UMAX_ACQ,
+ handlers::atomic_minmax (handlers::AtomicMinMaxKind::UnsignedMax,
+ __ATOMIC_ACQUIRE)},
+ {IValue::ATOMIC_UMAX_REL,
+ handlers::atomic_minmax (handlers::AtomicMinMaxKind::UnsignedMax,
+ __ATOMIC_RELEASE)},
+ {IValue::ATOMIC_UMAX_ACQREL,
+ handlers::atomic_minmax (handlers::AtomicMinMaxKind::UnsignedMax,
+ __ATOMIC_ACQ_REL)},
+ {IValue::ATOMIC_UMAX_RELAXED,
+ handlers::atomic_minmax (handlers::AtomicMinMaxKind::UnsignedMax,
+ __ATOMIC_RELAXED)},
+ {IValue::ATOMIC_MIN,
+ handlers::atomic_minmax (handlers::AtomicMinMaxKind::SignedMin,
+ __ATOMIC_SEQ_CST)},
+ {IValue::ATOMIC_MIN_ACQ,
+ handlers::atomic_minmax (handlers::AtomicMinMaxKind::SignedMin,
+ __ATOMIC_ACQUIRE)},
+ {IValue::ATOMIC_MIN_REL,
+ handlers::atomic_minmax (handlers::AtomicMinMaxKind::SignedMin,
+ __ATOMIC_RELEASE)},
+ {IValue::ATOMIC_MIN_ACQREL,
+ handlers::atomic_minmax (handlers::AtomicMinMaxKind::SignedMin,
+ __ATOMIC_ACQ_REL)},
+ {IValue::ATOMIC_MIN_RELAXED,
+ handlers::atomic_minmax (handlers::AtomicMinMaxKind::SignedMin,
+ __ATOMIC_RELAXED)},
+ {IValue::ATOMIC_UMIN,
+ handlers::atomic_minmax (handlers::AtomicMinMaxKind::UnsignedMin,
+ __ATOMIC_SEQ_CST)},
+ {IValue::ATOMIC_UMIN_ACQ,
+ handlers::atomic_minmax (handlers::AtomicMinMaxKind::UnsignedMin,
+ __ATOMIC_ACQUIRE)},
+ {IValue::ATOMIC_UMIN_REL,
+ handlers::atomic_minmax (handlers::AtomicMinMaxKind::UnsignedMin,
+ __ATOMIC_RELEASE)},
+ {IValue::ATOMIC_UMIN_ACQREL,
+ handlers::atomic_minmax (handlers::AtomicMinMaxKind::UnsignedMin,
+ __ATOMIC_ACQ_REL)},
+ {IValue::ATOMIC_UMIN_RELAXED,
+ handlers::atomic_minmax (handlers::AtomicMinMaxKind::UnsignedMin,
+ __ATOMIC_RELAXED)},
{IValue::UNCHECKED_ADD, handlers::unchecked_op (PLUS_EXPR)},
{IValue::UNCHECKED_SUB, handlers::unchecked_op (MINUS_EXPR)},
{IValue::UNCHECKED_MUL, handlers::unchecked_op (MULT_EXPR)},
diff --git a/gcc/rust/backend/rust-intrinsic-handlers.cc
b/gcc/rust/backend/rust-intrinsic-handlers.cc
index 1beb7a2e9..84eb4cbbb 100644
--- a/gcc/rust/backend/rust-intrinsic-handlers.cc
+++ b/gcc/rust/backend/rust-intrinsic-handlers.cc
@@ -706,6 +706,94 @@ atomic_compare_exchange (IntrinsicCtx &ctx, bool weak, int
success_ordering,
ctx.add_statement (return_statement);
}
+// Compiles atomic min/max with signature (*mut T, T) -> T
+//
+// no gcc backend built-in equivalent, so we just do a compare-and-swap loop
+// similar to rustc_codegen_gcc & libstdc++.
+//
+// This is equivalent to the following code:
+//
+// T old_val = __atomic_load_N (dst, failure_order);
+// do
+// {
+// T desired = min_or_max (old_val, value);
+// if (__atomic_compare_exchange_N (dst, &old_val, desired, true,
+// order, failure_order))
+// break;
+// } while (true);
+// return old_val;
+void
+atomic_minmax (IntrinsicCtx &ctx, AtomicMinMaxKind kind, int ordering)
+{
+ // Most intrinsic functions are pure but not the atomic ones
+ TREE_READONLY (ctx.fn) = 0;
+ TREE_SIDE_EFFECTS (ctx.fn) = 1;
+
+ auto load_decl = resolve_atomic_builtin (ctx, "atomic_load");
+ if (!load_decl || load_decl == error_mark_node)
+ return;
+ auto exchange_decl = resolve_atomic_builtin (ctx, "atomic_compare_exchange");
+ if (!exchange_decl || exchange_decl == error_mark_node)
+ return;
+
+ auto dst = Backend::var_expression (ctx.param_vars[0], UNDEF_LOCATION);
+ TREE_READONLY (dst) = 0;
+ auto value = Backend::var_expression (ctx.param_vars[1], UNDEF_LOCATION);
+ auto value_type = ctx.param_types[1];
+
+ // release uses relaxed & acq_req uses acquire for loads on fail exchanges
+ int failure_ordering = ordering;
+ if (ordering == __ATOMIC_RELEASE)
+ failure_ordering = __ATOMIC_RELAXED;
+ else if (ordering == __ATOMIC_ACQ_REL)
+ failure_ordering = __ATOMIC_ACQUIRE;
+
+ auto failure_memorder = make_unsigned_long_tree (failure_ordering);
+ auto load_addr = build_fold_addr_expr_loc (UNDEF_LOCATION, load_decl);
+ auto load_call = Backend::call_expression (load_addr, {dst,
failure_memorder},
+ nullptr, UNDEF_LOCATION);
+ TREE_READONLY (load_call) = 0;
+ TREE_SIDE_EFFECTS (load_call) = 1;
+
+ tree tmp_stmt = NULL_TREE;
+ Bvariable *expected_var
+ = Backend::temporary_variable (ctx.fn, NULL_TREE, value_type, load_call,
+ true, UNDEF_LOCATION, &tmp_stmt);
+ ctx.add_statement (tmp_stmt);
+ auto expected = expected_var->get_tree (UNDEF_LOCATION);
+
+ bool is_unsigned = kind == AtomicMinMaxKind::UnsignedMax
+ || kind == AtomicMinMaxKind::UnsignedMin;
+ auto comparison_type = is_unsigned ? unsigned_type_for (value_type)
+ : signed_type_for (value_type);
+
+ // handle signedness irrespective of what the original type of the var is,
+ // in case users do things like using atomic_umin on signed types and expect
+ // it to work correctly
+ bool is_min = (kind == AtomicMinMaxKind::SignedMin
+ || kind == AtomicMinMaxKind::UnsignedMin);
+ auto desired = build2 (is_min ? MIN_EXPR : MAX_EXPR, comparison_type,
+ fold_convert (comparison_type, expected),
+ fold_convert (comparison_type, value));
+ desired = fold_convert (value_type, desired);
+
+ auto exchange_addr = build_fold_addr_expr_loc (UNDEF_LOCATION,
exchange_decl);
+ auto expected_addr = build_fold_addr_expr_loc (UNDEF_LOCATION, expected);
+ auto exchange_call
+ = Backend::call_expression (exchange_addr,
+ {dst, expected_addr, desired, boolean_true_node,
+ make_unsigned_long_tree (ordering),
+ failure_memorder},
+ nullptr, UNDEF_LOCATION);
+ TREE_READONLY (exchange_call) = 0;
+ TREE_SIDE_EFFECTS (exchange_call) = 1;
+
+ auto exit = Backend::exit_expression (exchange_call, UNDEF_LOCATION);
+ ctx.add_statement (Backend::loop_expression (exit, UNDEF_LOCATION));
+ ctx.add_statement (
+ Backend::return_statement (ctx.fn, expected, UNDEF_LOCATION));
+}
+
// Shared inner implementation for ctlz and ctlz_nonzero.
//
// nonzero=false → ctlz: ctlz(0) is well-defined in Rust and must return
@@ -1195,6 +1283,14 @@ atomic_compare_exchange (bool weak, int
success_ordering, int failure_ordering)
};
}
+Intrinsic::CompileFn
+atomic_minmax (AtomicMinMaxKind kind, int ordering)
+{
+ return [kind, ordering] (IntrinsicCtx &ctx) {
+ return inner::atomic_minmax (ctx, kind, ordering);
+ };
+}
+
Intrinsic::CompileFn
unchecked_op (tree_code op)
{
diff --git a/gcc/rust/backend/rust-intrinsic-handlers.h
b/gcc/rust/backend/rust-intrinsic-handlers.h
index a1f3aa03f..685612b2f 100644
--- a/gcc/rust/backend/rust-intrinsic-handlers.h
+++ b/gcc/rust/backend/rust-intrinsic-handlers.h
@@ -130,6 +130,14 @@ enum class TyAssert
namespace handlers {
+enum class AtomicMinMaxKind
+{
+ SignedMax,
+ SignedMin,
+ UnsignedMax,
+ UnsignedMin,
+};
+
namespace inner {
void wrapping_op (IntrinsicCtx &ctx, tree_code op);
@@ -139,6 +147,7 @@ void atomic_binary_op (IntrinsicCtx &ctx, const std::string
&op_name,
int ordering);
void atomic_compare_exchange (IntrinsicCtx &ctx, bool weak,
int success_ordering, int failure_ordering);
+void atomic_minmax (IntrinsicCtx &ctx, AtomicMinMaxKind kind, int ordering);
inline void copy (IntrinsicCtx &ctx, bool overlaps);
inline void expect (IntrinsicCtx &ctx, bool likely);
void try_handler (IntrinsicCtx &ctx, bool is_new_api);
@@ -203,6 +212,8 @@ Intrinsic::CompileFn atomic_or (int ordering);
Intrinsic::CompileFn atomic_xor (int ordering);
Intrinsic::CompileFn atomic_compare_exchange (bool weak, int success_ordering,
int failure_ordering);
+Intrinsic::CompileFn atomic_minmax (handlers::AtomicMinMaxKind kind,
+ int ordering);
Intrinsic::CompileFn unchecked_op (tree_code op);
diff --git a/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
b/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
index eccbe882a..8a632fae8 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
@@ -277,6 +277,47 @@ const std::unordered_map<std::string, IntrinsicRules>
// pub unsafe fn atomic_xor_relaxed<T: Copy>(dst: *mut T, val: T) -> T;
{IValue::ATOMIC_XOR_RELAXED,
{1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+ // fn atomic_[u]min/max<T>(dst: *mut T, val: T) -> T;
+ {IValue::ATOMIC_MIN,
+ {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+ {IValue::ATOMIC_MIN_ACQ,
+ {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+ {IValue::ATOMIC_MIN_REL,
+ {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+ {IValue::ATOMIC_MIN_ACQREL,
+ {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+ {IValue::ATOMIC_MIN_RELAXED,
+ {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+ {IValue::ATOMIC_MAX,
+ {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+ {IValue::ATOMIC_MAX_ACQ,
+ {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+ {IValue::ATOMIC_MAX_REL,
+ {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+ {IValue::ATOMIC_MAX_ACQREL,
+ {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+ {IValue::ATOMIC_MAX_RELAXED,
+ {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+ {IValue::ATOMIC_UMIN,
+ {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+ {IValue::ATOMIC_UMIN_ACQ,
+ {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+ {IValue::ATOMIC_UMIN_REL,
+ {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+ {IValue::ATOMIC_UMIN_ACQREL,
+ {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+ {IValue::ATOMIC_UMIN_RELAXED,
+ {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+ {IValue::ATOMIC_UMAX,
+ {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+ {IValue::ATOMIC_UMAX_ACQ,
+ {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+ {IValue::ATOMIC_UMAX_REL,
+ {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+ {IValue::ATOMIC_UMAX_ACQREL,
+ {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+ {IValue::ATOMIC_UMAX_RELAXED,
+ {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
// fn atomic_cxchg[weak]*<T>(dst: *mut T, old: T, new: T) -> (T, bool);
{IValue::ATOMIC_CXCHG,
{1,
diff --git a/gcc/rust/util/rust-intrinsic-values.h
b/gcc/rust/util/rust-intrinsic-values.h
index 06d3469e5..37f61f8cb 100644
--- a/gcc/rust/util/rust-intrinsic-values.h
+++ b/gcc/rust/util/rust-intrinsic-values.h
@@ -151,6 +151,27 @@ public:
static constexpr auto &ATOMIC_XOR_ACQREL = "atomic_xor_acqrel";
static constexpr auto &ATOMIC_XOR_RELAXED = "atomic_xor_relaxed";
+ static constexpr auto &ATOMIC_MIN = "atomic_min";
+ static constexpr auto &ATOMIC_MIN_ACQ = "atomic_min_acq";
+ static constexpr auto &ATOMIC_MIN_REL = "atomic_min_rel";
+ static constexpr auto &ATOMIC_MIN_ACQREL = "atomic_min_acqrel";
+ static constexpr auto &ATOMIC_MIN_RELAXED = "atomic_min_relaxed";
+ static constexpr auto &ATOMIC_MAX = "atomic_max";
+ static constexpr auto &ATOMIC_MAX_ACQ = "atomic_max_acq";
+ static constexpr auto &ATOMIC_MAX_REL = "atomic_max_rel";
+ static constexpr auto &ATOMIC_MAX_ACQREL = "atomic_max_acqrel";
+ static constexpr auto &ATOMIC_MAX_RELAXED = "atomic_max_relaxed";
+ static constexpr auto &ATOMIC_UMIN = "atomic_umin";
+ static constexpr auto &ATOMIC_UMIN_ACQ = "atomic_umin_acq";
+ static constexpr auto &ATOMIC_UMIN_REL = "atomic_umin_rel";
+ static constexpr auto &ATOMIC_UMIN_ACQREL = "atomic_umin_acqrel";
+ static constexpr auto &ATOMIC_UMIN_RELAXED = "atomic_umin_relaxed";
+ static constexpr auto &ATOMIC_UMAX = "atomic_umax";
+ static constexpr auto &ATOMIC_UMAX_ACQ = "atomic_umax_acq";
+ static constexpr auto &ATOMIC_UMAX_REL = "atomic_umax_rel";
+ static constexpr auto &ATOMIC_UMAX_ACQREL = "atomic_umax_acqrel";
+ static constexpr auto &ATOMIC_UMAX_RELAXED = "atomic_umax_relaxed";
+
static constexpr auto &ATOMIC_CXCHG = "atomic_cxchg";
static constexpr auto &ATOMIC_CXCHG_ACQ = "atomic_cxchg_acq";
static constexpr auto &ATOMIC_CXCHG_REL = "atomic_cxchg_rel";
diff --git a/gcc/testsuite/rust/compile/atomic_minmax.rs
b/gcc/testsuite/rust/compile/atomic_minmax.rs
new file mode 100644
index 000000000..4ae47a377
--- /dev/null
+++ b/gcc/testsuite/rust/compile/atomic_minmax.rs
@@ -0,0 +1,78 @@
+#![feature(no_core)]
+#![no_core]
+
+#![feature(intrinsics)]
+
+#![feature(lang_items)]
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "clone"]
+pub trait Clone: Sized {
+ fn clone(&self) -> Self;
+
+ fn clone_from(&mut self, source: &Self) {
+ *self = source.clone()
+ }
+}
+
+mod impls {
+ use super::Clone;
+
+ macro_rules! impl_clone {
+ ($($t:ty)*) => {
+ $(
+ impl Clone for $t {
+ fn clone(&self) -> Self {
+ *self
+ }
+ }
+ )*
+ }
+ }
+
+ impl_clone! {
+ usize u8 u16 u32 u64 // u128
+ isize i8 i16 i32 i64 // i128
+ f32 f64
+ bool char
+ }
+}
+
+#[lang = "copy"]
+pub trait Copy: Clone {
+ // Empty.
+}
+
+mod copy_impls {
+ use super::Copy;
+
+ macro_rules! impl_copy {
+ ($($t:ty)*) => {
+ $(
+ impl Copy for $t {}
+ )*
+ }
+ }
+
+ impl_copy! {
+ usize u8 u16 u32 u64 // u128
+ isize i8 i16 i32 i64 // i128
+ f32 f64
+ bool char
+ }
+}
+
+extern "rust-intrinsic" {
+ fn atomic_min<T>(dst: *mut T, val: T) -> T;
+ fn atomic_umax<T>(dst: *mut T, val: T) -> T;
+}
+
+fn main() {
+ let mut flag = true;
+ let mut value = 1.0f32;
+ unsafe {
+ atomic_min(&mut flag, false); // { dg-error "atomic operation
intrinsic can only be used with basic integer types .got .bool.." }
+ atomic_umax(&mut value, 2.0f32); // { dg-error "atomic operation
intrinsic can only be used with basic integer types .got .f32.." }
+ }
+}
diff --git a/gcc/testsuite/rust/execute/torture/atomic_minmax.rs
b/gcc/testsuite/rust/execute/torture/atomic_minmax.rs
new file mode 100644
index 000000000..0135a6fe7
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/atomic_minmax.rs
@@ -0,0 +1,226 @@
+#![feature(no_core)]
+#![no_core]
+
+#![feature(intrinsics)]
+
+#![feature(lang_items)]
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "clone"]
+pub trait Clone: Sized {
+ fn clone(&self) -> Self;
+
+ fn clone_from(&mut self, source: &Self) {
+ *self = source.clone()
+ }
+}
+
+mod impls {
+ use super::Clone;
+
+ macro_rules! impl_clone {
+ ($($t:ty)*) => {
+ $(
+ impl Clone for $t {
+ fn clone(&self) -> Self {
+ *self
+ }
+ }
+ )*
+ }
+ }
+
+ impl_clone! {
+ usize u8 u16 u32 u64 // u128
+ isize i8 i16 i32 i64 // i128
+ f32 f64
+ bool char
+ }
+}
+
+#[lang = "copy"]
+pub trait Copy: Clone {
+ // Empty.
+}
+
+mod copy_impls {
+ use super::Copy;
+
+ macro_rules! impl_copy {
+ ($($t:ty)*) => {
+ $(
+ impl Copy for $t {}
+ )*
+ }
+ }
+
+ impl_copy! {
+ usize u8 u16 u32 u64 // u128
+ isize i8 i16 i32 i64 // i128
+ f32 f64
+ bool char
+ }
+}
+
+extern "rust-intrinsic" {
+ pub fn atomic_min<T: Copy>(dst: *mut T, val: T) -> T;
+ pub fn atomic_min_acq<T: Copy>(dst: *mut T, val: T) -> T;
+ pub fn atomic_min_rel<T: Copy>(dst: *mut T, val: T) -> T;
+ pub fn atomic_min_acqrel<T: Copy>(dst: *mut T, val: T) -> T;
+ pub fn atomic_min_relaxed<T: Copy>(dst: *mut T, val: T) -> T;
+ pub fn atomic_max<T: Copy>(dst: *mut T, val: T) -> T;
+ pub fn atomic_max_acq<T: Copy>(dst: *mut T, val: T) -> T;
+ pub fn atomic_max_rel<T: Copy>(dst: *mut T, val: T) -> T;
+ pub fn atomic_max_acqrel<T: Copy>(dst: *mut T, val: T) -> T;
+ pub fn atomic_max_relaxed<T: Copy>(dst: *mut T, val: T) -> T;
+ pub fn atomic_umin<T: Copy>(dst: *mut T, val: T) -> T;
+ pub fn atomic_umin_acq<T: Copy>(dst: *mut T, val: T) -> T;
+ pub fn atomic_umin_rel<T: Copy>(dst: *mut T, val: T) -> T;
+ pub fn atomic_umin_acqrel<T: Copy>(dst: *mut T, val: T) -> T;
+ pub fn atomic_umin_relaxed<T: Copy>(dst: *mut T, val: T) -> T;
+ pub fn atomic_umax<T: Copy>(dst: *mut T, val: T) -> T;
+ pub fn atomic_umax_acq<T: Copy>(dst: *mut T, val: T) -> T;
+ pub fn atomic_umax_rel<T: Copy>(dst: *mut T, val: T) -> T;
+ pub fn atomic_umax_acqrel<T: Copy>(dst: *mut T, val: T) -> T;
+ pub fn atomic_umax_relaxed<T: Copy>(dst: *mut T, val: T) -> T;
+}
+
+fn main() -> u32 {
+ unsafe {
+ let mut src = 9i8;
+
+ let old = atomic_min(&mut src, -7);
+ if old != 9 || src != -7 {
+ return 1;
+ }
+
+ let old = atomic_min_acq(&mut src, 9);
+ if old != -7 || src != -7 {
+ return 1;
+ }
+
+ let old = atomic_min_rel(&mut src, -9);
+ if old != -7 || src != -9 {
+ return 1;
+ }
+
+ let old = atomic_min_acqrel(&mut src, -9);
+ if old != -9 || src != -9 {
+ return 1;
+ }
+
+ let old = atomic_min_relaxed(&mut src, -10);
+ if old != -9 || src != -10 {
+ return 1;
+ }
+
+ let mut src = -7i8;
+
+ let old = atomic_max(&mut src, 9);
+ if old != -7 || src != 9 {
+ return 1;
+ }
+
+ let old = atomic_max_acq(&mut src, -7);
+ if old != 9 || src != 9 {
+ return 1;
+ }
+
+ let old = atomic_max_rel(&mut src, 10);
+ if old != 9 || src != 10 {
+ return 1;
+ }
+
+ let old = atomic_max_acqrel(&mut src, 10);
+ if old != 10 || src != 10 {
+ return 1;
+ }
+
+ let old = atomic_max_relaxed(&mut src, 11);
+ if old != 10 || src != 11 {
+ return 1;
+ }
+
+ let mut src = 249u8;
+
+ let old = atomic_umin(&mut src, 9);
+ if old != 249 || src != 9 {
+ return 1;
+ }
+
+ let old = atomic_umin_acq(&mut src, 249);
+ if old != 9 || src != 9 {
+ return 1;
+ }
+
+ let old = atomic_umin_rel(&mut src, 7);
+ if old != 9 || src != 7 {
+ return 1;
+ }
+
+ let old = atomic_umin_acqrel(&mut src, 7);
+ if old != 7 || src != 7 {
+ return 1;
+ }
+
+ let old = atomic_umin_relaxed(&mut src, 6);
+ if old != 7 || src != 6 {
+ return 1;
+ }
+
+ let mut src = 9u8;
+
+ let old = atomic_umax(&mut src, 249);
+ if old != 9 || src != 249 {
+ return 1;
+ }
+
+ let old = atomic_umax_acq(&mut src, 9);
+ if old != 249 || src != 249 {
+ return 1;
+ }
+
+ let old = atomic_umax_rel(&mut src, 250);
+ if old != 249 || src != 250 {
+ return 1;
+ }
+
+ let old = atomic_umax_acqrel(&mut src, 250);
+ if old != 250 || src != 250 {
+ return 1;
+ }
+
+ let old = atomic_umax_relaxed(&mut src, 251);
+ if old != 250 || src != 251 {
+ return 1;
+ }
+
+ // funny non-matching signedness tests below
+ let mut src = 128u8;
+
+ let old = atomic_min(&mut src, 7);
+ if old != 128 || src != 128 {
+ return 1;
+ }
+
+ let old = atomic_max(&mut src, 7);
+ if old != 128 || src != 7 {
+ return 1;
+ }
+
+ let mut src = 7i8;
+
+ let old = atomic_umax(&mut src, -128);
+ if old != 7 || src != -128 {
+ return 1;
+ }
+
+ let old = atomic_umin(&mut src, 7);
+ if old != -128 || src != 7 {
+ return 1;
+ }
+ }
+
+ 0
+}
--
2.56.0