From: Enes Cevik <[email protected]>

This patch adds the size_of_val intrinsic to the compiler. This
intrinsic evaluates the size of a value at runtime, including
Dynamically Sized Types (DSTs).

gcc/rust/ChangeLog:

        * backend/rust-compile-intrinsic.cc (generic_intrinsics): Add
        size_of_val_handler to the map.
        * backend/rust-intrinsic-handlers.cc (size_of_val_handler): New
        function.
        * backend/rust-intrinsic-handlers.h (size_of_val_handler): New
        declaration.
        * typecheck/rust-hir-type-check-intrinsic.cc
        (IntrinsicChecker::intrinsic_rules): Add size_of_val signature
        rule to the map.
        * util/rust-intrinsic-values.h (class Intrinsics): Add
        SIZE_OF_VAL constexpr.

gcc/testsuite/ChangeLog:

        * rust/execute/size-of-val.rs: New test.

Signed-off-by: Enes Cevik <[email protected]>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.


Commit on github: 
https://github.com/Rust-GCC/gccrs/commit/3e6dc95a60c20a0756f5142ba51c5a2e8683693e

The commit has NOT been mentioned in any issue.

The commit has been mentioned in the following pull-request(s):
 - https://github.com/Rust-GCC/gccrs/pull/4672

 gcc/rust/backend/rust-compile-intrinsic.cc    |   1 +
 gcc/rust/backend/rust-intrinsic-handlers.cc   | 102 ++++++++++++++++++
 gcc/rust/backend/rust-intrinsic-handlers.h    |   2 +
 .../rust-hir-type-check-intrinsic.cc          |   2 +
 gcc/rust/util/rust-intrinsic-values.h         |   1 +
 gcc/testsuite/rust/execute/size-of-val.rs     |  63 +++++++++++
 6 files changed, 171 insertions(+)
 create mode 100644 gcc/testsuite/rust/execute/size-of-val.rs

diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc 
b/gcc/rust/backend/rust-compile-intrinsic.cc
index e9407e051..05187c35c 100644
--- a/gcc/rust/backend/rust-compile-intrinsic.cc
+++ b/gcc/rust/backend/rust-compile-intrinsic.cc
@@ -32,6 +32,7 @@ static const std::map<std::string, handlers::HandlerBuilder> 
generic_intrinsics
      {IValue::ARITH_OFFSET, handlers::arith_offset_handler},
      {IValue::WRITE_BYTES, handlers::write_bytes_handler},
      {IValue::SIZE_OF, handlers::sizeof_handler},
+     {IValue::SIZE_OF_VAL, handlers::size_of_val_handler},
      {IValue::MIN_ALIGN_OF, handlers::min_align_of_handler},
      {IValue::TRANSMUTE, handlers::transmute},
      {IValue::ROTATE_LEFT, handlers::rotate_left},
diff --git a/gcc/rust/backend/rust-intrinsic-handlers.cc 
b/gcc/rust/backend/rust-intrinsic-handlers.cc
index 735529cc9..d08b1e2e2 100644
--- a/gcc/rust/backend/rust-intrinsic-handlers.cc
+++ b/gcc/rust/backend/rust-intrinsic-handlers.cc
@@ -1609,6 +1609,108 @@ sizeof_handler (Context *ctx, TyTy::FnType *fntype, 
location_t)
   return fndecl;
 }
 
+/**
+ * pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
+ */
+tree
+size_of_val_handler (Context *ctx, TyTy::FnType *fntype, location_t)
+{
+  rust_assert (fntype->get_params ().size () == 1);
+
+  tree lookup = NULL_TREE;
+  if (check_for_cached_intrinsic (ctx, fntype, &lookup))
+    return lookup;
+
+  auto fndecl = compile_intrinsic_function (ctx, fntype);
+
+  auto locus = fntype->get_locus ();
+
+  std::vector<Bvariable *> param_vars;
+  compile_fn_params (ctx, fntype, fndecl, &param_vars);
+
+  auto &__param = param_vars.at (0);
+  rust_assert (param_vars.size () == 1);
+  if (!Backend::function_set_parameters (fndecl, param_vars))
+    return error_mark_node;
+
+  rust_assert (fntype->get_num_substitutions () == 1);
+  auto &param_mapping = fntype->get_substs ().at (0);
+  const auto param_tyty = param_mapping.get_param_ty ();
+  auto resolved_tyty = param_tyty->resolve ();
+  tree template_parameter_type
+    = TyTyResolveCompile::compile (ctx, resolved_tyty);
+
+  enter_intrinsic_block (ctx, fndecl);
+
+  // BUILTIN size_of FN BODY BEGIN
+
+  tree size_expr = NULL_TREE;
+  if (RS_DST_FLAG_P (template_parameter_type))
+    {
+      tree param = Backend::var_expression (__param, UNDEF_LOCATION);
+      tree param_ty = TREE_TYPE (param);
+      tree data_field = TYPE_FIELDS (param_ty);
+      tree meta_field = DECL_CHAIN (data_field);
+      tree meta_field_expr
+       = build3_loc (locus, COMPONENT_REF, TREE_TYPE (meta_field), param,
+                     meta_field, NULL_TREE);
+
+      if (resolved_tyty->get_kind () == TyTy::TypeKind::SLICE
+         || resolved_tyty->get_kind () == TyTy::TypeKind::STR)
+       {
+         tree elem_type = NULL_TREE;
+         if (resolved_tyty->get_kind () == TyTy::TypeKind::SLICE)
+           {
+             auto slice_tyty = static_cast<TyTy::SliceType *> (resolved_tyty);
+             elem_type
+               = TyTyResolveCompile::compile (ctx,
+                                              slice_tyty->get_element_type ());
+           }
+         else
+           elem_type = char_type_node;
+
+         tree elem_size = TYPE_SIZE_UNIT (elem_type);
+         size_expr
+           = build2_loc (locus, MULT_EXPR, size_type_node,
+                         fold_convert_loc (locus, size_type_node,
+                                           meta_field_expr),
+                         fold_convert_loc (locus, size_type_node, elem_size));
+       }
+      else if (resolved_tyty->get_kind () == TyTy::TypeKind::DYNAMIC)
+       {
+         tree vtable_ptr_ty = TREE_TYPE (meta_field_expr);
+         tree vtable_ty = TREE_TYPE (vtable_ptr_ty);
+
+         tree vtable_ref
+           = build1_loc (locus, INDIRECT_REF, vtable_ty, meta_field_expr);
+
+         tree vtable_field_0 = TYPE_FIELDS (vtable_ty);
+         tree vtable_field_size = DECL_CHAIN (vtable_field_0);
+         rust_assert (vtable_field_size != NULL_TREE);
+
+         size_expr
+           = build3_loc (locus, COMPONENT_REF, TREE_TYPE (vtable_field_size),
+                         vtable_ref, vtable_field_size, NULL_TREE);
+       }
+      else
+       {
+         rust_unreachable ();
+       }
+    }
+  else
+    size_expr = TYPE_SIZE_UNIT (template_parameter_type);
+
+  auto return_statement
+    = Backend::return_statement (fndecl, size_expr, UNDEF_LOCATION);
+  ctx->add_statement (return_statement);
+
+  // BUILTIN size_of FN BODY END
+
+  finalize_intrinsic_block (ctx, fndecl);
+
+  return fndecl;
+}
+
 /**
  * pub fn min_align_of<T>() -> usize;
  */
diff --git a/gcc/rust/backend/rust-intrinsic-handlers.h 
b/gcc/rust/backend/rust-intrinsic-handlers.h
index 1c81417b7..58f52650a 100644
--- a/gcc/rust/backend/rust-intrinsic-handlers.h
+++ b/gcc/rust/backend/rust-intrinsic-handlers.h
@@ -58,6 +58,8 @@ tree rotate_right (Context *ctx, TyTy::FnType *fntype, 
location_t expr_locus);
 const HandlerBuilder wrapping_op (tree_code op);
 tree offset (Context *ctx, TyTy::FnType *fntype, location_t expr_locus);
 tree sizeof_handler (Context *ctx, TyTy::FnType *fntype, location_t 
expr_locus);
+tree size_of_val_handler (Context *ctx, TyTy::FnType *fntype,
+                         location_t expr_locus);
 tree min_align_of_handler (Context *ctx, TyTy::FnType *fntype,
                           location_t expr_locus);
 tree transmute (Context *ctx, TyTy::FnType *fntype, location_t expr_locus);
