From: Yap Zhi Heng <[email protected]>

gcc/rust/ChangeLog:

        * util/rust-intrinsic-values.h (Intrinsics): Add new entries for atomic 
binary op
        function names.
        * backend/rust-intrinsic-handlers.h (inner::atomic_binary_op): New 
function for compiling
        atomic binary op intrinsics.
        (atomic_xadd): New function to handle atomic_xadd and its variants.
        (atomic_xsub): New function to handle atomic_xsub and its variants.
        (atomic_and): New function to handle atomic_and and its variants.
        (atomic_nand): New function to handle atomic_nand and its variants.
        (atomic_or): New function to handle atomic_or and its variants.
        (atomic_xor): New function to handle atomic_xor and its variants.
        * backend/rust-intrinsic-handlers.cc (resolve_atomic_builtin): Renamed 
and repurposed from
        build_atomic_builtin_name, now directly resolves the tree of the atomic 
builtin.
        (inner::atomic_store): Add new assert for return type.
        (inner::atomic_load): Likewise.
        (inner::atomic_binary_op): Implement.
        (atomic_xadd): Implement.
        (atomic_xsub): Implement.
        (atomic_and): Implement
        (atomic_nand): Implement.
        (atomic_or): Implement.
        (atomic_xor): Implement.
        * backend/rust-compile-intrinsic.cc (generic_intrinsics): Add entries 
for the new atomic
        binary op intrinsics.
        * typecheck/rust-hir-type-check-intrinsic.cc (intrinsic_rules): 
Likewise, but for type
        checking.

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/a0e912a0e134b18e2001ff01560860571a2cac47

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    |  30 ++++
 gcc/rust/backend/rust-intrinsic-handlers.cc   | 168 ++++++++++++------
 gcc/rust/backend/rust-intrinsic-handlers.h    |   9 +
 .../rust-hir-type-check-intrinsic.cc          |  90 ++++++++++
 gcc/rust/util/rust-intrinsic-values.h         |  31 ++++
 .../rust/execute/torture/atomic_and.rs        | 105 +++++++++++
 .../rust/execute/torture/atomic_nand.rs       | 105 +++++++++++
 .../rust/execute/torture/atomic_or.rs         | 105 +++++++++++
 .../rust/execute/torture/atomic_xadd.rs       |  95 ++++++++++
 .../rust/execute/torture/atomic_xor.rs        | 105 +++++++++++
 .../rust/execute/torture/atomic_xsub.rs       |  95 ++++++++++
 11 files changed, 880 insertions(+), 58 deletions(-)
 create mode 100644 gcc/testsuite/rust/execute/torture/atomic_and.rs
 create mode 100644 gcc/testsuite/rust/execute/torture/atomic_nand.rs
 create mode 100644 gcc/testsuite/rust/execute/torture/atomic_or.rs
 create mode 100644 gcc/testsuite/rust/execute/torture/atomic_xadd.rs
 create mode 100644 gcc/testsuite/rust/execute/torture/atomic_xor.rs
 create mode 100644 gcc/testsuite/rust/execute/torture/atomic_xsub.rs

diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc 
b/gcc/rust/backend/rust-compile-intrinsic.cc
index 881c03cc6..dab7f67d0 100644
--- a/gcc/rust/backend/rust-compile-intrinsic.cc
+++ b/gcc/rust/backend/rust-compile-intrinsic.cc
@@ -60,6 +60,36 @@ static const std::map<std::string, Intrinsic::CompileFn> 
intrinsics = {
   {IValue::ATOMIC_LOAD_ACQUIRE, handlers::atomic_load (__ATOMIC_ACQUIRE)},
   {IValue::ATOMIC_LOAD_RELAXED, handlers::atomic_load (__ATOMIC_RELAXED)},
   {IValue::ATOMIC_LOAD_UNORDERED, handlers::atomic_load (__ATOMIC_RELAXED)},
+  {IValue::ATOMIC_XADD, handlers::atomic_xadd (__ATOMIC_SEQ_CST)},
+  {IValue::ATOMIC_XADD_ACQ, handlers::atomic_xadd (__ATOMIC_ACQUIRE)},
+  {IValue::ATOMIC_XADD_REL, handlers::atomic_xadd (__ATOMIC_RELEASE)},
+  {IValue::ATOMIC_XADD_ACQREL, handlers::atomic_xadd (__ATOMIC_ACQ_REL)},
+  {IValue::ATOMIC_XADD_RELAXED, handlers::atomic_xadd (__ATOMIC_RELAXED)},
+  {IValue::ATOMIC_XSUB, handlers::atomic_xsub (__ATOMIC_SEQ_CST)},
+  {IValue::ATOMIC_XSUB_ACQ, handlers::atomic_xsub (__ATOMIC_ACQUIRE)},
+  {IValue::ATOMIC_XSUB_REL, handlers::atomic_xsub (__ATOMIC_RELEASE)},
+  {IValue::ATOMIC_XSUB_ACQREL, handlers::atomic_xsub (__ATOMIC_ACQ_REL)},
+  {IValue::ATOMIC_XSUB_RELAXED, handlers::atomic_xsub (__ATOMIC_RELAXED)},
+  {IValue::ATOMIC_AND, handlers::atomic_and (__ATOMIC_SEQ_CST)},
+  {IValue::ATOMIC_AND_ACQ, handlers::atomic_and (__ATOMIC_ACQUIRE)},
+  {IValue::ATOMIC_AND_REL, handlers::atomic_and (__ATOMIC_RELEASE)},
+  {IValue::ATOMIC_AND_ACQREL, handlers::atomic_and (__ATOMIC_ACQ_REL)},
+  {IValue::ATOMIC_AND_RELAXED, handlers::atomic_and (__ATOMIC_RELAXED)},
+  {IValue::ATOMIC_NAND, handlers::atomic_nand (__ATOMIC_SEQ_CST)},
+  {IValue::ATOMIC_NAND_ACQ, handlers::atomic_nand (__ATOMIC_ACQUIRE)},
+  {IValue::ATOMIC_NAND_REL, handlers::atomic_nand (__ATOMIC_RELEASE)},
+  {IValue::ATOMIC_NAND_ACQREL, handlers::atomic_nand (__ATOMIC_ACQ_REL)},
+  {IValue::ATOMIC_NAND_RELAXED, handlers::atomic_nand (__ATOMIC_RELAXED)},
+  {IValue::ATOMIC_OR, handlers::atomic_or (__ATOMIC_SEQ_CST)},
+  {IValue::ATOMIC_OR_ACQ, handlers::atomic_or (__ATOMIC_ACQUIRE)},
+  {IValue::ATOMIC_OR_REL, handlers::atomic_or (__ATOMIC_RELEASE)},
+  {IValue::ATOMIC_OR_ACQREL, handlers::atomic_or (__ATOMIC_ACQ_REL)},
+  {IValue::ATOMIC_OR_RELAXED, handlers::atomic_or (__ATOMIC_RELAXED)},
+  {IValue::ATOMIC_XOR, handlers::atomic_xor (__ATOMIC_SEQ_CST)},
+  {IValue::ATOMIC_XOR_ACQ, handlers::atomic_xor (__ATOMIC_ACQUIRE)},
+  {IValue::ATOMIC_XOR_REL, handlers::atomic_xor (__ATOMIC_RELEASE)},
+  {IValue::ATOMIC_XOR_ACQREL, handlers::atomic_xor (__ATOMIC_ACQ_REL)},
+  {IValue::ATOMIC_XOR_RELAXED, handlers::atomic_xor (__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 034d28044..b15e4a539 100644
--- a/gcc/rust/backend/rust-intrinsic-handlers.cc
+++ b/gcc/rust/backend/rust-intrinsic-handlers.cc
@@ -246,44 +246,35 @@ get_inner_dst (TyTy::BaseType *type)
 namespace handlers {
 namespace inner {
 
-static std::string
-build_atomic_builtin_name (const std::string &prefix, location_t locus,
-                          TyTy::BaseType *operand_type)
-{
-  static const std::map<std::string, std::string> allowed_types = {
-    {"i8", "1"},    {"i16", "2"},   {"i32", "4"},   {"i64", "8"},
-    {"i128", "16"}, {"isize", "8"}, {"u8", "1"},    {"u16", "2"},
-    {"u32", "4"},   {"u64", "8"},   {"u128", "16"}, {"usize", "8"},
-  };
-
-  // TODO: Can we maybe get the generic version (atomic_store_n) to work... 
This
-  // would be so much better
+static tree
+resolve_atomic_builtin (IntrinsicCtx &ctx, const std::string &prefix)
+{
+  auto locus = ctx.get_mappings ().lookup_location (ctx.fntype.get_ref ());
+  auto operand_type = ctx.fntype.get_substs ()[0].get_param_ty ()->resolve ();
 
-  std::string result = "__" + prefix; //  + "n";
+  if (!check_for_basic_integer_type ("atomic operation", locus, operand_type))
+    return error_mark_node;
 
-  auto type_name = operand_type->get_name ();
-  if (type_name == "usize" || type_name == "isize")
-    {
-      rust_sorry_at (
-       locus, "atomics are not yet available for size types (usize, isize)");
-      return "";
-    }
+  tree operand_type_tree
+    = TyTyResolveCompile::compile (ctx.inner (), operand_type);
+  if (operand_type_tree == error_mark_node)
+    return error_mark_node;
 
-  if (type_name.at (0) == 'i')
+  operand_type_tree = TYPE_MAIN_VARIANT (operand_type_tree);
+  if (TREE_CODE (operand_type_tree) != INTEGER_TYPE)
     {
-      rust_sorry_at (locus, "atomics are not yet supported for signed "
-                           "integer types (i8, i16, i32, i64, i128)");
-      return "";
+      rust_error_at (locus, "atomic operation requires an integer type");
+      return error_mark_node;
     }
 
-  auto type_size_str = allowed_types.find (type_name);
+  HOST_WIDE_INT bytes = int_size_in_bytes (operand_type_tree);
 
-  if (!check_for_basic_integer_type ("atomic operation", locus, operand_type))
-    return "";
+  std::string builtin_name = "__" + prefix + "_" + std::to_string (bytes);
 
-  result += type_size_str->second;
+  auto decl = BuiltinsContext::get ().lookup_simple_builtin (builtin_name);
+  rust_assert (decl);
 
-  return result;
+  return decl.value ();
 }
 
 inline void
@@ -554,6 +545,7 @@ copy (IntrinsicCtx &ctx, bool overlaps)
   ctx.add_statement (copy_call);
 }
 
+// Compiles atomic_store that has the signature (*mut T, T) -> ()
 void
 atomic_store (IntrinsicCtx &ctx, int ordering)
 {
@@ -569,23 +561,11 @@ atomic_store (IntrinsicCtx &ctx, int ordering)
   auto value = Backend::var_expression (ctx.param_vars[1], UNDEF_LOCATION);
   auto memorder = make_unsigned_long_tree (ordering);
 
-  auto monomorphized_type
-    = ctx.fntype.get_substs ()[0].get_param_ty ()->resolve ();
-
-  auto call_locus = ctx.get_mappings ().lookup_location (ctx.fntype.get_ref 
());
-  auto builtin_name = build_atomic_builtin_name ("atomic_store_", call_locus,
-                                                monomorphized_type);
-
-  if (builtin_name.empty ())
+  auto builtin_decl = resolve_atomic_builtin (ctx, "atomic_store");
+  if (!builtin_decl || builtin_decl == error_mark_node)
     return;
 
-  auto atomic_store_raw
-    = BuiltinsContext::get ().lookup_simple_builtin (builtin_name);
-
-  rust_assert (atomic_store_raw);
-
-  auto atomic_store
-    = build_fold_addr_expr_loc (UNKNOWN_LOCATION, *atomic_store_raw);
+  auto atomic_store = build_fold_addr_expr_loc (UNKNOWN_LOCATION, 
builtin_decl);
 
   auto store_call
     = Backend::call_expression (atomic_store, {dst, value, memorder}, nullptr,
@@ -596,6 +576,7 @@ atomic_store (IntrinsicCtx &ctx, int ordering)
   ctx.add_statement (store_call);
 }
 
+// Compiles atomic_load that has the signature (*const T) -> T
 void
 atomic_load (IntrinsicCtx &ctx, int ordering)
 {
@@ -609,22 +590,11 @@ atomic_load (IntrinsicCtx &ctx, int ordering)
   auto src = Backend::var_expression (ctx.param_vars[0], UNDEF_LOCATION);
   auto memorder = make_unsigned_long_tree (ordering);
 
-  auto monomorphized_type
-    = ctx.fntype.get_substs ()[0].get_param_ty ()->resolve ();
-
-  auto builtin_name
-    = build_atomic_builtin_name ("atomic_load_", ctx.fntype.get_locus (),
-                                monomorphized_type);
-
-  if (builtin_name.empty ())
+  auto builtin_decl = resolve_atomic_builtin (ctx, "atomic_load");
+  if (!builtin_decl || builtin_decl == error_mark_node)
     return;
 
-  auto atomic_load_raw
-    = BuiltinsContext::get ().lookup_simple_builtin (builtin_name);
-  rust_assert (atomic_load_raw);
-
-  auto atomic_load
-    = build_fold_addr_expr_loc (UNKNOWN_LOCATION, *atomic_load_raw);
+  auto atomic_load = build_fold_addr_expr_loc (UNKNOWN_LOCATION, builtin_decl);
 
   auto load_call = Backend::call_expression (atomic_load, {src, memorder},
                                             nullptr, UNDEF_LOCATION);
@@ -637,6 +607,40 @@ atomic_load (IntrinsicCtx &ctx, int ordering)
   ctx.add_statement (return_statement);
 }
 
+// Compiles for atomic builtins that have the signature (*mut T, T) -> T
+void
+atomic_binary_op (IntrinsicCtx &ctx, const std::string &op_name, int ordering)
+{
+  // Most intrinsic functions are pure but not the atomic ones
+  TREE_READONLY (ctx.fn) = 0;
+  TREE_SIDE_EFFECTS (ctx.fn) = 1;
+
+  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 memorder = make_unsigned_long_tree (ordering);
+
+  auto builtin_decl = resolve_atomic_builtin (ctx, "atomic_" + op_name);
+
+  if (!builtin_decl || builtin_decl == error_mark_node)
+    return;
+
+  auto atomic_binary_op
+    = build_fold_addr_expr_loc (UNKNOWN_LOCATION, builtin_decl);
+
+  auto binary_op_call
+    = Backend::call_expression (atomic_binary_op, {dst, value, memorder},
+                               nullptr, UNDEF_LOCATION);
+
+  TREE_READONLY (binary_op_call) = 0;
+  TREE_SIDE_EFFECTS (binary_op_call) = 1;
+
+  auto return_statement
+    = Backend::return_statement (ctx.fn, binary_op_call, UNDEF_LOCATION);
+  ctx.add_statement (return_statement);
+}
+
 // Shared inner implementation for ctlz and ctlz_nonzero.
 //
 // nonzero=false → ctlz: ctlz(0) is well-defined in Rust and must return
@@ -1070,6 +1074,54 @@ atomic_load (int ordering)
   };
 }
 
+Intrinsic::CompileFn
+atomic_xadd (int ordering)
+{
+  return [ordering] (IntrinsicCtx &ctx) {
+    return inner::atomic_binary_op (ctx, "fetch_add", ordering);
+  };
+}
+
+Intrinsic::CompileFn
+atomic_xsub (int ordering)
+{
+  return [ordering] (IntrinsicCtx &ctx) {
+    return inner::atomic_binary_op (ctx, "fetch_sub", ordering);
+  };
+}
+
+Intrinsic::CompileFn
+atomic_and (int ordering)
+{
+  return [ordering] (IntrinsicCtx &ctx) {
+    return inner::atomic_binary_op (ctx, "fetch_and", ordering);
+  };
+}
+
+Intrinsic::CompileFn
+atomic_nand (int ordering)
+{
+  return [ordering] (IntrinsicCtx &ctx) {
+    return inner::atomic_binary_op (ctx, "fetch_nand", ordering);
+  };
+}
+
+Intrinsic::CompileFn
+atomic_or (int ordering)
+{
+  return [ordering] (IntrinsicCtx &ctx) {
+    return inner::atomic_binary_op (ctx, "fetch_or", ordering);
+  };
+}
+
+Intrinsic::CompileFn
+atomic_xor (int ordering)
+{
+  return [ordering] (IntrinsicCtx &ctx) {
+    return inner::atomic_binary_op (ctx, "fetch_xor", 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 68fdec129..3bd1d12db 100644
--- a/gcc/rust/backend/rust-intrinsic-handlers.h
+++ b/gcc/rust/backend/rust-intrinsic-handlers.h
@@ -135,6 +135,8 @@ void wrapping_op (IntrinsicCtx &ctx, tree_code op);
 
 void atomic_store (IntrinsicCtx &ctx, int ordering);
 void atomic_load (IntrinsicCtx &ctx, int ordering);
+void atomic_binary_op (IntrinsicCtx &ctx, const std::string &op_name,
+                      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);
@@ -191,6 +193,13 @@ Intrinsic::CompileFn wrapping_op (tree_code op);
 Intrinsic::CompileFn atomic_store (int ordering);
 Intrinsic::CompileFn atomic_load (int ordering);
 
+Intrinsic::CompileFn atomic_xadd (int ordering);
+Intrinsic::CompileFn atomic_xsub (int ordering);
+Intrinsic::CompileFn atomic_and (int ordering);
+Intrinsic::CompileFn atomic_nand (int ordering);
+Intrinsic::CompileFn atomic_or (int ordering);
+Intrinsic::CompileFn atomic_xor (int ordering);
+
 Intrinsic::CompileFn unchecked_op (tree_code op);
 
 Intrinsic::CompileFn copy (bool overlaps);
diff --git a/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc 
b/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
index 882ba5deb..6e94d6f5f 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
@@ -187,6 +187,96 @@ const std::unordered_map<std::string, IntrinsicRules>
     // pub unsafe fn atomic_load_unordered<T: Copy>(_src: *const T) -> T;
     {IValue::ATOMIC_LOAD_UNORDERED,
      {1, {IRT::ConstPtrFirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn atomic_xadd<T: Copy>(dst: *mut T, val: T) -> T;
+    {IValue::ATOMIC_XADD,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn atomic_xadd_acq<T: Copy>(dst: *mut T, val: T) -> T;
+    {IValue::ATOMIC_XADD_ACQ,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn atomic_xadd_rel<T: Copy>(dst: *mut T, val: T) -> T;
+    {IValue::ATOMIC_XADD_REL,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn atomic_xadd_acqrel<T: Copy>(dst: *mut T, val: T) -> T;
+    {IValue::ATOMIC_XADD_ACQREL,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn atomic_xadd_relaxed<T: Copy>(dst: *mut T, val: T) -> T;
+    {IValue::ATOMIC_XADD_RELAXED,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn atomic_xsub<T: Copy>(dst: *mut T, val: T) -> T;
+    {IValue::ATOMIC_XSUB,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn atomic_xsub_acq<T: Copy>(dst: *mut T, val: T) -> T;
+    {IValue::ATOMIC_XSUB_ACQ,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn atomic_xsub_rel<T: Copy>(dst: *mut T, val: T) -> T;
+    {IValue::ATOMIC_XSUB_REL,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn atomic_xsub_acqrel<T: Copy>(dst: *mut T, val: T) -> T;
+    {IValue::ATOMIC_XSUB_ACQREL,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn atomic_xsub_relaxed<T: Copy>(dst: *mut T, val: T) -> T;
+    {IValue::ATOMIC_XSUB_RELAXED,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn atomic_and<T: Copy>(dst: *mut T, val: T) -> T;
+    {IValue::ATOMIC_AND,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn atomic_and_acq<T: Copy>(dst: *mut T, val: T) -> T;
+    {IValue::ATOMIC_AND_ACQ,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn atomic_and_rel<T: Copy>(dst: *mut T, val: T) -> T;
+    {IValue::ATOMIC_AND_REL,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn atomic_and_acqrel<T: Copy>(dst: *mut T, val: T) -> T;
+    {IValue::ATOMIC_AND_ACQREL,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn atomic_and_relaxed<T: Copy>(dst: *mut T, val: T) -> T;
+    {IValue::ATOMIC_AND_RELAXED,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn atomic_nand<T: Copy>(dst: *mut T, val: T) -> T;
+    {IValue::ATOMIC_NAND,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn atomic_nand_acq<T: Copy>(dst: *mut T, val: T) -> T;
+    {IValue::ATOMIC_NAND_ACQ,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn atomic_nand_rel<T: Copy>(dst: *mut T, val: T) -> T;
+    {IValue::ATOMIC_NAND_REL,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn atomic_nand_acqrel<T: Copy>(dst: *mut T, val: T) -> T;
+    {IValue::ATOMIC_NAND_ACQREL,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn atomic_nand_relaxed<T: Copy>(dst: *mut T, val: T) -> T;
+    {IValue::ATOMIC_NAND_RELAXED,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn atomic_or<T: Copy>(dst: *mut T, val: T) -> T;
+    {IValue::ATOMIC_OR,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn atomic_or_acq<T: Copy>(dst: *mut T, val: T) -> T;
+    {IValue::ATOMIC_OR_ACQ,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn atomic_or_rel<T: Copy>(dst: *mut T, val: T) -> T;
+    {IValue::ATOMIC_OR_REL,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn atomic_or_acqrel<T: Copy>(dst: *mut T, val: T) -> T;
+    {IValue::ATOMIC_OR_ACQREL,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn atomic_or_relaxed<T: Copy>(dst: *mut T, val: T) -> T;
+    {IValue::ATOMIC_OR_RELAXED,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn atomic_xor<T: Copy>(dst: *mut T, val: T) -> T;
+    {IValue::ATOMIC_XOR,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn atomic_xor_acq<T: Copy>(dst: *mut T, val: T) -> T;
+    {IValue::ATOMIC_XOR_ACQ,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn atomic_xor_rel<T: Copy>(dst: *mut T, val: T) -> T;
+    {IValue::ATOMIC_XOR_REL,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // pub unsafe fn atomic_xor_acqrel<T: Copy>(dst: *mut T, val: T) -> T;
+    {IValue::ATOMIC_XOR_ACQREL,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+    // 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}},
     // pub fn unchecked_add<T: Copy>(x: T, y: T) -> T;
     {IValue::UNCHECKED_ADD,
      {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
diff --git a/gcc/rust/util/rust-intrinsic-values.h 
b/gcc/rust/util/rust-intrinsic-values.h
index 1308444b8..e184859a0 100644
--- a/gcc/rust/util/rust-intrinsic-values.h
+++ b/gcc/rust/util/rust-intrinsic-values.h
@@ -120,6 +120,37 @@ public:
   static constexpr auto &ATOMIC_LOAD_RELAXED = "atomic_load_relaxed";
   static constexpr auto &ATOMIC_LOAD_UNORDERED = "atomic_load_unordered";
 
+  static constexpr auto &ATOMIC_XADD = "atomic_xadd";
+  static constexpr auto &ATOMIC_XADD_ACQ = "atomic_xadd_acq";
+  static constexpr auto &ATOMIC_XADD_REL = "atomic_xadd_rel";
+  static constexpr auto &ATOMIC_XADD_ACQREL = "atomic_xadd_acqrel";
+  static constexpr auto &ATOMIC_XADD_RELAXED = "atomic_xadd_relaxed";
+  static constexpr auto &ATOMIC_XSUB = "atomic_xsub";
+  static constexpr auto &ATOMIC_XSUB_ACQ = "atomic_xsub_acq";
+  static constexpr auto &ATOMIC_XSUB_REL = "atomic_xsub_rel";
+  static constexpr auto &ATOMIC_XSUB_ACQREL = "atomic_xsub_acqrel";
+  static constexpr auto &ATOMIC_XSUB_RELAXED = "atomic_xsub_relaxed";
+  static constexpr auto &ATOMIC_AND = "atomic_and";
+  static constexpr auto &ATOMIC_AND_ACQ = "atomic_and_acq";
+  static constexpr auto &ATOMIC_AND_REL = "atomic_and_rel";
+  static constexpr auto &ATOMIC_AND_ACQREL = "atomic_and_acqrel";
+  static constexpr auto &ATOMIC_AND_RELAXED = "atomic_and_relaxed";
+  static constexpr auto &ATOMIC_NAND = "atomic_nand";
+  static constexpr auto &ATOMIC_NAND_ACQ = "atomic_nand_acq";
+  static constexpr auto &ATOMIC_NAND_REL = "atomic_nand_rel";
+  static constexpr auto &ATOMIC_NAND_ACQREL = "atomic_nand_acqrel";
+  static constexpr auto &ATOMIC_NAND_RELAXED = "atomic_nand_relaxed";
+  static constexpr auto &ATOMIC_OR = "atomic_or";
+  static constexpr auto &ATOMIC_OR_ACQ = "atomic_or_acq";
+  static constexpr auto &ATOMIC_OR_REL = "atomic_or_rel";
+  static constexpr auto &ATOMIC_OR_ACQREL = "atomic_or_acqrel";
+  static constexpr auto &ATOMIC_OR_RELAXED = "atomic_or_relaxed";
+  static constexpr auto &ATOMIC_XOR = "atomic_xor";
+  static constexpr auto &ATOMIC_XOR_ACQ = "atomic_xor_acq";
+  static constexpr auto &ATOMIC_XOR_REL = "atomic_xor_rel";
+  static constexpr auto &ATOMIC_XOR_ACQREL = "atomic_xor_acqrel";
+  static constexpr auto &ATOMIC_XOR_RELAXED = "atomic_xor_relaxed";
+
   static constexpr auto &UNCHECKED_ADD = "unchecked_add";
   static constexpr auto &UNCHECKED_SUB = "unchecked_sub";
   static constexpr auto &UNCHECKED_MUL = "unchecked_mul";
diff --git a/gcc/testsuite/rust/execute/torture/atomic_and.rs 
b/gcc/testsuite/rust/execute/torture/atomic_and.rs
new file mode 100644
index 000000000..000c3358b
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/atomic_and.rs
@@ -0,0 +1,105 @@
+#![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_and<T: Copy>(dst: *mut T, val: T) -> T;
+    pub fn atomic_and_acq<T: Copy>(dst: *mut T, val: T) -> T;
+    pub fn atomic_and_rel<T: Copy>(dst: *mut T, val: T) -> T;
+    pub fn atomic_and_acqrel<T: Copy>(dst: *mut T, val: T) -> T;
+    pub fn atomic_and_relaxed<T: Copy>(dst: *mut T, val: T) -> T;
+}
+
+fn main() -> u32 {
+    unsafe {
+        let mut src = 0b11111u32;
+
+        let one = atomic_and(&mut src, 0b11110);
+        if one != 0b11111 || src != 0b11110 {
+            return 1;
+        }
+
+        let two = atomic_and_acq(&mut src, 0b11101);
+        if two != 0b11110 || src != 0b11100 {
+            return 1;
+        }
+
+        let three = atomic_and_rel(&mut src, 0b11011);
+        if three != 0b11100 || src != 0b11000 {
+            return 1;
+        }
+
+        let four = atomic_and_acqrel(&mut src, 0b10111);
+        if four != 0b11000 || src != 0b10000 {
+            return 1;
+        }
+
+        let five = atomic_and_relaxed(&mut src, 0b01111);
+        if five != 0b10000 || src != 0 {
+            return 1;
+        }
+    }
+
+    0
+}
diff --git a/gcc/testsuite/rust/execute/torture/atomic_nand.rs 
b/gcc/testsuite/rust/execute/torture/atomic_nand.rs
new file mode 100644
index 000000000..ab26812f8
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/atomic_nand.rs
@@ -0,0 +1,105 @@
+#![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_nand<T: Copy>(dst: *mut T, val: T) -> T;
+    pub fn atomic_nand_acq<T: Copy>(dst: *mut T, val: T) -> T;
+    pub fn atomic_nand_rel<T: Copy>(dst: *mut T, val: T) -> T;
+    pub fn atomic_nand_acqrel<T: Copy>(dst: *mut T, val: T) -> T;
+    pub fn atomic_nand_relaxed<T: Copy>(dst: *mut T, val: T) -> T;
+}
+
+fn main() -> u32 {
+    unsafe {
+        let mut src = 0b11110000u8;
+
+        let one = atomic_nand(&mut src, 0b10101010);
+        if one != 0b11110000 || src != 0b01011111 {
+            return 1;
+        }
+
+        let two = atomic_nand_acq(&mut src, 0b11001100);
+        if two != 0b01011111 || src != 0b10110011 {
+            return 1;
+        }
+
+        let three = atomic_nand_rel(&mut src, 0b11110000);
+        if three != 0b10110011 || src != 0b01001111 {
+            return 1;
+        }
+
+        let four = atomic_nand_acqrel(&mut src, 0b00001111);
+        if four != 0b01001111 || src != 0b11110000 {
+            return 1;
+        }
+
+        let five = atomic_nand_relaxed(&mut src, 0b11111111);
+        if five != 0b11110000 || src != 0b00001111 {
+            return 1;
+        }
+    }
+
+    0
+}
diff --git a/gcc/testsuite/rust/execute/torture/atomic_or.rs 
b/gcc/testsuite/rust/execute/torture/atomic_or.rs
new file mode 100644
index 000000000..1b6dd0c22
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/atomic_or.rs
@@ -0,0 +1,105 @@
+#![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_or<T: Copy>(dst: *mut T, val: T) -> T;
+    pub fn atomic_or_acq<T: Copy>(dst: *mut T, val: T) -> T;
+    pub fn atomic_or_rel<T: Copy>(dst: *mut T, val: T) -> T;
+    pub fn atomic_or_acqrel<T: Copy>(dst: *mut T, val: T) -> T;
+    pub fn atomic_or_relaxed<T: Copy>(dst: *mut T, val: T) -> T;
+}
+
+fn main() -> u32 {
+    unsafe {
+        let mut src = 0u32;
+
+        let one = atomic_or(&mut src, 0b00001);
+        if one != 0 || src != 0b00001 {
+            return 1;
+        }
+
+        let two = atomic_or_acq(&mut src, 0b00011);
+        if two != 0b00001 || src != 0b00011 {
+            return 1;
+        }
+
+        let three = atomic_or_rel(&mut src, 0b00110);
+        if three != 0b00011 || src != 0b00111 {
+            return 1;
+        }
+
+        let four = atomic_or_acqrel(&mut src, 0b01100);
+        if four != 0b00111 || src != 0b01111 {
+            return 1;
+        }
+
+        let five = atomic_or_relaxed(&mut src, 0b11000);
+        if five != 0b01111 || src != 0b11111 {
+            return 1;
+        }
+    }
+
+    0
+}
diff --git a/gcc/testsuite/rust/execute/torture/atomic_xadd.rs 
b/gcc/testsuite/rust/execute/torture/atomic_xadd.rs
new file mode 100644
index 000000000..fae538491
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/atomic_xadd.rs
@@ -0,0 +1,95 @@
+#![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_xadd<T: Copy>(dst: *mut T, val: T) -> T;
+    pub fn atomic_xadd_acq<T: Copy>(dst: *mut T, val: T) -> T;
+    pub fn atomic_xadd_rel<T: Copy>(dst: *mut T, val: T) -> T;
+    pub fn atomic_xadd_acqrel<T: Copy>(dst: *mut T, val: T) -> T;
+    pub fn atomic_xadd_relaxed<T: Copy>(dst: *mut T, val: T) -> T;
+}
+
+fn main() -> u32 {
+    let one;
+    let two;
+    let three;
+    let four;
+    let five;
+
+    unsafe {
+        let mut src = 1u32;
+        one = atomic_xadd(&mut src, 1);
+        two = atomic_xadd_acq(&mut src, 1);
+        three = atomic_xadd_rel(&mut src, 1);
+        four = atomic_xadd_acqrel(&mut src, 1);
+        five = atomic_xadd_relaxed(&mut src, 1);
+
+        if one != 1 || two != 2 || three != 3 || four != 4 || five != 5 || src 
!= 6 {
+            return 1;
+        }
+    }
+
+    0
+}
diff --git a/gcc/testsuite/rust/execute/torture/atomic_xor.rs 
b/gcc/testsuite/rust/execute/torture/atomic_xor.rs
new file mode 100644
index 000000000..845ead9bb
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/atomic_xor.rs
@@ -0,0 +1,105 @@
+#![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_xor<T: Copy>(dst: *mut T, val: T) -> T;
+    pub fn atomic_xor_acq<T: Copy>(dst: *mut T, val: T) -> T;
+    pub fn atomic_xor_rel<T: Copy>(dst: *mut T, val: T) -> T;
+    pub fn atomic_xor_acqrel<T: Copy>(dst: *mut T, val: T) -> T;
+    pub fn atomic_xor_relaxed<T: Copy>(dst: *mut T, val: T) -> T;
+}
+
+fn main() -> u32 {
+    unsafe {
+        let mut src = 0b10101u32;
+
+        let one = atomic_xor(&mut src, 0b00111);
+        if one != 0b10101 || src != 0b10010 {
+            return 1;
+        }
+
+        let two = atomic_xor_acq(&mut src, 0b11000);
+        if two != 0b10010 || src != 0b01010 {
+            return 1;
+        }
+
+        let three = atomic_xor_rel(&mut src, 0b01111);
+        if three != 0b01010 || src != 0b00101 {
+            return 1;
+        }
+
+        let four = atomic_xor_acqrel(&mut src, 0b10101);
+        if four != 0b00101 || src != 0b10000 {
+            return 1;
+        }
+
+        let five = atomic_xor_relaxed(&mut src, 0b10000);
+        if five != 0b10000 || src != 0 {
+            return 1;
+        }
+    }
+
+    0
+}
diff --git a/gcc/testsuite/rust/execute/torture/atomic_xsub.rs 
b/gcc/testsuite/rust/execute/torture/atomic_xsub.rs
new file mode 100644
index 000000000..7c7ae3a08
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/atomic_xsub.rs
@@ -0,0 +1,95 @@
+#![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_xsub<T: Copy>(dst: *mut T, val: T) -> T;
+    pub fn atomic_xsub_acq<T: Copy>(dst: *mut T, val: T) -> T;
+    pub fn atomic_xsub_rel<T: Copy>(dst: *mut T, val: T) -> T;
+    pub fn atomic_xsub_acqrel<T: Copy>(dst: *mut T, val: T) -> T;
+    pub fn atomic_xsub_relaxed<T: Copy>(dst: *mut T, val: T) -> T;
+}
+
+fn main() -> u32 {
+    let one;
+    let two;
+    let three;
+    let four;
+    let five;
+    let mut src = 5u32;
+
+    unsafe {
+        five = atomic_xsub(&mut src, 1);
+        four = atomic_xsub_acq(&mut src, 1);
+        three = atomic_xsub_rel(&mut src, 1);
+        two = atomic_xsub_acqrel(&mut src, 1);
+        one = atomic_xsub_relaxed(&mut src, 1);
+
+        if one != 1 || two != 2 || three != 3 || four != 4 || five != 5 {
+            return 1;
+        }
+    }
+
+    src
+}

base-commit: d2951e4c83ec26a05114ebee366ac508806043fa
-- 
2.56.0

Reply via email to