https://gcc.gnu.org/g:5786caddb307fbe61fb3b6c1a54699336270aa8f
commit r17-4101-g5786caddb307fbe61fb3b6c1a54699336270aa8f Author: Yap Zhi Heng <[email protected]> Date: Sat Aug 1 20:55:48 2026 +0800 gccrs: Implement basic support for #[repr(simd)] Only type-checking support is implemented, simd representation structs are still compiled as regular structs. Note that this implementation is specific to 1.49.0, #[repr(simd)] structs uses a single array field from 1.50.0 onwards. gcc/rust/ChangeLog: * typecheck/rust-tyty.h (ADTType::ReprKind): Add new SIMD variant. * typecheck/rust-hir-type-check-base.cc (TypeCheckBase::parse_repr_options): Parse #[repr(simd)] attribute, rename inline_option to repr_option. * typecheck/rust-hir-type-check-item.h (TypeCheckItem::validate_repr_simd): New function. * typecheck/rust-hir-type-check-item.cc (TypeCheckItem::validate_repr_simd): Implement type-checking of #[repr(simd)] structs. (TypeCheckItem::visit (HIR::TupleStruct)): Support type-checking simd representation. (TypeCheckItem::visit (HIR::StructStruct)): Ditto. Signed-off-by: Yap Zhi Heng <[email protected]> Diff: --- gcc/rust/typecheck/rust-hir-type-check-base.cc | 50 +++++---- gcc/rust/typecheck/rust-hir-type-check-item.cc | 134 ++++++++++++++++++++++++- gcc/rust/typecheck/rust-hir-type-check-item.h | 3 + gcc/rust/typecheck/rust-tyty.h | 2 +- gcc/testsuite/rust/compile/repr_simd.rs | 35 +++++++ 5 files changed, 196 insertions(+), 28 deletions(-) diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.cc b/gcc/rust/typecheck/rust-hir-type-check-base.cc index f966f002aa2b..4c276ce83d0a 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-base.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-base.cc @@ -506,23 +506,24 @@ TypeCheckBase::parse_repr_options (const AST::AttrVec &attrs, location_t locus) continue; } - const std::string inline_option = items.at (0)->as_string (); + const std::string repr_option = items.at (0)->as_string (); // TODO: it would probably be better to make the MetaItems more aware // of constructs with nesting like #[repr(packed(2))] rather than // manually parsing the string "packed(2)" here. - size_t oparen = inline_option.find ('(', 0); + size_t oparen = repr_option.find ('(', 0); bool is_pack = false; bool is_align = false; bool is_c = false; bool is_integer = false; bool is_transparent = false; + bool is_simd = false; unsigned char value = 1; if (oparen == std::string::npos) { - if (inline_option.compare ("align") == 0) + if (repr_option.compare ("align") == 0) { rust_error_at (attr.get_locus (), ErrorCode::E0589, "invalid %<repr(align)%> attribute: %<align%> " @@ -531,36 +532,37 @@ TypeCheckBase::parse_repr_options (const AST::AttrVec &attrs, location_t locus) break; } - is_pack = inline_option.compare ("packed") == 0; - is_c = inline_option.compare ("C") == 0; - is_integer = (inline_option.compare ("isize") == 0 - || inline_option.compare ("i8") == 0 - || inline_option.compare ("i16") == 0 - || inline_option.compare ("i32") == 0 - || inline_option.compare ("i64") == 0 - || inline_option.compare ("i128") == 0 - || inline_option.compare ("usize") == 0 - || inline_option.compare ("u8") == 0 - || inline_option.compare ("u16") == 0 - || inline_option.compare ("u32") == 0 - || inline_option.compare ("u64") == 0 - || inline_option.compare ("u128") == 0); - is_transparent = inline_option.compare ("transparent") == 0; + is_pack = repr_option.compare ("packed") == 0; + is_c = repr_option.compare ("C") == 0; + is_integer = (repr_option.compare ("isize") == 0 + || repr_option.compare ("i8") == 0 + || repr_option.compare ("i16") == 0 + || repr_option.compare ("i32") == 0 + || repr_option.compare ("i64") == 0 + || repr_option.compare ("i128") == 0 + || repr_option.compare ("usize") == 0 + || repr_option.compare ("u8") == 0 + || repr_option.compare ("u16") == 0 + || repr_option.compare ("u32") == 0 + || repr_option.compare ("u64") == 0 + || repr_option.compare ("u128") == 0); + is_transparent = repr_option.compare ("transparent") == 0; + is_simd = repr_option.compare ("simd") == 0; } else { - std::string rep = inline_option.substr (0, oparen); + std::string rep = repr_option.substr (0, oparen); is_pack = rep.compare ("packed") == 0; is_align = rep.compare ("align") == 0; - size_t cparen = inline_option.find (')', oparen); + size_t cparen = repr_option.find (')', oparen); if (cparen == std::string::npos) { rust_error_at (locus, "malformed attribute"); } - std::string value_str = inline_option.substr (oparen, cparen); + std::string value_str = repr_option.substr (oparen, cparen); value = strtoul (value_str.c_str () + 1, NULL, 10); } @@ -594,13 +596,17 @@ TypeCheckBase::parse_repr_options (const AST::AttrVec &attrs, location_t locus) else if (is_integer) { repr.repr_kind = TyTy::ADTType::ReprKind::INT; - bool ok = context->lookup_builtin (inline_option, &repr.repr); + bool ok = context->lookup_builtin (repr_option, &repr.repr); if (!ok) { rust_error_at (attr.get_locus (), ErrorCode::E0552, "unrecognized representation hint"); } } + else if (is_simd) + { + repr.repr_kind = TyTy::ADTType::ReprKind::SIMD; + } else { rust_error_at (attr.get_locus (), ErrorCode::E0552, diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.cc b/gcc/rust/typecheck/rust-hir-type-check-item.cc index 44d5434b1269..112ba0b41653 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-item.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-item.cc @@ -265,6 +265,11 @@ TypeCheckItem::visit (HIR::TupleStruct &struct_decl) ResolveWhereClauseItem::Resolve (*where_clause_item, region_constraints); } + // Process #[repr(X)] attribute, if any + const AST::AttrVec &attrs = struct_decl.get_outer_attrs (); + TyTy::ADTType::ReprOptions repr + = parse_repr_options (attrs, struct_decl.get_locus ()); + std::vector<TyTy::StructFieldType *> fields; size_t idx = 0; for (auto &field : struct_decl.get_fields ()) @@ -280,6 +285,13 @@ TypeCheckItem::visit (HIR::TupleStruct &struct_decl) idx++; } + if (repr.repr_kind == TyTy::ADTType::ReprKind::SIMD) + { + bool is_valid = validate_repr_simd (fields, struct_decl.get_locus ()); + if (!is_valid) + return; + } + // get the path auto &nr_ctx = Resolver2_0::FinalizedNameResolutionContext::get (); @@ -299,11 +311,6 @@ TypeCheckItem::visit (HIR::TupleStruct &struct_decl) TyTy::VariantDef::VariantType::TUPLE, tl::nullopt, std::move (fields))); - // Process #[repr(X)] attribute, if any - const AST::AttrVec &attrs = struct_decl.get_outer_attrs (); - TyTy::ADTType::ReprOptions repr - = parse_repr_options (attrs, struct_decl.get_locus ()); - auto *type = new TyTy::ADTType ( struct_decl.get_mappings ().get_defid (), struct_decl.get_mappings ().get_hirid (), @@ -365,6 +372,12 @@ TypeCheckItem::visit (HIR::StructStruct &struct_decl) context->insert_type (field.get_mappings (), ty_field->get_field_type ()); } + if (repr.repr_kind == TyTy::ADTType::ReprKind::SIMD) + { + bool is_valid = validate_repr_simd (fields, struct_decl.get_locus ()); + if (!is_valid) + return; + } if (repr.repr_kind == TyTy::ADTType::ReprKind::TRANSPARENT) { size_t num_non_zst = 0; @@ -986,5 +999,116 @@ TypeCheckItem::resolve_impl_block_self (HIR::ImplBlock &impl_block) return TypeCheckType::Resolve (impl_block.get_type ()); } +bool +TypeCheckItem::validate_repr_simd ( + const std::vector<TyTy::StructFieldType *> &fields, location_t locus) +{ + if (fields.empty ()) + { + rust_error_at (locus, ErrorCode::E0075, "SIMD vector cannot be empty"); + return false; + } + + // in 1.49, repr simd assumes all fields are same type with its size + // being power-of-two. + // + // TODO update this typecheck to make repr simd take in a single field + // of an array instead when we move past 1.49. Relevant Rust github + // issues/PRs: + // - https://github.com/rust-lang/compiler-team/issues/621 + // - https://github.com/rust-lang/rust/pull/78863 (implemented + // for 1.50.0) + + TyTy::BaseType *first_field_ty = fields.at (0)->get_field_type (); + TyTy::TypeKind ty_kind = first_field_ty->get_kind (); + bool fields_are_same_type = true; + + switch (ty_kind) + { + case TyTy::TypeKind::INT: + { + auto int_ty = static_cast<TyTy::IntType *> (first_field_ty); + auto int_kind = int_ty->get_int_kind (); + for (const auto field : fields) + { + if (field->get_field_type ()->get_kind () != ty_kind) + { + fields_are_same_type = false; + break; + } + auto field_int_ty + = static_cast<TyTy::IntType *> (field->get_field_type ()); + if (field_int_ty->get_int_kind () != int_kind) + { + fields_are_same_type = false; + break; + } + } + break; + } + case TyTy::TypeKind::UINT: + { + auto uint_ty = static_cast<TyTy::UintType *> (first_field_ty); + auto uint_kind = uint_ty->get_uint_kind (); + for (const auto field : fields) + { + if (field->get_field_type ()->get_kind () != ty_kind) + { + fields_are_same_type = false; + break; + } + auto field_uint_ty + = static_cast<TyTy::UintType *> (field->get_field_type ()); + if (field_uint_ty->get_uint_kind () != uint_kind) + { + fields_are_same_type = false; + break; + } + } + break; + } + case TyTy::TypeKind::FLOAT: + { + auto float_ty = static_cast<TyTy::FloatType *> (first_field_ty); + auto float_kind = float_ty->get_float_kind (); + for (const auto field : fields) + { + if (field->get_field_type ()->get_kind () != ty_kind) + { + fields_are_same_type = false; + break; + } + auto field_float_ty + = static_cast<TyTy::FloatType *> (field->get_field_type ()); + if (field_float_ty->get_float_kind () != float_kind) + { + fields_are_same_type = false; + break; + } + } + break; + } + default: + rust_error_at (locus, ErrorCode::E0077, + "SIMD vector element type should be a primitive scalar"); + return false; + } + + if (!fields_are_same_type) + { + rust_error_at (locus, "SIMD struct fields should be of the same type"); + return false; + } + + // check whether field count is power of 2 + size_t field_count = fields.size (); + if ((field_count & (field_count - 1)) != 0) + { + rust_error_at (locus, "Size of SIMD struct must be a power of 2"); + return false; + } + return true; +} + } // namespace Resolver } // namespace Rust diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.h b/gcc/rust/typecheck/rust-hir-type-check-item.h index 1f8cddef4fe3..52be8e2f680a 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-item.h +++ b/gcc/rust/typecheck/rust-hir-type-check-item.h @@ -88,6 +88,9 @@ protected: TyTy::BaseType *resolve_impl_block_self (HIR::ImplBlock &impl_block); + bool validate_repr_simd (const std::vector<TyTy::StructFieldType *> &fields, + location_t locus); + private: TypeCheckItem (); diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index 3eaf23a3ce82..d607c6b49633 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -921,7 +921,7 @@ public: ALIGN, PACKED, TRANSPARENT, - // SIMD, + SIMD, // ... }; diff --git a/gcc/testsuite/rust/compile/repr_simd.rs b/gcc/testsuite/rust/compile/repr_simd.rs new file mode 100644 index 000000000000..c8f4dc382f32 --- /dev/null +++ b/gcc/testsuite/rust/compile/repr_simd.rs @@ -0,0 +1,35 @@ +#![feature(no_core, repr_simd)] +#![no_core] + +// all simd types declared in stdarch/crates/core_arch/src/x86/mod.rs +#[repr(simd)] +pub struct __m128i(i64, i64); +#[repr(simd)] +pub struct __m128(f32, f32, f32, f32); +#[repr(simd)] +pub struct __m128d(f64, f64); +#[repr(simd)] +pub struct __m256i(i64, i64, i64, i64); +#[repr(simd)] +pub struct __m256(f32, f32, f32, f32, f32, f32, f32, f32); +#[repr(simd)] +pub struct __m256d(f64, f64, f64, f64); +#[repr(simd)] +pub struct __m512i(i64, i64, i64, i64, i64, i64, i64, i64); +#[repr(simd)] +pub struct __m512( + f32, f32, f32, f32, f32, f32, f32, f32, + f32, f32, f32, f32, f32, f32, f32, f32, +); +#[repr(simd)] +pub struct __m512d(f64, f64, f64, f64, f64, f64, f64, f64); + +// errorneous simd types +#[repr(simd)] +pub struct Foo (f32, f32, f32); // { dg-error "Size of SIMD struct must be a power of 2" } +#[repr(simd)] +pub struct Bar (f32, i32); // { dg-error "SIMD struct fields should be of the same type" } +#[repr(simd)] +pub struct Baz (str); // { dg-error "SIMD vector element type should be a primitive scalar .E0077." } + +fn main() {} \ No newline at end of file
