https://gcc.gnu.org/g:b7a9ebe63ddb3112b63ea9ad6629d08a7d8dc47a
commit r17-2256-gb7a9ebe63ddb3112b63ea9ad6629d08a7d8dc47a Author: Enes Cevik <[email protected]> Date: Tue Jun 30 10:14:36 2026 +0300 gccrs: intrinsic: Add min_align_of_val 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]> Diff: --- gcc/rust/backend/rust-compile-intrinsic.cc | 1 + gcc/rust/backend/rust-intrinsic-handlers.cc | 100 +++++++++++++++++++++ gcc/rust/backend/rust-intrinsic-handlers.h | 2 + .../typecheck/rust-hir-type-check-intrinsic.cc | 2 + gcc/rust/util/rust-intrinsic-values.h | 1 + gcc/testsuite/rust/execute/min-align-of-val.rs | 64 +++++++++++++ 6 files changed, 170 insertions(+) diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc b/gcc/rust/backend/rust-compile-intrinsic.cc index 05187c35ca4b..205bf4113962 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 d08b1e2e2d61..b119593b8a92 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 58f52650a451..8916c59f39c1 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 bfb5baf3161a..df596c58a4e4 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 35e76a87c349..d79326459116 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 000000000000..eb01f5bcefe7 --- /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 + } +}
