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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits