[gcc/devel/rust/master] intrinsics: Add copy_nonoverlapping<T>

Thomas Schwinge tschwinge@gcc.gnu.org
Tue Aug 16 19:04:48 GMT 2022


https://gcc.gnu.org/g:f68ecc7e5914ef99b22c258e404c73b2401f9d89

commit f68ecc7e5914ef99b22c258e404c73b2401f9d89
Author: Arthur Cohen <arthur.cohen@embecosm.com>
Date:   Wed Aug 10 16:08:38 2022 +0200

    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>

Diff:
---
 gcc/rust/backend/rust-builtins.h                   |  8 +++
 gcc/rust/backend/rust-compile-intrinsic.cc         | 73 +++++++++++++++++++++-
 .../rust/execute/torture/copy_nonoverlapping1.rs   | 17 +++++
 3 files changed, 97 insertions(+), 1 deletion(-)

diff --git a/gcc/rust/backend/rust-builtins.h b/gcc/rust/backend/rust-builtins.h
index 13c16d15723..2bfa6c6cdf7 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 06dc45797e9..61084b90f33 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
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 00000000000..2ae7a0869e3
--- /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


More information about the Gcc-cvs mailing list