Skip to content

Commit e09a576

Browse files
committed
Add support for transmute intrinsic
This adds in the transmute intrisic by utilizing the convert_expression framework we have in the backend class. Fixes #1130 Addresses #658
1 parent ca75985 commit e09a576

File tree

3 files changed

+171
-2
lines changed

3 files changed

+171
-2
lines changed

gcc/rust/backend/rust-compile-intrinsic.cc

Lines changed: 113 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,11 +174,14 @@ static tree
174174
offset_intrinsic_handler (Context *ctx, TyTy::BaseType *fntype);
175175
static tree
176176
sizeof_intrinsic_handler (Context *ctx, TyTy::BaseType *fntype);
177+
static tree
178+
transmute_intrinsic_handler (Context *ctx, TyTy::BaseType *fntype);
177179

178180
static const std::map<std::string,
179181
std::function<tree (Context *, TyTy::BaseType *)>>
180182
generic_intrinsics = {{"offset", &offset_intrinsic_handler},
181-
{"size_of", &sizeof_intrinsic_handler}};
183+
{"size_of", &sizeof_intrinsic_handler},
184+
{"transmute", &transmute_intrinsic_handler}};
182185

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

@@ -340,7 +343,7 @@ sizeof_intrinsic_handler (Context *ctx, TyTy::BaseType *fntype_tyty)
340343
fntype->override_context ();
341344
}
342345

