From: Enes Cevik <[email protected]>
This patch adds the min_align_of_val intrinsic to the compiler. This
intrinsic evaluates the align of a value at runtime, including
Dynamically Sized Types (DSTs).
gcc/rust/ChangeLog:
* backend/rust-compile-intrinsic.cc (generic_intrinsics): Add
min_align_of_val_handler to the map.
* backend/rust-intrinsic-handlers.cc (min_align_of_val_handler):
New function.
* backend/rust-intrinsic-handlers.h (min_align_of_val_handler):
New declaration.
* typecheck/rust-hir-type-check-intrinsic.cc
(IntrinsicChecker::intrinsic_rules): Add min_align_of_val
signature rule to the map.
* util/rust-intrinsic-values.h (class Intrinsics): Add
MIN_ALIGN_OF_VAL constexpr.
gcc/testsuite/ChangeLog:
* rust/execute/min-align-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/33c94177a20f00ac0b849b531927a32127235102
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 | 100 ++++++++++++++++++
gcc/rust/backend/rust-intrinsic-handlers.h | 2 +
.../rust-hir-type-check-intrinsic.cc | 2 +
gcc/rust/util/rust-intrinsic-values.h | 1 +
.../rust/execute/min-align-of-val.rs | 64 +++++++++++
6 files changed, 170 insertions(+)
create mode 100644 gcc/testsuite/rust/execute/min-align-of-val.rs
diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc
b/gcc/rust/backend/rust-compile-intrinsic.cc
index 05187c35c..205bf4113 100644
--- a/gcc/rust/backend/rust-compile-intrinsic.cc
+++ b/gcc/rust/backend/rust-compile-intrinsic.cc
@@ -34,6 +34,7 @@ static const std::map<std::string, handlers::HandlerBuilder>
generic_intrinsics
{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::MIN_ALIGN_OF_VAL, handlers::min_align_of_val_handler},
{IValue::TRANSMUTE, handlers::transmute},
{IValue::ROTATE_LEFT, handlers::rotate_left},
{IValue::ROTATE_RIGHT, handlers::rotate_right},
diff --git a/gcc/rust/backend/rust-intrinsic-handlers.cc
b/gcc/rust/backend/rust-intrinsic-handlers.cc
index d08b1e2e2..b119593b8 100644
--- a/gcc/rust/backend/rust-intrinsic-handlers.cc
+++ b/gcc/rust/backend/rust-intrinsic-handlers.cc
@@ -1750,6 +1750,106 @@ min_align_of_handler (Context *ctx, TyTy::FnType
*fntype, location_t)
return fndecl;
}
+/**
+ * pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize;
+ */
+tree
+min_align_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 align_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;
+
+ align_expr
+ = build_int_cst (size_type_node, TYPE_ALIGN_UNIT (elem_type));
+ }
+ 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_1 = DECL_CHAIN (vtable_field_0);
+ tree vtable_field_align = DECL_CHAIN (vtable_field_1);
+ rust_assert (vtable_field_align != NULL_TREE);
+
+ align_expr
+ = build3_loc (locus, COMPONENT_REF, TREE_TYPE (vtable_field_align),
+ vtable_ref, vtable_field_align, NULL_TREE);
+ }
+ else
+ {
+ rust_unreachable ();
+ }
+ }
+ else
+ align_expr = build_int_cst (size_type_node,
+ TYPE_ALIGN_UNIT (template_parameter_type));
+
+ auto return_statement
+ = Backend::return_statement (fndecl, align_expr, UNDEF_LOCATION);
+ ctx->add_statement (return_statement);
+
+ // BUILTIN size_of FN BODY END
+
+ finalize_intrinsic_block (ctx, fndecl);
+
+ return fndecl;
+}
+
tree
offset (Context *ctx, TyTy::FnType *fntype, location_t expr_locus)
{
diff --git a/gcc/rust/backend/rust-intrinsic-handlers.h
b/gcc/rust/backend/rust-intrinsic-handlers.h
index 58f52650a..8916c59f3 100644
--- a/gcc/rust/backend/rust-intrinsic-handlers.h
+++ b/gcc/rust/backend/rust-intrinsic-handlers.h
@@ -62,6 +62,8 @@ 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 min_align_of_val_handler (Context *ctx, TyTy::FnType *fntype,
+ location_t expr_locus);
tree transmute (Context *ctx, TyTy::FnType *fntype, location_t expr_locus);
tree rotate (Context *ctx, TyTy::FnType *fntype, tree_code op);
tree uninit (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 bfb5baf31..df596c58a 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
@@ -267,6 +267,8 @@ const std::unordered_map<std::string, IntrinsicRules>
{IValue::ASSUME, {0, {IRT::Bool}, IRT::Unit}},
// pub fn min_align_of<T>() -> usize;
{IValue::MIN_ALIGN_OF, {1, {}, IRT::Usize}},
+ // pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize;
+ {IValue::MIN_ALIGN_OF_VAL, {1, {IRT::ConstPtrFirstGeneric}, IRT::Usize}},
// pub fn needs_drop<T>() -> bool;
{IValue::NEEDS_DROP, {1, {}, IRT::Bool}},
// pub fn caller_location() -> &'static crate::panic::Location<'static>;
diff --git a/gcc/rust/util/rust-intrinsic-values.h
b/gcc/rust/util/rust-intrinsic-values.h
index 35e76a87c..d79326459 100644
--- a/gcc/rust/util/rust-intrinsic-values.h
+++ b/gcc/rust/util/rust-intrinsic-values.h
@@ -138,6 +138,7 @@ public:
static constexpr auto &ASSUME = "assume";
static constexpr auto &MIN_ALIGN_OF = "min_align_of";
+ static constexpr auto &MIN_ALIGN_OF_VAL = "min_align_of_val";
static constexpr auto &NEEDS_DROP = "needs_drop";
static constexpr auto &CALLER_LOCATION = "caller_location";
static constexpr auto &CTPOP = "ctpop";
diff --git a/gcc/testsuite/rust/execute/min-align-of-val.rs
b/gcc/testsuite/rust/execute/min-align-of-val.rs
new file mode 100644
index 000000000..eb01f5bce
--- /dev/null
+++ b/gcc/testsuite/rust/execute/min-align-of-val.rs
@@ -0,0 +1,64 @@
+// { dg-require-effective-target lp64 }
+#![feature(no_core, intrinsics, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+pub trait Sized {}
+
+extern "rust-intrinsic" {
+ pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize;
+}
+
+trait TraitA {
+ fn foo(&self) {}
+}
+
+struct StructA {
+ _a: i32,
+ _b: i16,
+}
+
+impl TraitA for StructA {}
+impl TraitA for u8 {}
+
+fn main() -> i32 {
+ let val_i32: i32 = 32;
+ let align_i32 = unsafe { min_align_of_val(&val_i32 as *const i32) };
+
+ let val_struct = StructA { _a: 1, _b: 2 };
+ let align_struct = unsafe { min_align_of_val(&val_struct as *const
StructA) };
+
+ let arr: [i32; 3] = [10, 20, 30];
+ let val_slice: &[i32] = &arr;
+ let align_slice = unsafe { min_align_of_val(val_slice as *const [i32]) };
+
+ let val_str: &str = "gccrs";
+ let align_str = unsafe { min_align_of_val(val_str as *const str) };
+
+ let val_dyn_struct = &val_struct as &dyn TraitA;
+ let align_dyn_struct = unsafe { min_align_of_val(val_dyn_struct as *const
dyn TraitA) };
+
+ let val_u8: u8 = 7;
+ let align_u8 = unsafe { min_align_of_val(&val_u8 as *const u8) };
+
+ let val_dyn_u8 = &val_u8 as &dyn TraitA;
+ let align_dyn_u8 = unsafe { min_align_of_val(val_dyn_u8 as *const dyn
TraitA) };
+
+ if align_i32 != 4 {
+ 1
+ } else if align_struct != 4 {
+ 2
+ } else if align_slice != 4 {
+ 3
+ } else if align_str != 1 {
+ 4
+ } else if align_dyn_struct != 4 {
+ 5
+ } else if align_u8 != 1 {
+ 6
+ } else if align_dyn_u8 != 1 {
+ 7
+ } else {
+ 0
+ }
+}
--
2.54.0