c-rhodes updated this revision to Diff 278430.
c-rhodes added a comment.

Changes:

- Documented internal type attributes.
- Set `ASTNode = 0` on user-facing `ArmSveVectorBitsAttr` as the internal type 
attrs are used in the AST. Also removed the case for this from `TypePrinter`.
- `getSveVectorWidth` now returns an `unsigned`. Added an unreachable if `T` 
has no attrs.
- `s/getArmSveVectorBits/getBitwidthForAttributedSveType`. Also now returns an 
`unsigned` and asserts if `!T->isVLST()`.
- Add a few comments in test and reduced them a little so we dont tell all 
types for structs / unions etc.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D83551/new/

https://reviews.llvm.org/D83551

Files:
  clang/include/clang/AST/ASTContext.h
  clang/include/clang/AST/Type.h
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/ASTContext.cpp
  clang/lib/AST/Type.cpp
  clang/lib/AST/TypePrinter.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaType.cpp
  clang/test/Sema/attr-arm-sve-vector-bits.c

Index: clang/test/Sema/attr-arm-sve-vector-bits.c
===================================================================
--- clang/test/Sema/attr-arm-sve-vector-bits.c
+++ clang/test/Sema/attr-arm-sve-vector-bits.c
@@ -60,3 +60,165 @@
 typedef float badtype3 __attribute__((arm_sve_vector_bits(N)));         // expected-error {{'arm_sve_vector_bits' attribute applied to non-SVE type 'float'}}
 typedef svint8x2_t badtype4 __attribute__((arm_sve_vector_bits(N)));    // expected-error {{'arm_sve_vector_bits' attribute applied to non-SVE type 'svint8x2_t' (aka '__clang_svint8x2_t')}}
 typedef svfloat32x3_t badtype5 __attribute__((arm_sve_vector_bits(N))); // expected-error {{'arm_sve_vector_bits' attribute applied to non-SVE type 'svfloat32x3_t' (aka '__clang_svfloat32x3_t')}}
