c-rhodes updated this revision to Diff 279178.
c-rhodes added a comment.
Changes:
- Remove internal type attributes (defined for each vector-size).
- Get the vector size from the `arm_sve_vector_bits` attribute via the
`AttributedTypeLoc` associated with the typedef decl.
- Change `NumBits` argument for `ArmSveVectorBits` type attribute from int to
unsigned.
- Only allow `ArmSveVectorBits` type attribute to be applied to typedefs (and
added test).
- Set `let PragmaAttributeSupport = 0;` after specifying `Subjects` to fixed
`clang/test/Misc/pragma-attribute-supported-attributes-list.test`.
- `vector-length sized` -> `vector-length-sized`.
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/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,168 @@
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')}}
+
+// Attribute only applies to typedefs.
+svint8_t non_typedef_type __attribute__((arm_sve_vector_bits(N))); // expected-error {{'arm_sve_vector_bits' attribute only applies to typedefs}}
+
+// 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();
}
@@ -7751,10 +7751,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;
@@ -7798,6 +7802,9 @@
Attr.setInvalid();
return;
}
+
+ auto *A = ::new (Ctx) ArmSveVectorBitsAttr(Ctx, Attr, VecSize);
+ CurType = State.getAttributedType(A, CurType, CurType);
}
static void HandleArmMveStrictPolymorphismAttr(TypeProcessingState &State,
@@ -8064,7 +8071,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
@@ -8004,7 +8004,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/Type.cpp
===================================================================
--- clang/lib/AST/Type.cpp
+++ clang/lib/AST/Type.cpp
@@ -2318,6 +2318,13 @@
return false;
}
+bool Type::isVLST() const {
+ if (!isVLSTBuiltinType())
+ return false;
+
+ return hasAttr(attr::ArmSveVectorBits);
+}
+
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,48 @@
return TI;
}
+unsigned getSveVectorWidth(const Type *T) {
+ // Get the vector size from the 'arm_sve_vector_bits' attribute via the
+ // AttributedTypeLoc associated with the typedef decl.
+ if (const auto *TT = T->getAs<TypedefType>()) {
+ const TypedefNameDecl *Typedef = TT->getDecl();
+ TypeSourceInfo *TInfo = Typedef->getTypeSourceInfo();
+ TypeLoc TL = TInfo->getTypeLoc();
+ if (AttributedTypeLoc ATL = TL.getAs<AttributedTypeLoc>())
+ if (const auto *Attr = ATL.getAttrAs<ArmSveVectorBitsAttr>())
+ return Attr->getNumBits();
+ }
+
+ llvm_unreachable("bad 'arm_sve_vector_bits' attribute!");
+}
+
+unsigned getSvePredWidth(const Type *T) { 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.
///
@@ -2273,7 +2315,10 @@
Align = Info.Align;
AlignIsRequired = Info.AlignIsRequired;
}
- Width = Info.Width;
+ if (T->isVLST())
+ Width = getBitwidthForAttributedSveType(T);
+ else
+ Width = Info.Width;
break;
}
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
@@ -1534,8 +1534,10 @@
def ArmSveVectorBits : TypeAttr {
let Spellings = [GNU<"arm_sve_vector_bits">];
- let Args = [IntArgument<"NumBits">];
+ let Subjects = SubjectList<[TypedefName], ErrorDiag>;
+ let Args = [UnsignedArgument<"NumBits">];
let Documentation = [ArmSveVectorBitsDocs];
+ let PragmaAttributeSupport = 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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits