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