+
+// Test that we can define non-local fixed-length SVE types (unsupported for
+// sizeless types).
+fixed_int8_t global_int8;
+fixed_bfloat16_t global_bfloat16;
+fixed_bool_t global_bool;
+
+extern fixed_int8_t extern_int8;
+extern fixed_bfloat16_t extern_bfloat16;
+extern fixed_bool_t extern_bool;
+
+static fixed_int8_t static_int8;
+static fixed_bfloat16_t static_bfloat16;
+static fixed_bool_t static_bool;
+
+fixed_int8_t *global_int8_ptr;
+extern fixed_int8_t *extern_int8_ptr;
+static fixed_int8_t *static_int8_ptr;
+__thread fixed_int8_t thread_int8;
+
+typedef fixed_int8_t int8_typedef;
+typedef fixed_int8_t *int8_ptr_typedef;
+
+// Test sized expressions
+int sizeof_int8 = sizeof(global_int8);
+int sizeof_int8_var = sizeof(*global_int8_ptr);
+int sizeof_int8_var_ptr = sizeof(global_int8_ptr);
+
+extern fixed_int8_t *extern_int8_ptr;
+
+int alignof_int8 = __alignof__(extern_int8);
+int alignof_int8_var = __alignof__(*extern_int8_ptr);
+int alignof_int8_var_ptr = __alignof__(extern_int8_ptr);
+
+void f(int c) {
+  fixed_int8_t fs8;
+  svint8_t ss8;
+
+  void *sel __attribute__((unused));
+  sel = c ? ss8 : fs8; // expected-error {{incompatible operand types ('svint8_t' (aka '__SVInt8_t') and 'fixed_int8_t' (aka '__SVInt8_t'))}}
+  sel = c ? fs8 : ss8; // expected-error {{incompatible operand types ('fixed_int8_t' (aka '__SVInt8_t') and 'svint8_t' (aka '__SVInt8_t'))}}
+}
+
+// --------------------------------------------------------------------------//
+// Sizeof
+
+#define VECTOR_SIZE ((N / 8))
+#define PRED_SIZE ((N / 64))
+
+_Static_assert(sizeof(fixed_int8_t) == VECTOR_SIZE, "");
+
+_Static_assert(sizeof(fixed_int16_t) == VECTOR_SIZE, "");
+_Static_assert(sizeof(fixed_int32_t) == VECTOR_SIZE, "");
+_Static_assert(sizeof(fixed_int64_t) == VECTOR_SIZE, "");
+
+_Static_assert(sizeof(fixed_uint8_t) == VECTOR_SIZE, "");
+_Static_assert(sizeof(fixed_uint16_t) == VECTOR_SIZE, "");
+_Static_assert(sizeof(fixed_uint32_t) == VECTOR_SIZE, "");
+_Static_assert(sizeof(fixed_uint64_t) == VECTOR_SIZE, "");
+
+_Static_assert(sizeof(fixed_float16_t) == VECTOR_SIZE, "");
+_Static_assert(sizeof(fixed_float32_t) == VECTOR_SIZE, "");
+_Static_assert(sizeof(fixed_float64_t) == VECTOR_SIZE, "");
+
+_Static_assert(sizeof(fixed_bfloat16_t) == VECTOR_SIZE, "");
+
+_Static_assert(sizeof(fixed_bool_t) == PRED_SIZE, "");
+
+// --------------------------------------------------------------------------//
+// Alignof
+
+#define VECTOR_ALIGN 16
+#define PRED_ALIGN 2
+
+_Static_assert(__alignof__(fixed_int8_t) == VECTOR_ALIGN, "");
+_Static_assert(__alignof__(fixed_int16_t) == VECTOR_ALIGN, "");
+_Static_assert(__alignof__(fixed_int32_t) == VECTOR_ALIGN, "");
+_Static_assert(__alignof__(fixed_int64_t) == VECTOR_ALIGN, "");
+
+_Static_assert(__alignof__(fixed_uint8_t) == VECTOR_ALIGN, "");
+_Static_assert(__alignof__(fixed_uint16_t) == VECTOR_ALIGN, "");
+_Static_assert(__alignof__(fixed_uint32_t) == VECTOR_ALIGN, "");
+_Static_assert(__alignof__(fixed_uint64_t) == VECTOR_ALIGN, "");
+
+_Static_assert(__alignof__(fixed_float16_t) == VECTOR_ALIGN, "");
+_Static_assert(__alignof__(fixed_float32_t) == VECTOR_ALIGN, "");
+_Static_assert(__alignof__(fixed_float64_t) == VECTOR_ALIGN, "");
+
+_Static_assert(__alignof__(fixed_bfloat16_t) == VECTOR_ALIGN, "");
+
+_Static_assert(__alignof__(fixed_bool_t) == PRED_ALIGN, "");
+
+// --------------------------------------------------------------------------//
+// Structs
+
+struct struct_int64 { fixed_int64_t x, y[5]; };
+struct struct_float64 { fixed_float64_t x, y[5]; };
+struct struct_bfloat16 { fixed_bfloat16_t x, y[5]; };
+struct struct_bool { fixed_bool_t x, y[5]; };
+
+// --------------------------------------------------------------------------//
+// Unions
+union union_int64 { fixed_int64_t x, y[5]; };
+union union_float64 { fixed_float64_t x, y[5]; };
+union union_bfloat16 { fixed_bfloat16_t x, y[5]; };
+union union_bool { fixed_bool_t x, y[5]; };
+
+// --------------------------------------------------------------------------//
+// Implicit casts
+
+#define TEST_CAST(TYPE)                                          \
+  sv##TYPE##_t to_sv##TYPE##_t(fixed_##TYPE##_t x) { return x; } \
+  fixed_##TYPE##_t from_sv##TYPE##_t(sv##TYPE##_t x) { return x; }
+
+TEST_CAST(int8)
+TEST_CAST(int16)
+TEST_CAST(int32)
+TEST_CAST(int64)
+TEST_CAST(uint8)
+TEST_CAST(uint16)
+TEST_CAST(uint32)
+TEST_CAST(uint64)
+TEST_CAST(float16)
+TEST_CAST(float32)
+TEST_CAST(float64)
+TEST_CAST(bfloat16)
+TEST_CAST(bool)
+
+// Test the implicit conversion only applies to valid types
+fixed_int8_t to_fixed_int8_t__from_svuint8_t(svuint8_t x) { return x; } // expected-error {{returning 'svuint8_t' (aka '__SVUint8_t') from a function with incompatible result type 'fixed_int8_t' (aka '__SVInt8_t')}}
+fixed_bool_t to_fixed_bool_t__from_svint32_t(svint32_t x) { return x; } // expected-error {{returning 'svint32_t' (aka '__SVInt32_t') from a function with incompatible result type 'fixed_bool_t' (aka '__SVBool_t')}}
+
+// Test the implicit conversion only applies to fixed-length types
+typedef signed int vSInt32 __attribute__((__vector_size__(16)));
+svint32_t to_svint32_t_from_gnut(vSInt32 x) { return x; } // expected-error {{returning 'vSInt32' (vector of 4 'int' values) from a function with incompatible result type 'svint32_t' (aka '__SVInt32_t')}}
+
+vSInt32 to_gnut_from_svint32_t(svint32_t x) { return x; } // expected-error {{returning 'svint32_t' (aka '__SVInt32_t') from a function with incompatible result type 'vSInt32' (vector of 4 'int' values)}}
+
+// --------------------------------------------------------------------------//
+// Test the scalable and fixed-length types can be used interchangeably
+
+svint32_t __attribute__((overloadable)) svfunc(svint32_t op1, svint32_t op2);
+svfloat64_t __attribute__((overloadable)) svfunc(svfloat64_t op1, svfloat64_t op2);
+svbool_t __attribute__((overloadable)) svfunc(svbool_t op1, svbool_t op2);
+
+#define TEST_CALL(TYPE)                                              \
+  fixed_##TYPE##_t                                                   \
+      call_##TYPE##_ff(fixed_##TYPE##_t op1, fixed_##TYPE##_t op2) { \
+    return svfunc(op1, op2);                                         \
+  }                                                                  \
+  fixed_##TYPE##_t                                                   \
+      call_##TYPE##_fs(fixed_##TYPE##_t op1, sv##TYPE##_t op2) {     \
+    return svfunc(op1, op2);                                         \
+  }                                                                  \
+  fixed_##TYPE##_t                                                   \
+      call_##TYPE##_sf(sv##TYPE##_t op1, fixed_##TYPE##_t op2) {     \
+    return svfunc(op1, op2);                                         \
+  }
+
+TEST_CALL(int32)
+TEST_CALL(float64)
+TEST_CALL(bool)
Index: clang/lib/Sema/SemaType.cpp
===================================================================
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -2303,7 +2303,7 @@
       return QualType();
   }
 