343-
// offset intrinsic has two params dst pointer and offset isize
346+
// size_of has _zero_ parameters its parameter is the generic one
344347
if (fntype->get_params ().size () != 0)
345348
{
346349
rust_error_at (fntype->get_ident ().locus,
@@ -396,5 +399,113 @@ sizeof_intrinsic_handler (Context *ctx, TyTy::BaseType *fntype_tyty)
396399
return fndecl;
397400
}
398401

402+
static tree
403+
transmute_intrinsic_handler (Context *ctx, TyTy::BaseType *fntype_tyty)
404+
{
405+
rust_assert (fntype_tyty->get_kind () == TyTy::TypeKind::FNDEF);
406+
TyTy::FnType *fntype = static_cast<TyTy::FnType *> (fntype_tyty);
407+
const Resolver::CanonicalPath &canonical_path = fntype->get_ident ().path;
408+
409+
// items can be forward compiled which means we may not need to invoke this
410+
// code. We might also have already compiled this generic function as well.
411+
tree lookup = NULL_TREE;
412+
if (ctx->lookup_function_decl (fntype->get_ty_ref (), &lookup,
413+
fntype->get_id (), fntype))
414+
{
415+
// has this been added to the list then it must be finished
416+
if (ctx->function_completed (lookup))
417+
{
418+
tree dummy = NULL_TREE;
419+
if (!ctx->lookup_function_decl (fntype->get_ty_ref (), &dummy))
420+
{
421+
ctx->insert_function_decl (fntype, lookup);
422+
}
423+
return lookup;
424+
}
425+
}
426+
427+
if (fntype->has_subsititions_defined ())
428+
{
429+
// override the Hir Lookups for the substituions in this context
430+
fntype->override_context ();
431+
}
432+
433+
// transmute intrinsic has one parameter
434+
if (fntype->get_params ().size () != 1)
435+
{
436+
rust_error_at (fntype->get_ident ().locus,
437+
"invalid number of parameters for transmute intrinsic");
438+
return error_mark_node;
439+
}
440+
441+
// build the intrinsic function
442+
tree compiled_fn_type = TyTyResolveCompile::compile (ctx, fntype);
443+
std::string ir_symbol_name
444+
= canonical_path.get () + fntype->subst_as_string ();
445+
std::string asm_name = ctx->mangle_item (fntype, canonical_path);
446+
447+
unsigned int flags = 0;
448+
tree fndecl
449+
= ctx->get_backend ()->function (compiled_fn_type, ir_symbol_name, asm_name,
450+
flags, fntype->get_ident ().locus);
451+
TREE_PUBLIC (fndecl) = 0;
452+
TREE_READONLY (fndecl) = 1;
453+
DECL_ARTIFICIAL (fndecl) = 1;
454+
DECL_EXTERNAL (fndecl) = 0;
455+
DECL_DECLARED_INLINE_P (fndecl) = 1;
456+
457+
// setup the params
458+
std::vector<Bvariable *> param_vars;
459+
for (auto &parm : fntype->get_params ())
460+
{
461+
auto &referenced_param = parm.first;
462+
auto &param_tyty = parm.second;
463+
auto compiled_param_type = TyTyResolveCompile::compile (ctx, param_tyty);
464+
465+
Location param_locus = referenced_param->get_locus ();
466+
Bvariable *compiled_param_var
467+
= CompileFnParam::compile (ctx, fndecl, referenced_param,
468+
compiled_param_type, param_locus);
469+
470+
param_vars.push_back (compiled_param_var);
471+
}
472+
473+
rust_assert (param_vars.size () == 1);
474+
if (!ctx->get_backend ()->function_set_parameters (fndecl, param_vars))
475+
return error_mark_node;
476+
477+
// param to convert
478+
Bvariable *convert_me_param = param_vars.at (0);
479+
tree convert_me_expr
480+
= ctx->get_backend ()->var_expression (convert_me_param, Location ());
481+
482+
tree enclosing_scope = NULL_TREE;
483+
Location start_location = Location ();
484+
Location end_location = Location ();
485+
486+
tree code_block = ctx->get_backend ()->block (fndecl, enclosing_scope, {},
487+
start_location, end_location);
488+
ctx->push_block (code_block);
489+
490+
// BUILTIN transmute FN BODY BEGIN
491+
tree result_type_tree = TREE_TYPE (DECL_RESULT (fndecl));
492+
tree result_expr
493+
= ctx->get_backend ()->convert_expression (result_type_tree,
494+
convert_me_expr, Location ());
495+
auto return_statement
496+
= ctx->get_backend ()->return_statement (fndecl, {result_expr},
497+
Location ());
498+
ctx->add_statement (return_statement);
499+
// BUILTIN transmute FN BODY END
500+
501+
tree bind_tree = ctx->pop_block ();
502+
503+
gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR);
504+
DECL_SAVED_TREE (fndecl) = bind_tree;
505+
ctx->push_function (fndecl);
506+
507+
return fndecl;
508+
}
509+
399510
} // namespace Compile
400511
} // namespace Rust
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// { dg-additional-options "-w" }
2+
mod mem {
3+
extern "rust-intrinsic" {
4+
fn size_of<T>() -> usize;
5+
fn transmute<U, V>(_: U) -> V;
6+
}
7+
}
8+
9+
impl u16 {
10+
fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
11+
unsafe { mem::transmute(self) }
12+
}
13+
}
14+
15+
pub trait Hasher {
16+
fn finish(&self) -> u64;
17+
18+
fn write(&mut self, bytes: &[u8]);
19+
20+
fn write_u8(&mut self, i: u8) {
21+
self.write(&[i])
22+
}
23+
24+
fn write_i8(&mut self, i: i8) {
25+
self.write_u8(i as u8)
26+
}
27+
28+
fn write_u16(&mut self, i: u16) {
29+
self.write(&i.to_ne_bytes())
30+
}
31+
32+
fn write_i16(&mut self, i: i16) {
33+
self.write_u16(i as u16)
34+
}
35+
}
36+
37+
pub struct SipHasher;
38+
39+
impl Hasher for SipHasher {
40+
#[inline]
41+
fn write(&mut self, msg: &[u8]) {}
42+
43+
#[inline]
44+
fn finish(&self) -> u64 {
45+
0
46+
}
47+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
mod mem {
2+
extern "rust-intrinsic" {
3+
fn size_of<T>() -> usize;
4+
fn transmute<U, V>(_: U) -> V;
5+
}
6+
}
7+
8+
fn main() {
9+
let a = 123;
10+
let _b: [u8; mem::size_of::<i32>()] = mem::transmute(a);
11+
}

0 commit comments

Comments
 (0)