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, ¶m_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 ¶m_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