public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/rust/master] Add support for transmute intrinsic
@ 2022-06-08 12:41 Thomas Schwinge
  0 siblings, 0 replies; only message in thread
From: Thomas Schwinge @ 2022-06-08 12:41 UTC (permalink / raw)
  To: gcc-cvs

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

commit e09a57632038dc965977e45beed591bf7056d20b
Author: Philip Herron <philip.herron@embecosm.com>
Date:   Thu Apr 28 15:48:42 2022 +0100

    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

Diff:
---
 gcc/rust/backend/rust-compile-intrinsic.cc       | 115 ++++++++++++++++++++++-
 gcc/testsuite/rust/compile/issue-1130.rs         |  47 +++++++++
 gcc/testsuite/rust/compile/torture/transmute1.rs |  11 +++
 3 files changed, 171 insertions(+), 2 deletions(-)

diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc b/gcc/rust/backend/rust-compile-intrinsic.cc
index 5fde694f1d8..2436aaaab0c 100644
--- a/gcc/rust/backend/rust-compile-intrinsic.cc
+++ b/gcc/rust/backend/rust-compile-intrinsic.cc
@@ -174,11 +174,14 @@ static tree
 offset_intrinsic_handler (Context *ctx, TyTy::BaseType *fntype);
 static tree
 sizeof_intrinsic_handler (Context *ctx, TyTy::BaseType *fntype);
+static tree
+transmute_intrinsic_handler (Context *ctx, TyTy::BaseType *fntype);
 
 static const std::map<std::string,
 		      std::function<tree (Context *, TyTy::BaseType *)>>
   generic_intrinsics = {{"offset", &offset_intrinsic_handler},
-			{"size_of", &sizeof_intrinsic_handler}};
+			{"size_of", &sizeof_intrinsic_handler},
+			{"transmute", &transmute_intrinsic_handler}};
 
 Intrinsics::Intrinsics (Context *ctx) : ctx (ctx) {}
 
@@ -340,7 +343,7 @@ sizeof_intrinsic_handler (Context *ctx, TyTy::BaseType *fntype_tyty)
       fntype->override_context ();
     }
 
-  // offset intrinsic has two params dst pointer and offset isize
+  // size_of has _zero_ parameters its parameter is the generic one
   if (fntype->get_params ().size () != 0)
     {
       rust_error_at (fntype->get_ident ().locus,
@@ -396,5 +399,113 @@ sizeof_intrinsic_handler (Context *ctx, TyTy::BaseType *fntype_tyty)
   return fndecl;
 }
 
+static tree
+transmute_intrinsic_handler (Context *ctx, TyTy::BaseType *fntype_tyty)
+{
+  rust_assert (fntype_tyty->get_kind () == TyTy::TypeKind::FNDEF);
+  TyTy::FnType *fntype = static_cast<TyTy::FnType *> (fntype_tyty);
+  const Resolver::CanonicalPath &canonical_path = fntype->get_ident ().path;
+
+  // items can be forward compiled which means we may not need to invoke this
+  // code. We might also have already compiled this generic function as well.
+  tree lookup = NULL_TREE;
+  if (ctx->lookup_function_decl (fntype->get_ty_ref (), &lookup,
+				 fntype->get_id (), fntype))
+    {
+      // has this been added to the list then it must be finished
+      if (ctx->function_completed (lookup))
+	{
+	  tree dummy = NULL_TREE;
+	  if (!ctx->lookup_function_decl (fntype->get_ty_ref (), &dummy))
+	    {
+	      ctx->insert_function_decl (fntype, lookup);
+	    }
+	  return lookup;
+	}
+    }
+
+  if (fntype->has_subsititions_defined ())
+    {
+      // override the Hir Lookups for the substituions in this context
+      fntype->override_context ();
+    }
+
+  // transmute intrinsic has one parameter
+  if (fntype->get_params ().size () != 1)
+    {
+      rust_error_at (fntype->get_ident ().locus,
+		     "invalid number of parameters for transmute intrinsic");
+      return error_mark_node;
+    }
+
+  // build the intrinsic function
+  tree compiled_fn_type = TyTyResolveCompile::compile (ctx, fntype);
+  std::string ir_symbol_name
+    = canonical_path.get () + fntype->subst_as_string ();
+  std::string asm_name = ctx->mangle_item (fntype, canonical_path);
+
+  unsigned int flags = 0;
+  tree fndecl
+    = ctx->get_backend ()->function (compiled_fn_type, ir_symbol_name, asm_name,
+				     flags, fntype->get_ident ().locus);
+  TREE_PUBLIC (fndecl) = 0;
+  TREE_READONLY (fndecl) = 1;
+  DECL_ARTIFICIAL (fndecl) = 1;
+  DECL_EXTERNAL (fndecl) = 0;
+  DECL_DECLARED_INLINE_P (fndecl) = 1;
+
+  // setup the params
+  std::vector<Bvariable *> param_vars;
+  for (auto &parm : fntype->get_params ())
+    {
+      auto &referenced_param = parm.first;
+      auto &param_tyty = parm.second;
+      auto compiled_param_type = TyTyResolveCompile::compile (ctx, param_tyty);
+
+      Location param_locus = referenced_param->get_locus ();
+      Bvariable *compiled_param_var
+	= CompileFnParam::compile (ctx, fndecl, referenced_param,
+				   compiled_param_type, param_locus);
+
+      param_vars.push_back (compiled_param_var);
+    }
+
+  rust_assert (param_vars.size () == 1);
+  if (!ctx->get_backend ()->function_set_parameters (fndecl, param_vars))
+    return error_mark_node;
+
+  // param to convert
+  Bvariable *convert_me_param = param_vars.at (0);
+  tree convert_me_expr
+    = ctx->get_backend ()->var_expression (convert_me_param, Location ());
+
+  tree enclosing_scope = NULL_TREE;
+  Location start_location = Location ();
+  Location end_location = Location ();
+
+  tree code_block = ctx->get_backend ()->block (fndecl, enclosing_scope, {},
+						start_location, end_location);
+  ctx->push_block (code_block);
+
+  // BUILTIN transmute FN BODY BEGIN
+  tree result_type_tree = TREE_TYPE (DECL_RESULT (fndecl));
+  tree result_expr
+    = ctx->get_backend ()->convert_expression (result_type_tree,
+					       convert_me_expr, Location ());
+  auto return_statement
+    = ctx->get_backend ()->return_statement (fndecl, {result_expr},
+					     Location ());
+  ctx->add_statement (return_statement);
+  // BUILTIN transmute FN BODY END
+
+  tree bind_tree = ctx->pop_block ();
+
+  gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR);
+  DECL_SAVED_TREE (fndecl) = bind_tree;
+  ctx->push_function (fndecl);
+
+  return fndecl;
+}
+
 } // namespace Compile
 } // namespace Rust