-  if (T->isSizelessType()) {
+  if (T->isSizelessType() && !T->isVLST()) {
     Diag(Loc, diag::err_array_incomplete_or_sizeless_type) << 1 << T;
     return QualType();
   }
@@ -7758,10 +7758,14 @@
 /// HandleArmSveVectorBitsTypeAttr - The "arm_sve_vector_bits" attribute is
 /// used to create fixed-length versions of sizeless SVE types defined by
 /// the ACLE, such as svint32_t and svbool_t.
-static void HandleArmSveVectorBitsTypeAttr(QualType &CurType,
-                                           const ParsedAttr &Attr, Sema &S) {
+static void HandleArmSveVectorBitsTypeAttr(TypeProcessingState &State,
+                                           QualType &CurType,
+                                           ParsedAttr &Attr) {
+  Sema &S = State.getSema();
+  ASTContext &Ctx = S.Context;
+
   // Target must have SVE.
-  if (!S.Context.getTargetInfo().hasFeature("sve")) {
+  if (!Ctx.getTargetInfo().hasFeature("sve")) {
     S.Diag(Attr.getLoc(), diag::err_attribute_unsupported) << Attr;
     Attr.setInvalid();
     return;
@@ -7805,6 +7809,29 @@
     Attr.setInvalid();
     return;
   }
+
+  clang::Attr *A;
+  switch (SveVectorSizeInBits.getZExtValue()) {
+  default:
+    llvm_unreachable("unsupported vector size!");
+  case 128:
+    A = createSimpleAttr<ArmSveVectorBits128Attr>(Ctx, Attr);
+    break;
+  case 256:
+    A = createSimpleAttr<ArmSveVectorBits256Attr>(Ctx, Attr);
+    break;
+  case 512:
+    A = createSimpleAttr<ArmSveVectorBits512Attr>(Ctx, Attr);
+    break;
+  case 1024:
+    A = createSimpleAttr<ArmSveVectorBits1024Attr>(Ctx, Attr);
+    break;
+  case 2048:
+    A = createSimpleAttr<ArmSveVectorBits2048Attr>(Ctx, Attr);
+    break;
+  }
+
+  CurType = State.getAttributedType(A, CurType, CurType);
 }
 
 static void HandleArmMveStrictPolymorphismAttr(TypeProcessingState &State,
@@ -8071,7 +8098,7 @@
       attr.setUsedAsTypeAttr();
       break;
     case ParsedAttr::AT_ArmSveVectorBits:
-      HandleArmSveVectorBitsTypeAttr(type, attr, state.getSema());
+      HandleArmSveVectorBitsTypeAttr(state, type, attr);
       attr.setUsedAsTypeAttr();
       break;
     case ParsedAttr::AT_ArmMveStrictPolymorphism: {
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -8001,7 +8001,7 @@
     return;
   }
 
-  if (!NewVD->hasLocalStorage() && T->isSizelessType()) {
+  if (!NewVD->hasLocalStorage() && T->isSizelessType() && !T->isVLST()) {
     Diag(NewVD->getLocation(), diag::err_sizeless_nonlocal) << T;
     NewVD->setInvalidDecl();
     return;
Index: clang/lib/AST/TypePrinter.cpp
===================================================================
--- clang/lib/AST/TypePrinter.cpp
+++ clang/lib/AST/TypePrinter.cpp
@@ -1632,8 +1632,20 @@
   case attr::ArmMveStrictPolymorphism:
     OS << "__clang_arm_mve_strict_polymorphism";
     break;
-  case attr::ArmSveVectorBits:
-    OS << "arm_sve_vector_bits";
+  case attr::ArmSveVectorBits128:
+    OS << "arm_sve_vector_bits(128)";
+    break;
+  case attr::ArmSveVectorBits256:
+    OS << "arm_sve_vector_bits(256)";
+    break;
+  case attr::ArmSveVectorBits512:
+    OS << "arm_sve_vector_bits(512)";
+    break;
+  case attr::ArmSveVectorBits1024:
+    OS << "arm_sve_vector_bits(1024)";
+    break;
+  case attr::ArmSveVectorBits2048:
+    OS << "arm_sve_vector_bits(2048)";
     break;
   }
   OS << "))";
Index: clang/lib/AST/Type.cpp
===================================================================
--- clang/lib/AST/Type.cpp
+++ clang/lib/AST/Type.cpp
@@ -2318,6 +2318,20 @@
   return false;
 }
 
+bool Type::isVLST() const {
+  if (!isVLSTBuiltinType())
+    return false;
+
+  if (hasAttr(attr::ArmSveVectorBits128) ||
+      hasAttr(attr::ArmSveVectorBits256) ||
+      hasAttr(attr::ArmSveVectorBits512) ||
+      hasAttr(attr::ArmSveVectorBits1024) ||
+      hasAttr(attr::ArmSveVectorBits2048))
+    return true;
+
+  return false;
+}
+
 bool QualType::isPODType(const ASTContext &Context) const {
   // C++11 has a more relaxed definition of POD.
   if (Context.getLangOpts().CPlusPlus11)
Index: clang/lib/AST/ASTContext.cpp
===================================================================
--- clang/lib/AST/ASTContext.cpp
+++ clang/lib/AST/ASTContext.cpp
@@ -1869,6 +1869,51 @@
   return TI;
 }
 
+unsigned getSveVectorWidth(const Type *T) {
+  if (T->hasAttr(attr::ArmSveVectorBits128))
+    return 128;
+  else if (T->hasAttr(attr::ArmSveVectorBits256))
+    return 256;
+  else if (T->hasAttr(attr::ArmSveVectorBits512))
+    return 512;
+  else if (T->hasAttr(attr::ArmSveVectorBits1024))
+    return 1024;
+  else if (T->hasAttr(attr::ArmSveVectorBits2048))
+    return 2048;
+
+  llvm_unreachable("missing 'arm_sve_vector_bits' attribute!");
+}
+
+unsigned getSvePredWidth(const Type *T) {
+  // Bit per byte
+  return getSveVectorWidth(T) / 8;
+}
+
+unsigned ASTContext::getBitwidthForAttributedSveType(const Type *T) const {
+  assert(T->isVLST() &&
+         "getBitwidthForAttributedSveType called for non-attributed type!");
+
+  switch (T->castAs<BuiltinType>()->getKind()) {
+  default:
+    llvm_unreachable("unknown builtin type!");
+  case BuiltinType::SveInt8:
+  case BuiltinType::SveInt16:
+  case BuiltinType::SveInt32:
+  case BuiltinType::SveInt64:
+  case BuiltinType::SveUint8:
+  case BuiltinType::SveUint16:
+  case BuiltinType::SveUint32:
+  case BuiltinType::SveUint64:
+  case BuiltinType::SveFloat16:
+  case BuiltinType::SveFloat32:
+  case BuiltinType::SveFloat64:
+  case BuiltinType::SveBFloat16:
+    return getSveVectorWidth(T);
+  case BuiltinType::SveBool:
+    return getSvePredWidth(T);
+  }
+}
+
 /// getTypeInfoImpl - Return the size of the specified type, in bits.  This
 /// method does not work on incomplete types.
 ///
@@ -2280,9 +2325,15 @@
   case Type::Elaborated:
     return getTypeInfo(cast<ElaboratedType>(T)->getNamedType().getTypePtr());
 
-  case Type::Attributed:
-    return getTypeInfo(
-                  cast<AttributedType>(T)->getEquivalentType().getTypePtr());
+  case Type::Attributed: {
+    TypeInfo Info =
+        getTypeInfo(cast<AttributedType>(T)->getEquivalentType().getTypePtr());
+    if (!T->isVLST())
+      return Info;
+    Width = getBitwidthForAttributedSveType(T);
+    Align = Info.Align;
+    break;
+  }
 
   case Type::Atomic: {
     // Start with the base type information.
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -1997,7 +1997,10 @@
   bool RequireCompleteSizedType(SourceLocation Loc, QualType T, unsigned DiagID,
                                 const Ts &... Args) {
     SizelessTypeDiagnoser<Ts...> Diagnoser(DiagID, Args...);
-    return RequireCompleteType(Loc, T, CompleteTypeKind::Normal, Diagnoser);
+    CompleteTypeKind Kind = CompleteTypeKind::Normal;
+    if (T->isVLST())
+      Kind = CompleteTypeKind::AcceptSizeless;
+    return RequireCompleteType(Loc, T, Kind, Diagnoser);
   }
 
   void completeExprArrayBound(Expr *E);
@@ -2015,7 +2018,10 @@
   bool RequireCompleteSizedExprType(Expr *E, unsigned DiagID,
                                     const Ts &... Args) {
     SizelessTypeDiagnoser<Ts...> Diagnoser(DiagID, Args...);
-    return RequireCompleteExprType(E, CompleteTypeKind::Normal, Diagnoser);
+    CompleteTypeKind Kind = CompleteTypeKind::Normal;
+    if (E->getType()->isVLST())
+      Kind = CompleteTypeKind::AcceptSizeless;
+    return RequireCompleteExprType(E, Kind, Diagnoser);
   }
 
   bool RequireLiteralType(SourceLocation Loc, QualType T,
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -1536,6 +1536,42 @@
   let Spellings = [GNU<"arm_sve_vector_bits">];
   let Args = [IntArgument<"NumBits">];
   let Documentation = [ArmSveVectorBitsDocs];
+  // Represented internally as ArmSveVectorBits<n> type attributes.
+  let ASTNode = 0;
+}
+
+// ArmSveVectorBits type attributes for each supported vector-length. These are
+// intended for internal use only and are therefore undocumented. Users should
+// use the user-facing ArmSveVectorBits attribute that is lowered to one of
+// these attributes.
+def ArmSveVectorBits128 : TypeAttr {
+  let Spellings = [];
+  let Documentation = [Undocumented];
+  let SemaHandler = 0;
+}
+
+def ArmSveVectorBits256 : TypeAttr {
+  let Spellings = [];
+  let Documentation = [Undocumented];
+  let SemaHandler = 0;
+}
+
+def ArmSveVectorBits512 : TypeAttr {
+  let Spellings = [];
+  let Documentation = [Undocumented];
+  let SemaHandler = 0;
+}
+
+def ArmSveVectorBits1024 : TypeAttr {
+  let Spellings = [];
+  let Documentation = [Undocumented];
+  let SemaHandler = 0;
+}
+
+def ArmSveVectorBits2048 : TypeAttr {
+  let Spellings = [];
+  let Documentation = [Undocumented];
+  let SemaHandler = 0;
 }
 
 def ArmMveStrictPolymorphism : TypeAttr, TargetSpecificAttr<TargetARM> {
Index: clang/include/clang/AST/Type.h
===================================================================
--- clang/include/clang/AST/Type.h
+++ clang/include/clang/AST/Type.h
@@ -1925,6 +1925,9 @@
   bool isSizelessType() const;
   bool isSizelessBuiltinType() const;
 
+  /// Determines if this is vector-length sized typed (VLST), i.e. a
+  /// sizeless type with the 'arm_sve_vector_bits(N)' attribute applied.
+  bool isVLST() const;
   /// Determines if this is a sizeless type supported by the
   /// 'arm_sve_vector_bits' type attribute, which can be applied to a single
   /// SVE vector or predicate, excluding tuple types such as svint32x4_t.
Index: clang/include/clang/AST/ASTContext.h
===================================================================
--- clang/include/clang/AST/ASTContext.h
+++ clang/include/clang/AST/ASTContext.h
@@ -2086,6 +2086,10 @@
     return getTypeSizeInCharsIfKnown(QualType(Ty, 0));
   }
 
+  /// Returns the bitwidth of \p T, an SVE type attributed with
+  /// 'arm_sve_vector_bits(N)'. Should only be called if T->isVLST().
+  unsigned getBitwidthForAttributedSveType(const Type *T) const;
+
   /// Return the ABI-specified alignment of a (complete) type \p T, in
   /// bits.
   unsigned getTypeAlign(QualType T) const { return getTypeInfo(T).Align; }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to