diff --git a/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc 
b/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
index 0011e3203..bfb5baf31 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
@@ -128,6 +128,8 @@ const std::unordered_map<std::string, IntrinsicRules>
      {1, {IRT::ConstPtrFirstGeneric, IRT::Isize}, IRT::ConstPtrFirstGeneric}},
     // pub fn size_of<T>() -> usize;
     {IValue::SIZE_OF, {1, {}, IRT::Usize}},
+    // pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
+    {IValue::SIZE_OF_VAL, {1, {IRT::ConstPtrFirstGeneric}, IRT::Usize}},
     // pub fn transmute<T, U>(e: T) -> U;
     {IValue::TRANSMUTE, {2, {IRT::FirstGeneric}, IRT::SecondGeneric}},
     // pub fn add_with_overflow<T: Copy>(x: T, y: T) -> (T, bool);
diff --git a/gcc/rust/util/rust-intrinsic-values.h 
b/gcc/rust/util/rust-intrinsic-values.h
index d47e66ce6..35e76a87c 100644
--- a/gcc/rust/util/rust-intrinsic-values.h
+++ b/gcc/rust/util/rust-intrinsic-values.h
@@ -84,6 +84,7 @@ public:
   static constexpr auto &ABORT = "abort";
   static constexpr auto &OFFSET = "offset";
   static constexpr auto &SIZE_OF = "size_of";
+  static constexpr auto &SIZE_OF_VAL = "size_of_val";
   static constexpr auto &TRANSMUTE = "transmute";
 
   static constexpr auto &ADD_WITH_OVERFLOW = "add_with_overflow";
diff --git a/gcc/testsuite/rust/execute/size-of-val.rs 
b/gcc/testsuite/rust/execute/size-of-val.rs
new file mode 100644
index 000000000..5fb9407e6
--- /dev/null
+++ b/gcc/testsuite/rust/execute/size-of-val.rs
@@ -0,0 +1,63 @@
+#![feature(no_core, intrinsics, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+pub trait Sized {}
+
+extern "rust-intrinsic" {
+    pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
+}
+
+trait TraitA {
+    fn foo(&self) {}
+}
+
+struct StructA {
+    _a: i32,
+    _b: i32,
+}
+
+impl TraitA for StructA {}
+impl TraitA for u8 {}
+
+fn main() -> i32 {
+    let val_i32: i32 = 32;
+    let size_i32 = unsafe { size_of_val(&val_i32 as *const i32) };
+
+    let val_struct = StructA { _a: 1, _b: 2 };
+    let size_struct = unsafe { size_of_val(&val_struct as *const StructA) };
+
+    let arr: [i32; 3] = [10, 20, 30];
+    let val_slice: &[i32] = &arr;
+    let size_slice = unsafe { size_of_val(val_slice as *const [i32]) };
+
+    let val_str: &str = "gccrs";
+    let size_str = unsafe { size_of_val(val_str as *const str) };
+
+    let val_dyn_struct = &val_struct as &dyn TraitA;
+    let size_dyn_struct = unsafe { size_of_val(val_dyn_struct as *const dyn 
TraitA) };
+
+    let val_u8: u8 = 7;
+    let size_u8 = unsafe { size_of_val(&val_u8 as *const u8) };
+
+    let val_dyn_u8 = &val_u8 as &dyn TraitA;
+    let size_dyn_u8 = unsafe { size_of_val(val_dyn_u8 as *const dyn TraitA) };
+
+    if size_i32 != 4 {
+        1
+    } else if size_struct != 8 {
+        2
+    } else if size_slice != 12 {
+        3
+    } else if size_str != 5 {
+        4
+    } else if size_dyn_struct != 8 {
+        5
+    } else if size_u8 != 1 {
+        6
+    } else if size_dyn_u8 != 1 {
+        7
+    } else {
+        0
+    }
+}

base-commit: 52a1e948dba4b04740d5aed8ee0afea399509eae
-- 
2.54.0

Reply via email to