diff --git a/gcc/testsuite/rust/compile/issue-1130.rs b/gcc/testsuite/rust/compile/issue-1130.rs
new file mode 100644
index 00000000000..92200c7cd5f
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-1130.rs
@@ -0,0 +1,47 @@
+// { dg-additional-options "-w" }
+mod mem {
+    extern "rust-intrinsic" {
+        fn size_of<T>() -> usize;
+        fn transmute<U, V>(_: U) -> V;
+    }
+}
+
+impl u16 {
+    fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
+        unsafe { mem::transmute(self) }
+    }
+}
+
+pub trait Hasher {
+    fn finish(&self) -> u64;
+
+    fn write(&mut self, bytes: &[u8]);
+
+    fn write_u8(&mut self, i: u8) {
+        self.write(&[i])
+    }
+
+    fn write_i8(&mut self, i: i8) {
+        self.write_u8(i as u8)
+    }
+
+    fn write_u16(&mut self, i: u16) {
+        self.write(&i.to_ne_bytes())
+    }
+
+    fn write_i16(&mut self, i: i16) {
+        self.write_u16(i as u16)
+    }
+}
+
+pub struct SipHasher;
+
+impl Hasher for SipHasher {
+    #[inline]
+    fn write(&mut self, msg: &[u8]) {}
+
+    #[inline]
+    fn finish(&self) -> u64 {
+        0
+    }
+}
diff --git a/gcc/testsuite/rust/compile/torture/transmute1.rs b/gcc/testsuite/rust/compile/torture/transmute1.rs
new file mode 100644
index 00000000000..333fffe0f2b
--- /dev/null
+++ b/gcc/testsuite/rust/compile/torture/transmute1.rs
@@ -0,0 +1,11 @@
+mod mem {
+    extern "rust-intrinsic" {
+        fn size_of<T>() -> usize;
+        fn transmute<U, V>(_: U) -> V;
+    }
+}
+
+fn main() {
+    let a = 123;
+    let _b: [u8; mem::size_of::<i32>()] = mem::transmute(a);
+}


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-06-08 12:41 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-08 12:41 [gcc/devel/rust/master] Add support for transmute intrinsic Thomas Schwinge

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).