From: Yap Zhi Heng <[email protected]>
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]>
---
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/84167f9bff1edb231d611e9b851f27bd4fe79b9e
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/4745
.../typecheck/rust-hir-type-check-base.cc | 50 ++++---
.../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(-)
create mode 100644 gcc/testsuite/rust/compile/repr_simd.rs
diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.cc
b/gcc/rust/typecheck/rust-hir-type-check-base.cc
index f966f002a..4c276ce83 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 44d5434b1..112ba0b41 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 1f8cddef4..52be8e2f6 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 3eaf23a3c..d607c6b49 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 000000000..c8f4dc382
--- /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
base-commit: db418335d71d605968d9d4978d2e312f58c1c59e
--
2.54.0