Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

intrinsics: Add copy_nonoverlapping<T> #1459

Merged
merged 1 commit into from Aug 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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
73 changes: 72 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 @@ -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)
Expand Down Expand Up @@ -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) {}

Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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;

Expand All @@ -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
17 changes: 17 additions & 0 deletions 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
}
}