return TI;
}
+static 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!");
+}
+
+static unsigned getSvePredWidth(const ASTContext &Context, const Type *T) {
+ return getSveVectorWidth(T) / Context.getCharWidth();
+}
+
+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(*this, T);
+ }
+}
+
/// getTypeInfoImpl - Return the size of the specified type, in bits. This
/// method does not work on incomplete types.
///
Align = Info.Align;
AlignIsRequired = Info.AlignIsRequired;
}
- Width = Info.Width;
+ if (T->isVLST())
+ Width = getBitwidthForAttributedSveType(T);
+ else
+ Width = Info.Width;
break;
}
return QualType();
}
- if (T->isSizelessType()) {
+ if (T->isSizelessType() && !T->isVLST()) {
Diag(Loc, diag::err_array_incomplete_or_sizeless_type) << 1 << T;
return QualType();
}
/// 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;
Attr.setInvalid();
return;
}
+
+ auto *A = ::new (Ctx) ArmSveVectorBitsAttr(Ctx, Attr, VecSize);
+ CurType = State.getAttributedType(A, CurType, CurType);
}
static void HandleArmMveStrictPolymorphismAttr(TypeProcessingState &State,
attr.setUsedAsTypeAttr();
break;
case ParsedAttr::AT_ArmSveVectorBits:
- HandleArmSveVectorBitsTypeAttr(type, attr, state.getSema());
+ HandleArmSveVectorBitsTypeAttr(state, type, attr);
attr.setUsedAsTypeAttr();
break;
case ParsedAttr::AT_ArmMveStrictPolymorphism: {
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)