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

Reply via email to