diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -2058,6 +2058,11 @@ /// types. bool areCompatibleVectorTypes(QualType FirstVec, QualType SecondVec); + /// Return true if the given types are an SVE builtin and a VectorType that + /// is a fixed-length representation of the SVE builtin for a specific + /// vector-length. + bool areCompatibleSveTypes(QualType FirstType, QualType SecondType); + /// Return true if the type has been explicitly qualified with ObjC ownership. /// A type may be implicitly qualified with ownership under ObjC ARC, and in /// some cases the compiler treats these differently. @@ -2114,10 +2119,6 @@ return getTypeSizeInCharsIfKnown(QualType(Ty, 0)); } - /// Returns the bitwidth of \p T, an SVE type attributed with - /// 'arm_sve_vector_bits'. 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; } diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -1886,14 +1886,16 @@ bool isSizelessType() const; bool isSizelessBuiltinType() const; - /// Determines if this is a vector-length-specific type (VLST), i.e. a - /// sizeless type with the 'arm_sve_vector_bits' 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. bool isVLSTBuiltinType() const; + /// Returns the representative type for the element of an SVE builtin type. + /// This is used to represent fixed-length SVE vectors created with the + /// 'arm_sve_vector_bits' type attribute as VectorType. + QualType getSveEltType(const ASTContext &Ctx) const; + /// Types are partitioned into 3 broad categories (C99 6.2.5p1): /// object types, function types, and incomplete types. @@ -3219,7 +3221,13 @@ NeonVector, /// is ARM Neon polynomial vector - NeonPolyVector + NeonPolyVector, + + /// is AArch64 SVE fixed-length data vector + SveFixedLengthDataVector, + + /// is AArch64 SVE fixed-length predicate vector + SveFixedLengthPredicateVector }; protected: diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1552,6 +1552,8 @@ let Args = [UnsignedArgument<"NumBits">]; let Documentation = [ArmSveVectorBitsDocs]; let PragmaAttributeSupport = 0; + // Represented as VectorType instead. + let ASTNode = 0; } def ArmMveStrictPolymorphism : TypeAttr, TargetSpecificAttr { diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2925,6 +2925,8 @@ "vector size not an integral multiple of component size">; def err_attribute_zero_size : Error<"zero %0 size">; def err_attribute_size_too_large : Error<"%0 size too large">; +def err_typecheck_vector_not_convertable_sizeless : Error< + "cannot convert between a fixed-length and a sizeless vector (%0 and %1)">; def err_typecheck_vector_not_convertable_implict_truncation : Error< "cannot convert between %select{scalar|vector}0 type %1 and vector type" " %2 as implicit conversion would cause truncation">; diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h --- a/clang/include/clang/Sema/Overload.h +++ b/clang/include/clang/Sema/Overload.h @@ -160,6 +160,9 @@ /// Vector conversions ICK_Vector_Conversion, + /// Arm SVE Vector conversions + ICK_SVE_Vector_Conversion, + /// A vector splat from an arithmetic type ICK_Vector_Splat, diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2003,10 +2003,7 @@ bool RequireCompleteSizedType(SourceLocation Loc, QualType T, unsigned DiagID, const Ts &... Args) { SizelessTypeDiagnoser Diagnoser(DiagID, Args...); - CompleteTypeKind Kind = CompleteTypeKind::Normal; - if (T->isVLST()) - Kind = CompleteTypeKind::AcceptSizeless; - return RequireCompleteType(Loc, T, Kind, Diagnoser); + return RequireCompleteType(Loc, T, CompleteTypeKind::Normal, Diagnoser); } void completeExprArrayBound(Expr *E); @@ -2024,10 +2021,7 @@ bool RequireCompleteSizedExprType(Expr *E, unsigned DiagID, const Ts &... Args) { SizelessTypeDiagnoser Diagnoser(DiagID, Args...); - CompleteTypeKind Kind = CompleteTypeKind::Normal; - if (E->getType()->isVLST()) - Kind = CompleteTypeKind::AcceptSizeless; - return RequireCompleteExprType(E, Kind, Diagnoser); + return RequireCompleteExprType(E, CompleteTypeKind::Normal, Diagnoser); } bool RequireLiteralType(SourceLocation Loc, QualType T, diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1871,50 +1871,6 @@ 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()) { - const TypedefNameDecl *Typedef = TT->getDecl(); - TypeSourceInfo *TInfo = Typedef->getTypeSourceInfo(); - TypeLoc TL = TInfo->getTypeLoc(); - if (AttributedTypeLoc ATL = TL.getAs()) - if (const auto *Attr = ATL.getAttrAs()) - 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()->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. /// @@ -1981,6 +1937,13 @@ uint64_t TargetVectorAlign = Target->getMaxVectorAlign(); if (TargetVectorAlign && TargetVectorAlign < Align) Align = TargetVectorAlign; + if (VT->getVectorKind() == VectorType::SveFixedLengthDataVector) + // Adjust the alignment for fixed-length SVE vectors. This is important + // for non-power-of-2 vector lengths. + Align = 128; + else if (VT->getVectorKind() == VectorType::SveFixedLengthPredicateVector) + // Adjust the alignment for fixed-length SVE predicates. + Align = 16; break; } @@ -2319,10 +2282,7 @@ Align = Info.Align; AlignIsRequired = Info.AlignIsRequired; } - if (T->isVLST()) - Width = getBitwidthForAttributedSveType(T); - else - Width = Info.Width; + Width = Info.Width; break; } @@ -8540,6 +8500,31 @@ return false; } +bool ASTContext::areCompatibleSveTypes(QualType FirstType, + QualType SecondType) { + assert(((FirstType->isSizelessBuiltinType() && SecondType->isVectorType()) || + (FirstType->isVectorType() && SecondType->isSizelessBuiltinType())) && + "Expected SVE builtin type and vector type!"); + + auto IsValidCast = [this](QualType FirstType, QualType SecondType) { + if (const auto *BT = FirstType->getAs()) { + if (const auto *VT = SecondType->getAs()) { + // Predicates have the same representation as uint8 so we also have to + // check the kind to make these types incompatible. + if (VT->getVectorKind() == VectorType::SveFixedLengthPredicateVector) + return BT->getKind() == BuiltinType::SveBool; + else if (VT->getVectorKind() == VectorType::SveFixedLengthDataVector) + return VT->getElementType().getCanonicalType() == + FirstType->getSveEltType(*this); + } + } + return false; + }; + + return IsValidCast(FirstType, SecondType) || + IsValidCast(SecondType, FirstType); +} + bool ASTContext::hasDirectOwnershipQualifier(QualType Ty) const { while (true) { // __strong id diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp --- a/clang/lib/AST/JSONNodeDumper.cpp +++ b/clang/lib/AST/JSONNodeDumper.cpp @@ -616,6 +616,12 @@ case VectorType::NeonPolyVector: JOS.attribute("vectorKind", "neon poly"); break; + case VectorType::SveFixedLengthDataVector: + JOS.attribute("vectorKind", "fixed-length sve data vector"); + break; + case VectorType::SveFixedLengthPredicateVector: + JOS.attribute("vectorKind", "fixed-length sve predicate vector"); + break; } } diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -1408,6 +1408,12 @@ case VectorType::NeonPolyVector: OS << " neon poly"; break; + case VectorType::SveFixedLengthDataVector: + OS << " fixed-length sve data vector"; + break; + case VectorType::SveFixedLengthPredicateVector: + OS << " fixed-length sve predicate vector"; + break; } OS << " " << T->getNumElements(); } diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -2313,11 +2313,42 @@ return false; } -bool Type::isVLST() const { - if (!isVLSTBuiltinType()) - return false; +QualType Type::getSveEltType(const ASTContext &Ctx) const { + assert(isVLSTBuiltinType() && "unsupported type!"); - return hasAttr(attr::ArmSveVectorBits); + const BuiltinType *BTy = getAs(); + switch (BTy->getKind()) { + default: + llvm_unreachable("Unknown builtin SVE type!"); + case BuiltinType::SveInt8: + return Ctx.SignedCharTy; + case BuiltinType::SveUint8: + case BuiltinType::SveBool: + // Represent predicates as i8 rather than i1 to avoid any layout issues. + // The type is bitcasted to a scalable predicate type when casting between + // scalable and fixed-length vectors. + return Ctx.UnsignedCharTy; + case BuiltinType::SveInt16: + return Ctx.ShortTy; + case BuiltinType::SveUint16: + return Ctx.UnsignedShortTy; + case BuiltinType::SveInt32: + return Ctx.IntTy; + case BuiltinType::SveUint32: + return Ctx.UnsignedIntTy; + case BuiltinType::SveInt64: + return Ctx.LongTy; + case BuiltinType::SveUint64: + return Ctx.UnsignedLongTy; + case BuiltinType::SveFloat16: + return Ctx.Float16Ty; + case BuiltinType::SveBFloat16: + return Ctx.BFloat16Ty; + case BuiltinType::SveFloat32: + return Ctx.FloatTy; + case BuiltinType::SveFloat64: + return Ctx.DoubleTy; + } } bool QualType::isPODType(const ASTContext &Context) const { diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -655,6 +655,24 @@ printBefore(T->getElementType(), OS); break; } + case VectorType::SveFixedLengthDataVector: + case VectorType::SveFixedLengthPredicateVector: + // FIXME: We prefer to print the size directly here, but have no way + // to get the size of the type. + OS << "__attribute__((__arm_sve_vector_bits__("; + + if (T->getVectorKind() == VectorType::SveFixedLengthPredicateVector) + // Predicates take a bit per byte of the vector size, multiply by 8 to + // get the number of bits passed to the attribute. + OS << T->getNumElements() * 8; + else + OS << T->getNumElements(); + + OS << " * sizeof("; + print(T->getElementType(), OS, StringRef()); + // Multiply by 8 for the number of bits. + OS << ") * 8))) "; + printBefore(T->getElementType(), OS); } } @@ -702,6 +720,24 @@ printBefore(T->getElementType(), OS); break; } + case VectorType::SveFixedLengthDataVector: + case VectorType::SveFixedLengthPredicateVector: + // FIXME: We prefer to print the size directly here, but have no way + // to get the size of the type. + OS << "__attribute__((__arm_sve_vector_bits__("; + if (T->getSizeExpr()) { + T->getSizeExpr()->printPretty(OS, nullptr, Policy); + if (T->getVectorKind() == VectorType::SveFixedLengthPredicateVector) + // Predicates take a bit per byte of the vector size, multiply by 8 to + // get the number of bits passed to the attribute. + OS << " * 8"; + OS << " * sizeof("; + print(T->getElementType(), OS, StringRef()); + // Multiply by 8 for the number of bits. + OS << ") * 8"; + } + OS << "))) "; + printBefore(T->getElementType(), OS); } } @@ -1634,9 +1670,6 @@ case attr::ArmMveStrictPolymorphism: OS << "__clang_arm_mve_strict_polymorphism"; break; - case attr::ArmSveVectorBits: - OS << "arm_sve_vector_bits"; - break; } OS << "))"; } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -8032,7 +8032,7 @@ return; } - if (!NewVD->hasLocalStorage() && T->isSizelessType() && !T->isVLST()) { + if (!NewVD->hasLocalStorage() && T->isSizelessType()) { Diag(NewVD->getLocation(), diag::err_sizeless_nonlocal) << T; NewVD->setInvalidDecl(); return; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -9009,6 +9009,14 @@ } } + // Allow assignments between fixed-length and sizeless SVE vectors. + if (((LHSType->isSizelessBuiltinType() && RHSType->isVectorType()) || + (LHSType->isVectorType() && RHSType->isSizelessBuiltinType())) && + Context.areCompatibleSveTypes(LHSType, RHSType)) { + Kind = CK_BitCast; + return Compatible; + } + return Incompatible; } @@ -9899,6 +9907,22 @@ // Okay, the expression is invalid. + // Returns true if the operands are SVE VLA and VLS types. + auto IsSveConversion = [](QualType FirstType, QualType SecondType) { + const VectorType *VecType = SecondType->getAs(); + return FirstType->isSizelessBuiltinType() && VecType && + (VecType->getVectorKind() == VectorType::SveFixedLengthDataVector || + VecType->getVectorKind() == + VectorType::SveFixedLengthPredicateVector); + }; + + // If there's a sizeless and fixed-length operand, diagnose that. + if (IsSveConversion(LHSType, RHSType) || IsSveConversion(RHSType, LHSType)) { + Diag(Loc, diag::err_typecheck_vector_not_convertable_sizeless) + << LHSType << RHSType; + return QualType(); + } + // If there's a non-vector, non-real operand, diagnose that. if ((!RHSVecType && !RHSType->isRealType()) || (!LHSVecType && !LHSType->isRealType())) { diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -4323,6 +4323,12 @@ VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; + case ICK_SVE_Vector_Conversion: + From = ImpCastExprToType(From, ToType, CK_BitCast, VK_RValue, + /*BasePath=*/nullptr, CCK) + .get(); + break; + case ICK_Vector_Splat: { // Vector splat from any arithmetic type to a vector. Expr *Elem = prepareVectorSplat(ToType, From).get(); diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -137,6 +137,7 @@ ICR_Conversion, ICR_Conversion, ICR_Conversion, + ICR_Conversion, ICR_OCL_Scalar_Widening, ICR_Complex_Real_Conversion, ICR_Conversion, @@ -174,6 +175,7 @@ "Compatible-types conversion", "Derived-to-base conversion", "Vector conversion", + "SVE Vector conversion", "Vector splat", "Complex-real conversion", "Block Pointer conversion", @@ -1650,6 +1652,12 @@ } } + if ((ToType->isSizelessBuiltinType() || FromType->isSizelessBuiltinType()) && + S.Context.areCompatibleSveTypes(FromType, ToType)) { + ICK = ICK_SVE_Vector_Conversion; + return true; + } + // We can perform the conversion between vector types in the following cases: // 1)vector types are equivalent AltiVec and GCC vector types // 2)lax vector conversions are permitted and the vector types are of the @@ -4104,6 +4112,20 @@ : ImplicitConversionSequence::Worse; } + if (SCS1.Second == ICK_SVE_Vector_Conversion && + SCS2.Second == ICK_SVE_Vector_Conversion) { + bool SCS1IsCompatibleSVEVectorConversion = + S.Context.areCompatibleSveTypes(SCS1.getFromType(), SCS1.getToType(2)); + bool SCS2IsCompatibleSVEVectorConversion = + S.Context.areCompatibleSveTypes(SCS2.getFromType(), SCS2.getToType(2)); + + if (SCS1IsCompatibleSVEVectorConversion != + SCS2IsCompatibleSVEVectorConversion) + return SCS1IsCompatibleSVEVectorConversion + ? ImplicitConversionSequence::Better + : ImplicitConversionSequence::Worse; + } + return ImplicitConversionSequence::Indistinguishable; } @@ -5524,6 +5546,7 @@ case ICK_Compatible_Conversion: case ICK_Derived_To_Base: case ICK_Vector_Conversion: + case ICK_SVE_Vector_Conversion: case ICK_Vector_Splat: case ICK_Complex_Real: case ICK_Block_Pointer_Conversion: diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -2342,7 +2342,7 @@ return QualType(); } - if (T->isSizelessType() && !T->isVLST()) { + if (T->isSizelessType()) { Diag(Loc, diag::err_array_incomplete_or_sizeless_type) << 1 << T; return QualType(); } @@ -7810,14 +7810,10 @@ /// 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(TypeProcessingState &State, - QualType &CurType, - ParsedAttr &Attr) { - Sema &S = State.getSema(); - ASTContext &Ctx = S.Context; - +static void HandleArmSveVectorBitsTypeAttr(QualType &CurType, ParsedAttr &Attr, + Sema &S) { // Target must have SVE. - if (!Ctx.getTargetInfo().hasFeature("sve")) { + if (!S.Context.getTargetInfo().hasFeature("sve")) { S.Diag(Attr.getLoc(), diag::err_attribute_unsupported) << Attr; Attr.setInvalid(); return; @@ -7862,8 +7858,18 @@ return; } - auto *A = ::new (Ctx) ArmSveVectorBitsAttr(Ctx, Attr, VecSize); - CurType = State.getAttributedType(A, CurType, CurType); + const auto *BT = CurType->castAs(); + + QualType EltType = CurType->getSveEltType(S.Context); + unsigned TypeSize = S.Context.getTypeSize(EltType); + VectorType::VectorKind VecKind = VectorType::SveFixedLengthDataVector; + if (BT->getKind() == BuiltinType::SveBool) { + // Predicates are represented as i8. + VecSize /= S.Context.getCharWidth() * S.Context.getCharWidth(); + VecKind = VectorType::SveFixedLengthPredicateVector; + } else + VecSize /= TypeSize; + CurType = S.Context.getVectorType(EltType, VecSize, VecKind); } static void HandleArmMveStrictPolymorphismAttr(TypeProcessingState &State, @@ -8134,7 +8140,7 @@ attr.setUsedAsTypeAttr(); break; case ParsedAttr::AT_ArmSveVectorBits: - HandleArmSveVectorBitsTypeAttr(state, type, attr); + HandleArmSveVectorBitsTypeAttr(type, attr, state.getSema()); attr.setUsedAsTypeAttr(); break; case ParsedAttr::AT_ArmMveStrictPolymorphism: { diff --git a/clang/test/Sema/attr-arm-sve-vector-bits.c b/clang/test/Sema/attr-arm-sve-vector-bits.c --- a/clang/test/Sema/attr-arm-sve-vector-bits.c +++ b/clang/test/Sema/attr-arm-sve-vector-bits.c @@ -102,8 +102,11 @@ 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'))}} + sel = c ? ss8 : fs8; // expected-error {{cannot convert between a fixed-length and a sizeless vector}} + sel = c ? fs8 : ss8; // expected-error {{cannot convert between a fixed-length and a sizeless vector}} + + sel = fs8 + ss8; // expected-error {{cannot convert between a fixed-length and a sizeless vector}} + sel = ss8 + fs8; // expected-error {{cannot convert between a fixed-length and a sizeless vector}} } // --------------------------------------------------------------------------// @@ -192,14 +195,18 @@ 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')}} +fixed_int8_t to_fixed_int8_t__from_svuint8_t(svuint8_t x) { return x; } // expected-error-re {{returning 'svuint8_t' (aka '__SVUint8_t') from a function with incompatible result type 'fixed_int8_t' (vector of {{[0-9]+}} 'signed char' values)}} +fixed_bool_t to_fixed_bool_t__from_svint32_t(svint32_t x) { return x; } // expected-error-re {{returning 'svint32_t' (aka '__SVInt32_t') from a function with incompatible result type 'fixed_bool_t' (vector of {{[0-9]+}} 'unsigned char' values)}} + +// Test conversion between predicate and uint8 is invalid, both have the same +// memory representation. +fixed_bool_t to_fixed_bool_t__from_svuint8_t(svuint8_t x) { return x; } // expected-error-re {{returning 'svuint8_t' (aka '__SVUint8_t') from a function with incompatible result type 'fixed_bool_t' (vector of {{[0-9]+}} 'unsigned char' values)}} // 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')}} +svint32_t to_svint32_t_from_gnut(vSInt32 x) { return x; } // expected-error-re {{returning 'vSInt32' (vector of {{[0-9]+}} '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)}} +vSInt32 to_gnut_from_svint32_t(svint32_t x) { return x; } // expected-error-re {{returning 'svint32_t' (aka '__SVInt32_t') from a function with incompatible result type 'vSInt32' (vector of {{[0-9]+}} 'int' values)}} // --------------------------------------------------------------------------// // Test the scalable and fixed-length types can be used interchangeably diff --git a/clang/test/SemaCXX/attr-arm-sve-vector-bits.cpp b/clang/test/SemaCXX/attr-arm-sve-vector-bits.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/attr-arm-sve-vector-bits.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve -target-feature +bf16 -fsyntax-only -verify -std=c++11 -msve-vector-bits=512 -fallow-half-arguments-and-returns %s +// expected-no-diagnostics + +#define N __ARM_FEATURE_SVE_BITS_EXPERIMENTAL + +typedef __SVInt8_t svint8_t; +typedef svint8_t fixed_int8_t __attribute__((arm_sve_vector_bits(N))); + +template struct S { T var; }; + +S s; + +svint8_t to_svint8_t(fixed_int8_t x) { return x; } +fixed_int8_t from_svint8_t(svint8_t x) { return x; }