aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/backend
diff options
context:
space:
mode:
authorArthur Cohen <arthur.cohen@embecosm.com>2022-08-10 16:08:38 +0200
committerArthur Cohen <arthur.cohen@embecosm.com>2022-08-16 11:29:00 +0200
commitf68ecc7e5914ef99b22c258e404c73b2401f9d89 (patch)
treef790a4bc549fcaee5e73a566f1507a5eae7b525b /gcc/rust/backend
parent021e4953390da748515debfc8973149457d3118a (diff)
downloadgcc-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>
Diffstat (limited to 'gcc/rust/backend')
-rw-r--r--gcc/rust/backend/rust-builtins.h8
-rw-r--r--gcc/rust/backend/rust-compile-intrinsic.cc73
2 files changed, 80 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", &copy_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, &param_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