From: Elle Rhumsaa <[email protected]>
Adds the `atomic_exchange` intrinsics for every memory ordering.
gcc/
* rust/backend/rust-compile-intrinsic.cc: compile impl
* rust/backend/rust-intrinsic-handlers.h: handler decls
* rust/backend/rust-intrinsic-handlers.cc: handler impls
* rust/util/rust-intrinsic-values.h: value defs
gcc/teststuite/
* rust/execute/torture/atomic_exchange.rs: basic tests
---
gcc/rust/backend/rust-compile-intrinsic.cc | 8 ++
gcc/rust/backend/rust-intrinsic-handlers.cc | 73 ++++++++++++
gcc/rust/backend/rust-intrinsic-handlers.h | 3 +
gcc/rust/util/rust-intrinsic-values.h | 6 +
.../rust/execute/torture/atomic_exchange.rs | 112 ++++++++++++++++++
5 files changed, 202 insertions(+)
create mode 100644 gcc/testsuite/rust/execute/torture/atomic_exchange.rs
diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc
b/gcc/rust/backend/rust-compile-intrinsic.cc
index 1456f88df985..1342772ce4e6 100644
--- a/gcc/rust/backend/rust-compile-intrinsic.cc
+++ b/gcc/rust/backend/rust-compile-intrinsic.cc
@@ -52,6 +52,14 @@ static const std::map<std::string, handlers::HandlerBuilder>
generic_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_EXCHANGE_SEQCST,
+ handlers::atomic_exchange (__ATOMIC_SEQ_CST)},
+ {IValue::ATOMIC_EXCHANGE_RELEASE,
+ handlers::atomic_exchange (__ATOMIC_RELEASE)},
+ {IValue::ATOMIC_EXCHANGE_RELAXED,
+ handlers::atomic_exchange (__ATOMIC_RELAXED)},
+ {IValue::ATOMIC_EXCHANGE_UNORDERED,
+ handlers::atomic_exchange (__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 8cbcb9ca4cef..f8e6bb8b977e 100644
--- a/gcc/rust/backend/rust-intrinsic-handlers.cc
+++ b/gcc/rust/backend/rust-intrinsic-handlers.cc
@@ -748,6 +748,71 @@ atomic_load (Context *ctx, TyTy::FnType *fntype, int
ordering)
return fndecl;
}
+tree
+atomic_exchange (Context *ctx, TyTy::FnType *fntype, int ordering)
+{
+ rust_assert (fntype->get_params ().size () == 2);
+ rust_assert (fntype->get_num_substitutions () == 1);
+
+ tree lookup = NULL_TREE;
+ if (check_for_cached_intrinsic (ctx, fntype, &lookup))
+ return lookup;
+
+ auto fndecl = compile_intrinsic_function (ctx, fntype);
+
+ // Most intrinsic functions are pure but not the atomic ones
+ TREE_READONLY (fndecl) = 0;
+ TREE_SIDE_EFFECTS (fndecl) = 1;
+
+ // setup the params
+ std::vector<Bvariable *> param_vars;
+ std::vector<tree> types;
+ compile_fn_params (ctx, fntype, fndecl, ¶m_vars, &types);
+
+ auto ok = Backend::function_set_parameters (fndecl, param_vars);
+ rust_assert (ok);
+
+ enter_intrinsic_block (ctx, fndecl);
+
+ auto dst = Backend::var_expression (param_vars[0], UNDEF_LOCATION);
+ TREE_READONLY (dst) = 0;
+
+ auto value = Backend::var_expression (param_vars[1], UNDEF_LOCATION);
+ auto memorder = make_unsigned_long_tree (ordering);
+
+ auto monomorphized_type
+ = fntype->get_substs ()[0].get_param_ty ()->resolve ();
+
+ auto builtin_name
+ = build_atomic_builtin_name ("atomic_exchange_", fntype->get_locus (),
+ monomorphized_type);
+ if (builtin_name.empty ())
+ return error_mark_node;
+
+ tree atomic_exchange_raw = nullptr;
+ BuiltinsContext::get ().lookup_simple_builtin (builtin_name,
+ &atomic_exchange_raw);
+ rust_assert (atomic_exchange_raw);
+
+ auto atomic_exchange
+ = build_fold_addr_expr_loc (UNKNOWN_LOCATION, atomic_exchange_raw);
+
+ auto exchange_call
+ = Backend::call_expression (atomic_exchange, {dst, value, memorder},
+ nullptr, UNDEF_LOCATION);
+
+ auto return_statement
+ = Backend::return_statement (fndecl, exchange_call, UNDEF_LOCATION);
+
+ TREE_READONLY (exchange_call) = 0;
+ TREE_SIDE_EFFECTS (exchange_call) = 1;
+
+ ctx->add_statement (return_statement);
+ finalize_intrinsic_block (ctx, fndecl);
+
+ return fndecl;
+}
+
// Shared inner implementation for ctlz and ctlz_nonzero.
//
// nonzero=false â ctlz: ctlz(0) is well-defined in Rust and must return
@@ -1069,6 +1134,14 @@ atomic_load (int ordering)
};
}
+HandlerBuilder
+atomic_exchange (int ordering)
+{
+ return [ordering] (Context *ctx, TyTy::FnType *fntype) {
+ return inner::atomic_exchange (ctx, fntype, ordering);
+ };
+}
+
const HandlerBuilder
unchecked_op (tree_code op)
{
diff --git a/gcc/rust/backend/rust-intrinsic-handlers.h
b/gcc/rust/backend/rust-intrinsic-handlers.h
index f4c36b3fe62d..ac26749dfdb9 100644
--- a/gcc/rust/backend/rust-intrinsic-handlers.h
+++ b/gcc/rust/backend/rust-intrinsic-handlers.h
@@ -37,6 +37,7 @@ tree wrapping_op (Context *ctx, TyTy::FnType *fntype,
tree_code op);
tree atomic_store (Context *ctx, TyTy::FnType *fntype, int ordering);
tree atomic_load (Context *ctx, TyTy::FnType *fntype, int ordering);
+tree atomic_exchange (Context *ctx, TyTy::FnType *fntype, int ordering);
inline tree copy (Context *ctx, TyTy::FnType *fntype, bool overlaps);
inline tree expect (Context *ctx, TyTy::FnType *fntype, bool likely);
tree try_handler (Context *ctx, TyTy::FnType *fntype, bool is_new_api);
@@ -79,6 +80,8 @@ HandlerBuilder atomic_store (int ordering);
HandlerBuilder atomic_load (int ordering);
+HandlerBuilder atomic_exchange (int ordering);
+
const HandlerBuilder unchecked_op (tree_code op);
const HandlerBuilder copy (bool overlaps);
diff --git a/gcc/rust/util/rust-intrinsic-values.h
b/gcc/rust/util/rust-intrinsic-values.h
index c868c851d237..eaa51928bacf 100644
--- a/gcc/rust/util/rust-intrinsic-values.h
+++ b/gcc/rust/util/rust-intrinsic-values.h
@@ -46,6 +46,12 @@ public:
static constexpr auto &ATOMIC_LOAD_RELAXED = "atomic_load_relaxed";
static constexpr auto &ATOMIC_LOAD_UNORDERED = "atomic_load_unordered";
+ static constexpr auto &ATOMIC_EXCHANGE_SEQCST = "atomic_exchange_seqcst";
+ static constexpr auto &ATOMIC_EXCHANGE_RELEASE = "atomic_exchange_release";
+ static constexpr auto &ATOMIC_EXCHANGE_RELAXED = "atomic_exchange_relaxed";
+ static constexpr auto &ATOMIC_EXCHANGE_UNORDERED
+ = "atomic_exchange_unordered";
+
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_exchange.rs
b/gcc/testsuite/rust/execute/torture/atomic_exchange.rs
new file mode 100644
index 000000000000..569504f6a30c
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/atomic_exchange.rs
@@ -0,0 +1,112 @@
+#![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_exchange_seqcst<T : Copy> (dst : *mut T, val : T) -> T;
+pub fn atomic_exchange_release<T : Copy> (dst : *mut T, val : T) -> T;
+pub fn atomic_exchange_relaxed<T : Copy> (dst : *mut T, val : T) -> T;
+pub fn atomic_exchange_unordered<T : Copy> (dst : *mut T, val : T) -> T;
+}
+
+fn
+main () -> u32
+{
+ let mut dst = 15u32;
+ let init = dst;
+ let one;
+ let two;
+ let three;
+ let four;
+
+ unsafe
+ {
+ let mut ret = atomic_exchange_seqcst (&mut dst, 1);
+ one = dst;
+
+ if ret
+ != init { return ret; }
+
+ ret = atomic_exchange_release (&mut dst, 2);
+ two = dst;
+
+ if ret
+ != one { return ret; }
+
+ ret = atomic_exchange_relaxed (&mut dst, 3);
+ three = dst;
+
+ if ret
+ != two { return ret; }
+
+ ret = atomic_exchange_unordered (&mut dst, 4);
+ four = dst;
+
+ if ret
+ != three { return ret; }
+ }
+
+ (four + three + two + one) - 10
+}
--
2.54.0