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
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.