Skip to content

Commit

Permalink
intrinsics: Add copy_nonoverlapping<T>
Browse files Browse the repository at this point in the history
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>())`
  • Loading branch information
CohenArthur committed Aug 11, 2022
1 parent eca2ac2 commit 2bbffdb
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 1 deletion.
8 changes: 8 additions & 0 deletions gcc/rust/backend/rust-builtins.h
Expand Up @@ -122,6 +122,14 @@ class BuiltinsContext
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
Expand Down
71 changes: 70 additions & 1 deletion gcc/rust/backend/rust-compile-intrinsic.cc
Expand Up @@ -25,6 +25,7 @@
#include "rust-location.h"
#include "rust-tree.h"
#include "tree-core.h"
#include "print-tree.h"

namespace Rust {
namespace Compile {
Expand All @@ -37,6 +38,8 @@ static tree
transmute_handler (Context *ctx, TyTy::FnType *fntype);
static tree
rotate_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)
Expand All @@ -55,7 +58,8 @@ static const std::map<std::string,
{"size_of", &sizeof_handler},
{"transmute", &transmute_handler},
{"rotate_left", &rotate_left_handler},
{"rotate_right", &rotate_right_handler}};
{"rotate_right", &rotate_right_handler},
{"copy_nonoverlapping", &copy_nonoverlapping_handler}};

Intrinsics::Intrinsics (Context *ctx) : ctx (ctx) {}

Expand Down Expand Up @@ -184,7 +188,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);
}

Expand Down Expand Up @@ -373,5 +379,68 @@ rotate_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);

// 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;
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);

// `memcpy` always has side effects, it is far from a pure function
TREE_SIDE_EFFECTS (fndecl) = 1;

return fndecl;
}

} // namespace Compile
} // namespace Rust

0 comments on commit 2bbffdb

Please sign in to comment.