diff options
author | Arthur Cohen <arthur.cohen@embecosm.com> | 2022-08-10 16:08:38 +0200 |
---|---|---|
committer | Arthur Cohen <arthur.cohen@embecosm.com> | 2022-08-16 11:29:00 +0200 |
commit | f68ecc7e5914ef99b22c258e404c73b2401f9d89 (patch) | |
tree | f790a4bc549fcaee5e73a566f1507a5eae7b525b | |
parent | 021e4953390da748515debfc8973149457d3118a (diff) | |
download | gcc-f68ecc7e5914ef99b22c258e404c73b2401f9d89.zip gcc-f68ecc7e5914ef99b22c258e404c73b2401f9d89.tar.gz gcc-f68ecc7e5914ef99b22c258e404c73b2401f9d89.tar.bz2 |
intrinsics: Add copy_nonoverlapping<T>
This intrinsic is similar to C's memcpy (or in our case, GCC's
__builtin_memcpy) with the order of arguments swapped and knowledge
about the type of the operands. So we can desugar the following calls:
`copy_nonoverlapping::<T>(src, dst, count)`
can be converted to
`__builtin_memcpy(dst, src, count * size_of::<T>())`
Finally, unlike most intrinsics, copy_nonoverlapping must be marked as impure
Co-authored-by: philbert <philip.herron@embecosm.com>
-rw-r--r-- | gcc/rust/backend/rust-builtins.h | 8 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile-intrinsic.cc | 73 | ||||
-rw-r--r-- | gcc/testsuite/rust/execute/torture/copy_nonoverlapping1.rs | 17 |
3 files changed, 97 insertions, 1 deletions
diff --git a/gcc/rust/backend/rust-builtins.h b/gcc/rust/backend/rust-builtins.h index 13c16d1..2bfa6c6 100644 --- a/gcc/rust/backend/rust-builtins.h +++ b/gcc/rust/backend/rust-builtins.h @@ -122,6 +122,14 @@ private: define_builtin ("breakpoint", BUILT_IN_TRAP, "__builtin_trap", "breakpoint", build_function_type (void_type_node, void_list_node), builtin_const | builtin_noreturn); + + define_builtin ( + "memcpy", BUILT_IN_MEMCPY, "__builtin_memcpy", "memcpy", + build_function_type_list (build_pointer_type (void_type_node), + build_pointer_type (void_type_node), + build_pointer_type (void_type_node), + size_type_node, NULL_TREE), + 0); } // Define a builtin function. BCODE is the builtin function code diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc b/gcc/rust/backend/rust-compile-intrinsic.cc index 06dc457..61084b9 100644 --- a/gcc/rust/backend/rust-compile-intrinsic.cc +++ b/gcc/rust/backend/rust-compile-intrinsic.cc @@ -25,6 +25,7 @@ #include "rust-location.h" #include "rust-tree.h" #include "tree-core.h" +#include "print-tree.h" namespace Rust { namespace Compile { @@ -39,6 +40,8 @@ static tree rotate_handler (Context *ctx, TyTy::FnType *fntype, tree_code op); static tree wrapping_op_handler (Context *ctx, TyTy::FnType *fntype, tree_code op); +static tree +copy_nonoverlapping_handler (Context *ctx, TyTy::FnType *fntype); static inline tree rotate_left_handler (Context *ctx, TyTy::FnType *fntype) @@ -76,7 +79,8 @@ static const std::map<std::string, {"rotate_right", &rotate_right_handler}, {"wrapping_add", &wrapping_add_handler}, {"wrapping_sub", &wrapping_sub_handler}, - {"wrapping_mul", &wrapping_mul_handler}}; + {"wrapping_mul", &wrapping_mul_handler}, + {"copy_nonoverlapping", ©_nonoverlapping_handler}}; Intrinsics::Intrinsics (Context *ctx) : ctx (ctx) {} @@ -205,7 +209,9 @@ finalize_intrinsic_block (Context *ctx, tree fndecl) tree bind_tree = ctx->pop_block (); gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR); + DECL_SAVED_TREE (fndecl) = bind_tree; + ctx->push_function (fndecl); } @@ -415,6 +421,7 @@ wrapping_op_handler (Context *ctx, TyTy::FnType *fntype, tree_code op) auto &lhs_param = param_vars.at (0); auto &rhs_param = param_vars.at (1); + if (!ctx->get_backend ()->function_set_parameters (fndecl, param_vars)) return error_mark_node; @@ -440,5 +447,69 @@ wrapping_op_handler (Context *ctx, TyTy::FnType *fntype, tree_code op) return fndecl; } +/** + * fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize); + */ +static tree +copy_nonoverlapping_handler (Context *ctx, TyTy::FnType *fntype) +{ + rust_assert (fntype->get_params ().size () == 3); + 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 - not `copy_nonoverlapping` + TREE_READONLY (fndecl) = 0; + TREE_SIDE_EFFECTS (fndecl) = 1; + + // setup the params + std::vector<Bvariable *> param_vars; + compile_fn_params (ctx, fntype, fndecl, ¶m_vars); + + if (!ctx->get_backend ()->function_set_parameters (fndecl, param_vars)) + return error_mark_node; + + enter_intrinsic_block (ctx, fndecl); + + // BUILTIN copy_nonoverlapping BODY BEGIN + + auto src = ctx->get_backend ()->var_expression (param_vars[0], Location ()); + auto dst = ctx->get_backend ()->var_expression (param_vars[1], Location ()); + auto count = ctx->get_backend ()->var_expression (param_vars[2], Location ()); + + // We want to create the following statement + // memcpy(dst, src, size_of::<T>()); + // so + // memcpy(dst, src, size_expr); + + auto *resolved_ty = fntype->get_substs ().at (0).get_param_ty ()->resolve (); + auto param_type = TyTyResolveCompile::compile (ctx, resolved_ty); + + tree size_expr + = build2 (MULT_EXPR, size_type_node, TYPE_SIZE_UNIT (param_type), count); + + tree memcpy_raw = nullptr; + BuiltinsContext::get ().lookup_simple_builtin ("memcpy", &memcpy_raw); + rust_assert (memcpy_raw); + auto memcpy + = build_fold_addr_expr_loc (Location ().gcc_location (), memcpy_raw); + + auto copy_call + = ctx->get_backend ()->call_expression (memcpy, {dst, src, size_expr}, + nullptr, Location ()); + + ctx->add_statement (copy_call); + + // BUILTIN copy_nonoverlapping BODY END + + finalize_intrinsic_block (ctx, fndecl); + + return fndecl; +} + } // namespace Compile } // namespace Rust diff --git a/gcc/testsuite/rust/execute/torture/copy_nonoverlapping1.rs b/gcc/testsuite/rust/execute/torture/copy_nonoverlapping1.rs new file mode 100644 index 0000000..2ae7a08 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/copy_nonoverlapping1.rs @@ -0,0 +1,17 @@ +extern "rust-intrinsic" { + pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize); +} + +fn main() -> i32 { + let i = 15; + let mut i_copy = 16; + + let i = &i as *const i32; + let i_copy = &mut i_copy as *mut i32; + + unsafe { + copy_nonoverlapping(i, i_copy, 1); + + *i_copy - *i + } +}
\ No newline at end of file |