diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -433,6 +433,73 @@ return v; } +GCC vector types are created using the ``vector_size(N)`` attribute. The +argument ``N`` specifies the number of bytes that will be allocated for an +object of this type. The size has to be multiple of the size of the vector +element type. For example: + +.. code-block:: c++ + + // OK: This declares a vector type with four 'int' elements + typedef int int4 __attribute__((vector_size(4 * sizeof(int)))); + + // ERROR: '11' is not a multiple of sizeof(int) + typedef int int_impossible __attribute__((vector_size(11))); + + int4 foo(int4 a) { + int4 v; + v = a; + return v; + } + + +Boolean Vectors +--------------- + +Unlike GCC, Clang also allows the attribute to be used with boolean +element types. For example: + +.. code-block:: c++ + + // legal for Clang, error for GCC: + typedef bool bool8 __attribute__((vector_size(1))); + // Objects of bool8 type hold 8 bits, sizeof(bool8) == 1 + + typedef bool bool32 __attribute__((vector_size(4))); + // Objects of bool32 type hold 32 bits, sizeof(bool32) == 4 + + bool8 foo(bool8 a) { + bool8 v; + v = a; + return v; + } + +Boolean vectors are a Clang extension of the GCC vector type. Boolean vectors +are intended, though not guaranteed, to map to vector mask registers. The size +parameter of a boolean vector type is the number of bytes in the vector. The +number of elements in a boolean vector of a given size depends on the target. +For most targets, the boolean vector is dense and each bit in the boolean +vector is one vector element. However, some targets (eg Hexagon hvx64), use +one byte per boolean element. + +The semantics of boolean vectors differs from the GCC vector of integer or +floating point type. This is mostly because bits are smaller than the smallest +addressable unit in memory on most architectures. The semantics of boolean +vectors borrows from C bit-fields with the following differences: + +* Distinct boolean vectors are always distinct memory objects (there is no + packing). +* Only the operators `!`, `~`, `|`, `&`, `^` and comparison are allowed on + boolean vectors. + +The memory representation of a dense boolean vector is the smallest fitting +integer. The alignment is the number of bits rounded up to the next +power-of-two but at most the maximum vector alignment of the target. This +permits the use of boolean vectors whose element count is a power of two in +allocated arrays using the common ``sizeof(Array)/sizeof(ElementType)`` +pattern. + + Vector Literals --------------- @@ -484,6 +551,7 @@ reinterpret_cast yes no yes no static_cast yes no yes no const_cast no no no no +address &v[i] no no no [#]_ no ============================== ======= ======= ============= ======= See also :ref:`langext-__builtin_shufflevector`, :ref:`langext-__builtin_convertvector`. @@ -493,6 +561,9 @@ it's only available in C++ and uses normal bool conversions (that is, != 0). If it's an extension (OpenCL) vector, it's only available in C and OpenCL C. And it selects base on signedness of the condition operands (OpenCL v1.1 s6.3.9). +.. [#] Clang does not allow the address of an element to be taken while GCC + allows this. This is intentional for vectors with a boolean element type and + not implemented otherwise. Matrix Types ============ 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 @@ -3256,6 +3256,11 @@ return VectorKind(VectorTypeBits.VecKind); } + bool isVectorSizeBoolean() const { + return (getVectorKind() == VectorKind::GenericVector) && + getElementType()->isBooleanType(); + } + void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getElementType(), getNumElements(), getTypeClass(), getVectorKind()); diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -77,6 +77,9 @@ unsigned char FractWidth, FractAlign; unsigned char LongFractWidth, LongFractAlign; + // Whether the elements of a boolean vector are bits. + bool DenseBoolVector; + // If true, unsigned fixed point types have the same number of fractional bits // as their signed counterparts, forcing the unsigned types to have one extra // bit of padding. Otherwise, unsigned fixed point types have @@ -413,6 +416,9 @@ /// Return the size of '_Bool' and C++ 'bool' for this target, in bits. unsigned getBoolWidth() const { return BoolWidth; } + /// Return whether the size of an element of a bool vector is just one bit. + bool hasDenseBoolVectors() const { return DenseBoolVector; } + /// Return the alignment of '_Bool' and C++ 'bool' for this target. unsigned getBoolAlign() const { return BoolAlign; } 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 @@ -11348,7 +11348,8 @@ /// type checking for vector binary operators. QualType CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign, - bool AllowBothBool, bool AllowBoolConversion); + bool AllowBothBool, bool AllowBoolConversion, + bool AllowBoolOperation, bool ReportInvalid); QualType GetSignedVectorType(QualType V); QualType CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, 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 @@ -1926,7 +1926,9 @@ case Type::Vector: { const auto *VT = cast(T); TypeInfo EltInfo = getTypeInfo(VT->getElementType()); - Width = EltInfo.Width * VT->getNumElements(); + Width = (Target->hasDenseBoolVectors() && VT->isVectorSizeBoolean()) + ? VT->getNumElements() + : EltInfo.Width * VT->getNumElements(); Align = Width; // If the alignment is not a power of 2, round up to the next power of 2. // This happens for non-power-of-2 length vectors. 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 @@ -645,13 +645,18 @@ printBefore(T->getElementType(), OS); break; case VectorType::GenericVector: { + auto NumVectorElems = T->getNumElements(); // FIXME: We prefer to print the size directly here, but have no way // to get the size of the type. - OS << "__attribute__((__vector_size__(" - << T->getNumElements() - << " * sizeof("; - print(T->getElementType(), OS, StringRef()); - OS << ")))) "; + // FIXME: Only the target knows whether the elements of 'Bool' vectors occpy + // one bit or sizeof(char). + OS << "__attribute__((__vector_size__(" << NumVectorElems; + if (!T->isVectorSizeBoolean()) { + OS << " * sizeof("; + print(T->getElementType(), OS, StringRef()); + OS << ")"; + } + OS << "))) "; printBefore(T->getElementType(), OS); break; } diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp --- a/clang/lib/Basic/TargetInfo.cpp +++ b/clang/lib/Basic/TargetInfo.cpp @@ -52,6 +52,10 @@ FractWidth = FractAlign = 16; LongFractWidth = LongFractAlign = 32; + // By default, each element of a boolean vector occpies one bit. Target that + // represent boolean elements as bytes may want to disable this. + DenseBoolVector = true; + // Fixed point default integral and fractional bit sizes // We give the _Accum 1 fewer fractional bits than their corresponding _Fract // types by default to have the same number of fractional bits between _Accum diff --git a/clang/lib/Basic/Targets/Hexagon.h b/clang/lib/Basic/Targets/Hexagon.h --- a/clang/lib/Basic/Targets/Hexagon.h +++ b/clang/lib/Basic/Targets/Hexagon.h @@ -64,6 +64,9 @@ // for modeling predicate registers in HVX, and the bool -> byte // correspondence matches the HVX architecture. BoolWidth = BoolAlign = 8; + // Make sure that the bool elements of bool vectors have the same size as + // the plain boolean type. + DenseBoolVector = false; } ArrayRef getTargetBuiltins() const override; diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -2768,6 +2768,23 @@ llvm::DIType *CGDebugInfo::CreateType(const VectorType *Ty, llvm::DIFile *Unit) { + if (CGM.getTarget().hasDenseBoolVectors() && Ty->isVectorSizeBoolean()) { + // vector_size(N) are special because their real element type (bits of bit + // size) is not their Clang element type (_Bool of size byte). For now, we + // pretend the boolean vector were actually a vector of bytes (where each + // byte represents 8 bits of the actual vector). + // FIXME Debug info should actually represent this proper as a vector mask + // type. + auto &Ctx = CGM.getContext(); + uint64_t Size = CGM.getContext().getTypeSize(Ty); + uint64_t NumVectorBytes = Size / Ctx.getCharWidth(); + + // construct the vector of 'unsigned char' type + QualType CharVecTy = Ctx.getVectorType(Ctx.CharTy, NumVectorBytes, + VectorType::GenericVector); + return CreateType(CharVecTy->getAs(), Unit); + } + llvm::DIType *ElementTy = getOrCreateType(Ty->getElementType(), Unit); int64_t Count = Ty->getNumElements(); diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1687,27 +1687,44 @@ LValueBaseInfo BaseInfo, TBAAAccessInfo TBAAInfo, bool isNontemporal) { - if (!CGM.getCodeGenOpts().PreserveVec3Type) { - // For better performance, handle vector loads differently. - if (Ty->isVectorType()) { - const llvm::Type *EltTy = Addr.getElementType(); - - const auto *VTy = cast(EltTy); - - // Handle vectors of size 3 like size 4 for better performance. - if (VTy->getNumElements() == 3) { - - // Bitcast to vec4 type. - auto *vec4Ty = llvm::FixedVectorType::get(VTy->getElementType(), 4); - Address Cast = Builder.CreateElementBitCast(Addr, vec4Ty, "castToVec4"); - // Now load value. - llvm::Value *V = Builder.CreateLoad(Cast, Volatile, "loadVec4"); - - // Shuffle vector to get vec3. - V = Builder.CreateShuffleVector(V, llvm::UndefValue::get(vec4Ty), - ArrayRef{0, 1, 2}, "extractVec"); - return EmitFromMemory(V, Ty); - } + const auto *ClangVecTy = Ty->getAs(); + if (ClangVecTy) { + // Boolean vectors use `iN` as storage type + if (Target.hasDenseBoolVectors() && ClangVecTy->isVectorSizeBoolean()) { + llvm::Type *ValTy = ConvertType(Ty); + unsigned ValNumElems = + cast(ValTy)->getNumElements(); + // Load the `iP` storage object (P is the padded vector size). + auto *RawIntV = Builder.CreateLoad(Addr, Volatile, "load_bits"); + const auto *RawIntTy = RawIntV->getType(); + assert(RawIntTy->isIntegerTy() && "compressed iN storage for bitvectors"); + // Bitcast iP -->

+ auto *PaddedVecTy = llvm::FixedVectorType::get( + Builder.getInt1Ty(), RawIntTy->getPrimitiveSizeInBits()); + llvm::Value *V = Builder.CreateBitCast(RawIntV, PaddedVecTy); + // Shuffle

--> (N is the actual bit size) + V = emitBoolVecConversion(V, ValNumElems, "extractvec"); + + return EmitFromMemory(V, Ty); + } + + // Handle vectors of size 3 like size 4 for better performance. + const llvm::Type *EltTy = Addr.getElementType(); + const auto *VTy = cast(EltTy); + + if (!CGM.getCodeGenOpts().PreserveVec3Type && VTy->getNumElements() == 3) { + + // Bitcast to vec4 type. + llvm::VectorType *vec4Ty = + llvm::FixedVectorType::get(VTy->getElementType(), 4); + Address Cast = Builder.CreateElementBitCast(Addr, vec4Ty, "castToVec4"); + // Now load value. + llvm::Value *V = Builder.CreateLoad(Cast, Volatile, "loadVec4"); + + // Shuffle vector to get vec3. + V = Builder.CreateShuffleVector(V, llvm::UndefValue::get(vec4Ty), + ArrayRef{0, 1, 2}, "extractVec"); + return EmitFromMemory(V, Ty); } } @@ -1751,6 +1768,13 @@ return Value; } +static bool isBooleanVector(QualType Ty) { + const auto *VecTy = Ty->getAs(); + if (!VecTy) + return false; + return VecTy->isVectorSizeBoolean(); +} + llvm::Value *CodeGenFunction::EmitFromMemory(llvm::Value *Value, QualType Ty) { // Bool has a different representation in memory than in registers. if (hasBooleanRepresentation(Ty)) { @@ -1758,6 +1782,17 @@ "wrong value rep of bool"); return Builder.CreateTrunc(Value, Builder.getInt1Ty(), "tobool"); } + if (Target.hasDenseBoolVectors() && isBooleanVector(Ty)) { + const auto *RawIntTy = Value->getType(); + // Bitcast iP -->

+ auto *PaddedVecTy = llvm::FixedVectorType::get( + Builder.getInt1Ty(), RawIntTy->getPrimitiveSizeInBits()); + auto *V = Builder.CreateBitCast(Value, PaddedVecTy); + // Shuffle

--> (N is the actual bit size) + llvm::Type *ValTy = ConvertType(Ty); + unsigned ValNumElems = cast(ValTy)->getNumElements(); + return emitBoolVecConversion(V, ValNumElems, "extractvec"); + } return Value; } @@ -1804,11 +1839,20 @@ LValueBaseInfo BaseInfo, TBAAAccessInfo TBAAInfo, bool isInit, bool isNontemporal) { - if (!CGM.getCodeGenOpts().PreserveVec3Type) { - // Handle vectors differently to get better performance. - if (Ty->isVectorType()) { - llvm::Type *SrcTy = Value->getType(); - auto *VecTy = dyn_cast(SrcTy); + llvm::Type *SrcTy = Value->getType(); + const auto *ClangVecTy = Ty->getAs(); + if (ClangVecTy) { + auto *VecTy = dyn_cast(SrcTy); + if (Target.hasDenseBoolVectors() && ClangVecTy->isVectorSizeBoolean()) { + auto *MemIntTy = + cast(Addr.getType()->getPointerElementType()); + // Expand to the memory bit width + unsigned MemNumElems = MemIntTy->getPrimitiveSizeInBits(); + // -->

+ Value = emitBoolVecConversion(Value, MemNumElems, "insertvec"); + //

--> iP + Value = Builder.CreateBitCast(Value, MemIntTy); + } else if (!CGM.getCodeGenOpts().PreserveVec3Type) { // Handle vec3 special. if (VecTy && cast(VecTy)->getNumElements() == 3) { // Our source is a vec3, do a shuffle vector to make it a vec4. @@ -2037,8 +2081,19 @@ // Read/modify/write the vector, inserting the new element. llvm::Value *Vec = Builder.CreateLoad(Dst.getVectorAddress(), Dst.isVolatileQualified()); + auto *IRStoreTy = dyn_cast(Vec->getType()); + if (IRStoreTy) { + auto *IRVecTy = llvm::FixedVectorType::get( + Builder.getInt1Ty(), IRStoreTy->getPrimitiveSizeInBits()); + Vec = Builder.CreateBitCast(Vec, IRVecTy); + // iN --> + } Vec = Builder.CreateInsertElement(Vec, Src.getScalarVal(), Dst.getVectorIdx(), "vecins"); + if (IRStoreTy) { + // --> + Vec = Builder.CreateBitCast(Vec, IRStoreTy); + } Builder.CreateStore(Vec, Dst.getVectorAddress(), Dst.isVolatileQualified()); return; diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -1958,7 +1958,7 @@ case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: case CK_BitCast: { - Value *Src = Visit(const_cast(E)); + Value *Src = Visit(const_cast(E)); llvm::Type *SrcTy = Src->getType(); llvm::Type *DstTy = ConvertType(DestTy); if (SrcTy->isPtrOrPtrVectorTy() && DstTy->isPtrOrPtrVectorTy() && @@ -2031,7 +2031,34 @@ return EmitLoadOfLValue(DestLV, CE->getExprLoc()); } - return Builder.CreateBitCast(Src, DstTy); + // SExt/Trunc Boolean vectors to fit the expected type + auto *VecSrcTy = dyn_cast(Src->getType()); + auto *VecDstTy = dyn_cast(DstTy); + bool VectorElementCast = + VecSrcTy && VecDstTy && + (VecSrcTy->getElementCount() == VecDstTy->getElementCount()); + bool IsDenseBoolVectorTarget = + CGF.getContext().getTargetInfo().hasDenseBoolVectors(); + if (IsDenseBoolVectorTarget && VecSrcTy && + VecSrcTy->getElementType()->isIntegerTy(1)) { + // When casting with the same element count extend this to the native + // result size Otw, signextend to 'i8' as an intermediary + unsigned DstElemBits = + VectorElementCast ? DstTy->getScalarSizeInBits() : 8; + + auto *PlainIntTy = llvm::VectorType::get(Builder.getIntNTy(DstElemBits), + VecSrcTy->getElementCount()); + Src = Builder.CreateSExt(Src, PlainIntTy); + } + Src = Builder.CreateBitCast(Src, DstTy); + if (IsDenseBoolVectorTarget && VectorElementCast && + VecDstTy->getElementType()->isIntegerTy(1)) { + auto *PlainIntTy = + llvm::VectorType::get(Builder.getIntNTy(SrcTy->getScalarSizeInBits()), + VecSrcTy->getElementCount()); + Src = Builder.CreateTrunc(Src, PlainIntTy); + } + return Src; } case CK_AddressSpaceConversion: { Expr::EvalResult Result; @@ -4571,6 +4598,14 @@ return Builder.CreateIntToPtr(Src, DstTy, Name); } +static bool IsGenericBoolVector(QualType Ty) { + const auto *ClangVecTy = dyn_cast(Ty); + if (!ClangVecTy) + return false; + + return ClangVecTy->isVectorSizeBoolean(); +} + Value *ScalarExprEmitter::VisitAsTypeExpr(AsTypeExpr *E) { Value *Src = CGF.EmitScalarExpr(E->getSrcExpr()); llvm::Type *DstTy = ConvertType(E->getType()); @@ -4585,6 +4620,12 @@ ? cast(DstTy)->getNumElements() : 0; + // Use bit vector expansion for generic boolean vectors + if (CGF.getTarget().hasDenseBoolVectors() && + IsGenericBoolVector(E->getType())) { + return CGF.emitBoolVecConversion(Src, NumElementsDst, "astype"); + } + // Going from vec3 to non-vec3 is a special case and requires a shuffle // vector to get a vec4, then a bitcast if the target type is different. if (NumElementsSrc == 3 && NumElementsDst != 3) { diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4465,6 +4465,11 @@ /// Set the codegen fast-math flags. void SetFastMathFlags(FPOptions FPFeatures); + // Truncate or extend a boolean vector to the requested number of elements. + llvm::Value *emitBoolVecConversion(llvm::Value *SrcVec, + unsigned NumElementsDst, + const llvm::Twine &Name = ""); + private: llvm::MDNode *getRangeForLoadFromType(QualType Ty); void EmitReturnOfRValue(RValue RV, QualType Ty); diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -2569,3 +2569,22 @@ return llvm::DebugLoc(); } + +llvm::Value *CodeGenFunction::emitBoolVecConversion(llvm::Value *SrcVec, + unsigned NumElementsDst, + const llvm::Twine &Name) { + auto *SrcTy = cast(SrcVec->getType()); + unsigned NumElementsSrc = SrcTy->getNumElements(); + if (NumElementsSrc == NumElementsDst) { + return SrcVec; + } + + std::vector ShuffleMask(NumElementsDst, -1); + for (unsigned MaskIdx = 0; + MaskIdx < std::min<>(NumElementsDst, NumElementsSrc); ++MaskIdx) { + ShuffleMask[MaskIdx] = MaskIdx; + } + + return Builder.CreateShuffleVector(SrcVec, llvm::UndefValue::get(SrcTy), + ShuffleMask, Name); +} diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp --- a/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/clang/lib/CodeGen/CodeGenTypes.cpp @@ -91,6 +91,17 @@ llvm::Type *R = ConvertType(T); + // Check for the boolean vector case + bool DenseBoolVector = CGM.getTarget().hasDenseBoolVectors(); + auto *FixedVT = dyn_cast(R); + if (DenseBoolVector && T->isVectorType() && FixedVT && + FixedVT->getElementType()->isIntegerTy(1)) { + + // Pad to at least one byte. + uint64_t BytePadded = std::max(FixedVT->getNumElements(), 8); + return llvm::IntegerType::get(FixedVT->getContext(), BytePadded); + } + // If this is a bool type, or an ExtIntType in a bitfield representation, // map this integer to the target-specified size. if ((ForBitField && T->isExtIntType()) || @@ -670,8 +681,10 @@ case Type::ExtVector: case Type::Vector: { const VectorType *VT = cast(Ty); - ResultType = llvm::FixedVectorType::get(ConvertType(VT->getElementType()), - VT->getNumElements()); + llvm::Type *IRElemTy = VT->getElementType()->isBooleanType() + ? llvm::Type::getInt1Ty(getLLVMContext()) + : ConvertType(VT->getElementType()); + ResultType = llvm::FixedVectorType::get(IRElemTy, VT->getNumElements()); break; } case Type::ConstantMatrix: { 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 @@ -7199,11 +7199,13 @@ llvm_unreachable("Unhandled scalar cast"); } -static bool breakDownVectorType(QualType type, uint64_t &len, - QualType &eltType) { +static bool breakDownVectorType(QualType type, uint64_t &len, QualType &eltType, + bool &IsVectorSizeBool) { // Vectors are simple. + IsVectorSizeBool = false; if (const VectorType *vecType = type->getAs()) { len = vecType->getNumElements(); + IsVectorSizeBool = vecType->isVectorSizeBoolean(); eltType = vecType->getElementType(); assert(eltType->isScalarType()); return true; @@ -7238,14 +7240,21 @@ uint64_t srcLen, destLen; QualType srcEltTy, destEltTy; - if (!breakDownVectorType(srcTy, srcLen, srcEltTy)) return false; - if (!breakDownVectorType(destTy, destLen, destEltTy)) return false; + bool srcBoolVector, destBoolVector; + if (!breakDownVectorType(srcTy, srcLen, srcEltTy, srcBoolVector)) + return false; + if (!breakDownVectorType(destTy, destLen, destEltTy, destBoolVector)) + return false; + + bool HasBitVectors = Context.getTargetInfo().hasDenseBoolVectors(); // ASTContext::getTypeSize will return the size rounded up to a // power of 2, so instead of using that, we need to use the raw // element size multiplied by the element count. - uint64_t srcEltSize = Context.getTypeSize(srcEltTy); - uint64_t destEltSize = Context.getTypeSize(destEltTy); + uint64_t srcEltSize = + (HasBitVectors & srcBoolVector) ? 1 : Context.getTypeSize(srcEltTy); + uint64_t destEltSize = + (HasBitVectors & destBoolVector) ? 1 : Context.getTypeSize(destEltTy); return (srcLen * srcEltSize == destLen * destEltSize); } @@ -8016,9 +8025,11 @@ if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) { QualType VecResTy = S.CheckVectorOperands(LHS, RHS, QuestionLoc, - /*isCompAssign*/false, - /*AllowBothBool*/true, - /*AllowBoolConversions*/false); + /*isCompAssign*/ false, + /*AllowBothBool*/ true, + /*AllowBoolConversions*/ false, + /*AllowBooleanOperation*/ false, + /*ReportInvalid*/ true); if (VecResTy.isNull()) return QualType(); // The result type must match the condition type as specified in // OpenCL v1.1 s6.11.6. @@ -8082,9 +8093,11 @@ // Now check the two expressions. if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) - return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/false, - /*AllowBothBool*/true, - /*AllowBoolConversions*/false); + return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/ false, + /*AllowBothBool*/ true, + /*AllowBoolConversions*/ false, + /*AllowBooleanOperation*/ false, + /*ReportInvalid*/ true); QualType ResTy = UsualArithmeticConversions(LHS, RHS, QuestionLoc, ACK_Conditional); @@ -9783,10 +9796,17 @@ return false; } +static bool IsScalarOrVectorSizeBool(QualType Ty) { + return Ty->isBooleanType() || + (Ty->isVectorType() && Ty->getAs()->isVectorSizeBoolean()); +} + QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign, bool AllowBothBool, - bool AllowBoolConversions) { + bool AllowBoolConversions, + bool AllowBoolOperation, + bool ReportInvalid) { if (!IsCompAssign) { LHS = DefaultFunctionArrayLvalueConversion(LHS.get()); if (LHS.isInvalid()) @@ -9807,14 +9827,19 @@ if ((LHSVecType && LHSVecType->getElementType()->isBFloat16Type()) || (RHSVecType && RHSVecType->getElementType()->isBFloat16Type())) - return InvalidOperands(Loc, LHS, RHS); + return ReportInvalid ? InvalidOperands(Loc, LHS, RHS) : QualType(); // AltiVec-style "vector bool op vector bool" combinations are allowed // for some operators but not others. if (!AllowBothBool && LHSVecType && LHSVecType->getVectorKind() == VectorType::AltiVecBool && RHSVecType && RHSVecType->getVectorKind() == VectorType::AltiVecBool) - return InvalidOperands(Loc, LHS, RHS); + return ReportInvalid ? InvalidOperands(Loc, LHS, RHS) : QualType(); + + // This operation may not be performed on boolean vectors. + if (!AllowBoolOperation && IsScalarOrVectorSizeBool(LHSType) && + IsScalarOrVectorSizeBool(RHSType)) + return ReportInvalid ? InvalidOperands(Loc, LHS, RHS) : QualType(); // If the vector types are identical, return. if (Context.hasSameType(LHSType, RHSType)) @@ -10079,8 +10104,10 @@ if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign, - /*AllowBothBool*/getLangOpts().AltiVec, - /*AllowBoolConversions*/false); + /*AllowBothBool*/ getLangOpts().AltiVec, + /*AllowBoolConversions*/ false, + /*AllowBooleanOperation*/ false, + /*ReportInvalid*/ true); if (!IsDiv && (LHS.get()->getType()->isConstantMatrixType() || RHS.get()->getType()->isConstantMatrixType())) return CheckMatrixMultiplyOperands(LHS, RHS, Loc, IsCompAssign); @@ -10109,8 +10136,10 @@ if (LHS.get()->getType()->hasIntegerRepresentation() && RHS.get()->getType()->hasIntegerRepresentation()) return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign, - /*AllowBothBool*/getLangOpts().AltiVec, - /*AllowBoolConversions*/false); + /*AllowBothBool*/ getLangOpts().AltiVec, + /*AllowBoolConversions*/ false, + /*AllowBooleanOperation*/ false, + /*ReportInvalid*/ true); return InvalidOperands(Loc, LHS, RHS); } @@ -10395,10 +10424,12 @@ if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) { - QualType compType = CheckVectorOperands( - LHS, RHS, Loc, CompLHSTy, - /*AllowBothBool*/getLangOpts().AltiVec, - /*AllowBoolConversions*/getLangOpts().ZVector); + QualType compType = + CheckVectorOperands(LHS, RHS, Loc, CompLHSTy, + /*AllowBothBool*/ getLangOpts().AltiVec, + /*AllowBoolConversions*/ getLangOpts().ZVector, + /*AllowBooleanOperation*/ false, + /*ReportInvalid*/ true); if (CompLHSTy) *CompLHSTy = compType; return compType; } @@ -10495,10 +10526,12 @@ if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) { - QualType compType = CheckVectorOperands( - LHS, RHS, Loc, CompLHSTy, - /*AllowBothBool*/getLangOpts().AltiVec, - /*AllowBoolConversions*/getLangOpts().ZVector); + QualType compType = + CheckVectorOperands(LHS, RHS, Loc, CompLHSTy, + /*AllowBothBool*/ getLangOpts().AltiVec, + /*AllowBoolConversions*/ getLangOpts().ZVector, + /*AllowBooleanOperation*/ false, + /*ReportInvalid*/ true); if (CompLHSTy) *CompLHSTy = compType; return compType; } @@ -10736,6 +10769,15 @@ const VectorType *RHSVecTy = RHSType->getAs(); QualType RHSEleType = RHSVecTy ? RHSVecTy->getElementType() : RHSType; + // Do not allow shifts for vector_size boolean vectors. + if ((LHSVecTy && LHSVecTy->isVectorSizeBoolean()) || + (RHSVecTy && RHSVecTy->isVectorSizeBoolean())) { + S.Diag(Loc, diag::err_typecheck_invalid_operands) + << LHS.get()->getType() << RHS.get()->getType() + << LHS.get()->getSourceRange(); + return QualType(); + } + // The operands need to be integers. if (!LHSEleType->isIntegerType()) { S.Diag(Loc, diag::err_typecheck_expect_int) @@ -11923,7 +11965,10 @@ return Context.getExtVectorType(Context.LongLongTy, VTy->getNumElements()); } - if (TypeSize == Context.getTypeSize(Context.LongLongTy)) + if (VTy->isVectorSizeBoolean()) + return Context.getVectorType(Context.BoolTy, VTy->getNumElements(), + VectorType::GenericVector); + else if (TypeSize == Context.getTypeSize(Context.LongLongTy)) return Context.getVectorType(Context.LongLongTy, VTy->getNumElements(), VectorType::GenericVector); else if (TypeSize == Context.getTypeSize(Context.LongTy)) @@ -11955,9 +12000,12 @@ // Check to make sure we're operating on vectors of the same type and width, // Allowing one side to be a scalar of element type. - QualType vType = CheckVectorOperands(LHS, RHS, Loc, /*isCompAssign*/false, - /*AllowBothBool*/true, - /*AllowBoolConversions*/getLangOpts().ZVector); + QualType vType = + CheckVectorOperands(LHS, RHS, Loc, /*isCompAssign*/ false, + /*AllowBothBool*/ true, + /*AllowBoolConversions*/ getLangOpts().ZVector, + /*AllowBooleanOperation*/ true, + /*ReportInvalid*/ true); if (vType.isNull()) return vType; @@ -12104,8 +12152,10 @@ // Ensure that either both operands are of the same vector type, or // one operand is of a vector type and the other is of its element type. QualType vType = CheckVectorOperands(LHS, RHS, Loc, false, - /*AllowBothBool*/true, - /*AllowBoolConversions*/false); + /*AllowBothBool*/ true, + /*AllowBoolConversions*/ false, + /*AllowBooleanOperation*/ false, + /*ReportInvalid*/ false); if (vType.isNull()) return InvalidOperands(Loc, LHS, RHS); if (getLangOpts().OpenCL && getLangOpts().OpenCLVersion < 120 && @@ -12198,6 +12248,20 @@ return CheckMatrixElementwiseOperands(LHS, RHS, Loc, IsCompAssign); } +static bool isLegalBoolVectorBinaryOp(BinaryOperatorKind Opc) { + switch (Opc) { + default: + return false; + case BO_And: + case BO_AndAssign: + case BO_Or: + case BO_OrAssign: + case BO_Xor: + case BO_XorAssign: + return true; + } +} + inline QualType Sema::CheckBitwiseOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc) { @@ -12206,13 +12270,17 @@ bool IsCompAssign = Opc == BO_AndAssign || Opc == BO_OrAssign || Opc == BO_XorAssign; + bool LegalBoolVecOperator = isLegalBoolVectorBinaryOp(Opc); + if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) { if (LHS.get()->getType()->hasIntegerRepresentation() && RHS.get()->getType()->hasIntegerRepresentation()) return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign, - /*AllowBothBool*/true, - /*AllowBoolConversions*/getLangOpts().ZVector); + /*AllowBothBool*/ true, + /*AllowBoolConversions*/ getLangOpts().ZVector, + /*AllowBooleanOperation*/ LegalBoolVecOperator, + /*ReportInvalid*/ true); return InvalidOperands(Loc, LHS, RHS); } 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 @@ -5916,9 +5916,8 @@ const QualType EltTy = cast(CondTy.getCanonicalType())->getElementType(); - assert(!EltTy->isBooleanType() && !EltTy->isEnumeralType() && - "Vectors cant be boolean or enum types"); - return EltTy->isIntegralType(Ctx); + assert(!EltTy->isEnumeralType() && "Vectors cant be enum types"); + return EltTy->isIntegralType(Ctx) || EltTy->isBooleanType(); } QualType Sema::CheckGNUVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS, @@ -5963,7 +5962,9 @@ } else if (LHSVT || RHSVT) { ResultType = CheckVectorOperands( LHS, RHS, QuestionLoc, /*isCompAssign*/ false, /*AllowBothBool*/ true, - /*AllowBoolConversions*/ false); + /*AllowBoolConversions*/ false, + /*AllowBoolOperation*/ true, + /*ReportInvalid*/ true); if (ResultType.isNull()) return {}; } else { @@ -6281,9 +6282,11 @@ // Extension: conditional operator involving vector types. if (LTy->isVectorType() || RTy->isVectorType()) - return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/false, - /*AllowBothBool*/true, - /*AllowBoolConversions*/false); + return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/ false, + /*AllowBothBool*/ true, + /*AllowBoolConversions*/ false, + /*AllowBoolOperation*/ false, + /*ReportInvalid*/ true); // -- The second and third operands have arithmetic or enumeration type; // the usual arithmetic conversions are performed to bring them to a 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 @@ -2515,11 +2515,11 @@ QualType Sema::BuildVectorType(QualType CurType, Expr *SizeExpr, SourceLocation AttrLoc) { - // The base type must be integer (not Boolean or enumeration) or float, and + // The base type must be boolean or integer (not enumeration) or float, and // can't already be a vector. - if ((!CurType->isDependentType() && - (!CurType->isBuiltinType() || CurType->isBooleanType() || - (!CurType->isIntegerType() && !CurType->isRealFloatingType()))) || + if (!CurType->isDependentType() && + (!CurType->isBuiltinType() || + (!CurType->isIntegerType() && !CurType->isRealFloatingType())) || CurType->isArrayType()) { Diag(AttrLoc, diag::err_attribute_invalid_vector_type) << CurType; return QualType(); @@ -2569,7 +2569,8 @@ return QualType(); } - return Context.getVectorType(CurType, VectorSizeBits / TypeSize, + uint64_t ElemSizeBits = CurType->isBooleanType() ? 1 : TypeSize; + return Context.getVectorType(CurType, VectorSizeBits / ElemSizeBits, VectorType::GenericVector); } @@ -7616,13 +7617,13 @@ T = Context.getAdjustedType(T, Wrapped); } -/// HandleVectorSizeAttribute - this attribute is only applicable to integral -/// and float scalars, although arrays, pointers, and function return values are -/// allowed in conjunction with this construct. Aggregates with this attribute -/// are invalid, even if they are of the same size as a corresponding scalar. -/// The raw attribute should contain precisely 1 argument, the vector size for -/// the variable, measured in bytes. If curType and rawAttr are well formed, -/// this routine will return a new vector type. +/// HandleVectorSizeAttribute - this attribute is only applicable to boolean, +/// integral and float scalars, although arrays, pointers, and function return +/// values are allowed in conjunction with this construct. Aggregates with this +/// attribute are invalid, even if they are of the same size as a corresponding +/// scalar. The raw attribute should contain precisely 1 argument, the vector +/// size for the variable, measured in bytes. If curType and rawAttr are well +/// formed, this routine will return a new vector type. static void HandleVectorSizeAttr(QualType &CurType, const ParsedAttr &Attr, Sema &S) { // Check the attribute arguments. diff --git a/clang/test/AST/ast-print-vector-size-bool.c b/clang/test/AST/ast-print-vector-size-bool.c new file mode 100644 --- /dev/null +++ b/clang/test/AST/ast-print-vector-size-bool.c @@ -0,0 +1,4 @@ +// RUN: %clang_cc1 -ast-print %s -o - | FileCheck %s + +// CHECK: typedef __attribute__((__vector_size__(256))) _Bool bool32; +typedef _Bool bool32 __attribute__((vector_size(32))); diff --git a/clang/test/CodeGen/debug-info-vector-bool-hvx64.c b/clang/test/CodeGen/debug-info-vector-bool-hvx64.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/debug-info-vector-bool-hvx64.c @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -triple hexagon-unknown-elf -target-cpu hexagonv65 -target-feature +hvxv65 -target-feature +hvx-length64b -emit-llvm -debug-info-kind=limited %s -o - | FileCheck %s +typedef _Bool bool4 __attribute__((__vector_size__(4))); + +bool4 b; + +// Test that we get byte-sized bool elements on Hexagon +// CHECK: !DICompositeType(tag: DW_TAG_array_type, +// CHECK-SAME: baseType: ![[BOOL:[0-9]+]] +// CHECK-SAME: size: 256 +// CHECK-SAME: DIFlagVector +// CHECK: ![[BOOL]] = !DIBasicType(name: "_Bool" diff --git a/clang/test/CodeGen/debug-info-vector-bool.c b/clang/test/CodeGen/debug-info-vector-bool.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/debug-info-vector-bool.c @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -triple x86_64-linux-pc -emit-llvm -debug-info-kind=limited %s -o - | FileCheck %s +typedef _Bool bool512 __attribute__((__vector_size__(64))); + +bool512 b; + +// Test that we get bit-sized bool elements on x86 +// CHECK: !DICompositeType(tag: DW_TAG_array_type, +// CHECK-SAME: baseType: ![[BOOL:[0-9]+]] +// CHECK-SAME: size: 512 +// CHECK-SAME: DIFlagVector +// CHECK: ![[BOOL]] = !DIBasicType(name: "char" diff --git a/clang/test/CodeGen/vector-alignment.c b/clang/test/CodeGen/vector-alignment.c --- a/clang/test/CodeGen/vector-alignment.c +++ b/clang/test/CodeGen/vector-alignment.c @@ -22,6 +22,8 @@ // SSE: @v2 {{.*}}, align 16 // AVX: @v2 {{.*}}, align 32 // AVX512: @v2 {{.*}}, align 32 +_Bool __attribute__((vector_size(2))) v2b; +// ALL: @v2b {{.*}}, align 2 // Alignment above target max alignment with no aligned attribute should align // based on the target max. @@ -33,6 +35,10 @@ // SSE: @v4 {{.*}}, align 16 // AVX: @v4 {{.*}}, align 32 // AVX512: @v4 {{.*}}, align 64 +_Bool __attribute__((vector_size(1024))) v4b; +// SSE: @v4b {{.*}}, align 16 +// AVX: @v4b {{.*}}, align 32 +// AVX512: @v4b {{.*}}, align 64 // Aliged attribute should always override. double __attribute__((vector_size(16), aligned(16))) v5; @@ -43,6 +49,8 @@ // ALL: @v7 {{.*}}, align 16 double __attribute__((vector_size(32), aligned(64))) v8; // ALL: @v8 {{.*}}, align 64 +_Bool __attribute__((vector_size(32), aligned(128))) v8b; +// ALL: @v8b {{.*}}, align 128 // Check non-power of 2 widths. double __attribute__((vector_size(24))) v9; @@ -53,9 +61,15 @@ // SSE: @v10 {{.*}}, align 16 // AVX: @v10 {{.*}}, align 32 // AVX512: @v10 {{.*}}, align 64 +_Bool __attribute__((vector_size(31))) v10b; +// SSE: @v10b {{.*}}, align 16 +// AVX: @v10b {{.*}}, align 32 +// AVX512: @v10b {{.*}}, align 32 // Check non-power of 2 widths with aligned attribute. double __attribute__((vector_size(24), aligned(64))) v11; // ALL: @v11 {{.*}}, align 64 double __attribute__((vector_size(80), aligned(16))) v12; // ALL: @v12 {{.*}}, align 16 +_Bool __attribute__((vector_size(31), aligned(4))) v12b; +// ALL: @v12b {{.*}}, align 4 diff --git a/clang/test/SemaCXX/constexpr-vectors.cpp b/clang/test/SemaCXX/constexpr-vectors.cpp --- a/clang/test/SemaCXX/constexpr-vectors.cpp +++ b/clang/test/SemaCXX/constexpr-vectors.cpp @@ -614,3 +614,19 @@ constexpr auto Y = CmpSub(a, b); // CHECK: store <4 x float> } + +using EightBoolsVecSize __attribute__((vector_size(1))) = bool; +void BoolVecUsage() { + constexpr auto a = EightBoolsVecSize{true, false, true, false} < + EightBoolsVecSize{false, false, true, true}; + constexpr auto b = EightBoolsVecSize{true, false, true, false} <= + EightBoolsVecSize{false, false, true, true}; + constexpr auto c = EightBoolsVecSize{true, false, true, false} == + EightBoolsVecSize{false, false, true, true}; + constexpr auto d = EightBoolsVecSize{true, false, true, false} != + EightBoolsVecSize{false, false, true, true}; + constexpr auto e = EightBoolsVecSize{true, false, true, false} >= + EightBoolsVecSize{false, false, true, true}; + constexpr auto f = EightBoolsVecSize{true, false, true, false} > + EightBoolsVecSize{false, false, true, true}; +} diff --git a/clang/test/SemaCXX/vector-bool.cpp b/clang/test/SemaCXX/vector-bool.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/vector-bool.cpp @@ -0,0 +1,81 @@ +// RUN: %clang_cc1 -triple x86_64-linux-pc -fsyntax-only -verify -fexceptions -fcxx-exceptions %s -std=c++17 +// Note that this test depends on the size of long-long to be different from +// int, so it specifies a triple. + +using FourShorts = short __attribute__((__vector_size__(8))); +using TwoInts = int __attribute__((__vector_size__(8))); +using EightInts = int __attribute__((__vector_size__(32))); +using TwoUInts = unsigned __attribute__((__vector_size__(8))); +using FourInts = int __attribute__((__vector_size__(16))); +using FourUInts = unsigned __attribute__((__vector_size__(16))); +using TwoLongLong = long long __attribute__((__vector_size__(16))); +using FourLongLong = long long __attribute__((__vector_size__(32))); +using TwoFloats = float __attribute__((__vector_size__(8))); +using FourFloats = float __attribute__((__vector_size__(16))); +using TwoDoubles = double __attribute__((__vector_size__(16))); +using FourDoubles = double __attribute__((__vector_size__(32))); +using EightBools = bool __attribute__((__vector_size__(1))); + +EightInts eight_ints; +EightBools eight_bools; +EightBools other_eight_bools; +bool one_bool; + +// Check the rules of the LHS/RHS of the conditional operator. +void Operations() { + // Legal binary + (void)(eight_bools | other_eight_bools); + (void)(eight_bools & other_eight_bools); + (void)(eight_bools ^ other_eight_bools); + (void)(~eight_bools); + (void)(!eight_bools); + + // Legal comparison + (void)(eight_bools == other_eight_bools); + (void)(eight_bools != other_eight_bools); + (void)(eight_bools < other_eight_bools); + (void)(eight_bools <= other_eight_bools); + (void)(eight_bools > other_eight_bools); + (void)(eight_bools >= other_eight_bools); + + // Legal assignments + (void)(eight_bools |= other_eight_bools); + (void)(eight_bools &= other_eight_bools); + (void)(eight_bools ^= other_eight_bools); + + // Illegal operators + (void)(eight_bools || other_eight_bools); // expected-error@47 {{invalid operands to binary expression ('EightBools' (vector of 8 'bool' values) and 'EightBools')}} + (void)(eight_bools && other_eight_bools); // expected-error@48 {{invalid operands to binary expression ('EightBools' (vector of 8 'bool' values) and 'EightBools')}} + (void)(eight_bools + other_eight_bools); // expected-error@49 {{invalid operands to binary expression ('EightBools' (vector of 8 'bool' values) and 'EightBools')}} + (void)(eight_bools - other_eight_bools); // expected-error@50 {{invalid operands to binary expression ('EightBools' (vector of 8 'bool' values) and 'EightBools')}} + (void)(eight_bools * other_eight_bools); // expected-error@51 {{invalid operands to binary expression ('EightBools' (vector of 8 'bool' values) and 'EightBools')}} + (void)(eight_bools << other_eight_bools); // expected-error@52 {{invalid operands to binary expression ('EightBools' (vector of 8 'bool' values) and 'EightBools')}} + (void)(eight_bools >> other_eight_bools); // expected-error@53 {{invalid operands to binary expression ('EightBools' (vector of 8 'bool' values) and 'EightBools')}} + (void)(eight_bools / other_eight_bools); // expected-error@54 {{invalid operands to binary expression ('EightBools' (vector of 8 'bool' values) and 'EightBools')}} + (void)(eight_bools % other_eight_bools); // expected-error@55 {{invalid operands to binary expression ('EightBools' (vector of 8 'bool' values) and 'EightBools')}} + + // Illegal assignment + (void)(eight_bools += other_eight_bools); // expected-error@58 {{invalid operands to binary expression ('EightBools' (vector of 8 'bool' values) and 'EightBools')}} + (void)(eight_bools -= other_eight_bools); // expected-error@59 {{invalid operands to binary expression ('EightBools' (vector of 8 'bool' values) and 'EightBools')}} + (void)(eight_bools *= other_eight_bools); // expected-error@60 {{invalid operands to binary expression ('EightBools' (vector of 8 'bool' values) and 'EightBools')}} + (void)(eight_bools <<= other_eight_bools); // expected-error@61 {{invalid operands to binary expression ('EightBools' (vector of 8 'bool' values) and 'EightBools')}} + (void)(eight_bools >>= other_eight_bools); // expected-error@62 {{invalid operands to binary expression ('EightBools' (vector of 8 'bool' values) and 'EightBools')}} + (void)(eight_bools /= other_eight_bools); // expected-error@63 {{invalid operands to binary expression ('EightBools' (vector of 8 'bool' values) and 'EightBools')}} + (void)(eight_bools %= other_eight_bools); // expected-error@64 {{invalid operands to binary expression ('EightBools' (vector of 8 'bool' values) and 'EightBools')}} + + // Illegal in/decrements + (void)(eight_bools++); // expected-error@67 {{cannot increment value of type 'EightBools' (vector of 8 'bool' values)}} + (void)(++eight_bools); // expected-error@68 {{cannot increment value of type 'EightBools' (vector of 8 'bool' values)}} + (void)(eight_bools--); // expected-error@69 {{cannot decrement value of type 'EightBools' (vector of 8 'bool' values)}} + (void)(--eight_bools); // expected-error@70 {{cannot decrement value of type 'EightBools' (vector of 8 'bool' values)}} + + // No implicit promotion + (void)(eight_bools + eight_ints); // expected-error@73 {{cannot convert between vector type 'EightInts' (vector of 8 'int' values) and vector type 'EightBools' (vector of 8 'bool' values) as implicit conversion would cause truncation}} + (void)(eight_ints - eight_bools); // expected-error@74 {{cannot convert between vector type 'EightBools' (vector of 8 'bool' values) and vector type 'EightInts' (vector of 8 'int' values) as implicit conversion would cause truncation}} +} + +// Check the conversion to integral type of same size +void Conversions() { + (void)((long)eight_bools); // expected-error@79 {{C-style cast from vector 'EightBools' (vector of 8 'bool' values) to scalar 'long' of different size}} + (void)((char)eight_bools); +} diff --git a/clang/test/SemaCXX/vector-conditional.cpp b/clang/test/SemaCXX/vector-conditional.cpp --- a/clang/test/SemaCXX/vector-conditional.cpp +++ b/clang/test/SemaCXX/vector-conditional.cpp @@ -13,6 +13,7 @@ using FourFloats = float __attribute__((__vector_size__(16))); using TwoDoubles = double __attribute__((__vector_size__(16))); using FourDoubles = double __attribute__((__vector_size__(32))); +using EightBools = bool __attribute__((__vector_size__(2))); FourShorts four_shorts; TwoInts two_ints; @@ -25,6 +26,8 @@ FourFloats four_floats; TwoDoubles two_doubles; FourDoubles four_doubles; +EightBools eight_bools; +EightBools other_eight_bools; enum E {}; enum class SE {}; @@ -95,6 +98,9 @@ (void)(four_ints ? four_uints : 3.0f); (void)(four_ints ? four_ints : 3.0f); + // Allow conditional select on bool vectors. + (void)(eight_bools ? eight_bools : other_eight_bools); + // When there is a vector and a scalar, conversions must be legal. (void)(four_ints ? four_floats : 3); // should work, ints can convert to floats. (void)(four_ints ? four_uints : e); // expected-error {{cannot convert between scalar type 'E' and vector type 'FourUInts'}} @@ -163,10 +169,10 @@ void Templates() { dependent_cond(two_ints); dependent_operand(two_floats); - // expected-error@159 {{vector operands to the vector conditional must be the same type ('__attribute__((__vector_size__(4 * sizeof(unsigned int)))) unsigned int' (vector of 4 'unsigned int' values) and '__attribute__((__vector_size__(4 * sizeof(double)))) double' (vector of 4 'double' values))}}} + // expected-error@165 {{vector operands to the vector conditional must be the same type ('__attribute__((__vector_size__(4 * sizeof(unsigned int)))) unsigned int' (vector of 4 'unsigned int' values) and '__attribute__((__vector_size__(4 * sizeof(double)))) double' (vector of 4 'double' values))}}} all_dependent(four_ints, four_uints, four_doubles); // expected-note {{in instantiation of}} - // expected-error@159 {{vector operands to the vector conditional must be the same type ('__attribute__((__vector_size__(4 * sizeof(unsigned int)))) unsigned int' (vector of 4 'unsigned int' values) and '__attribute__((__vector_size__(2 * sizeof(unsigned int)))) unsigned int' (vector of 2 'unsigned int' values))}}} + // expected-error@165 {{vector operands to the vector conditional must be the same type ('__attribute__((__vector_size__(4 * sizeof(unsigned int)))) unsigned int' (vector of 4 'unsigned int' values) and '__attribute__((__vector_size__(2 * sizeof(unsigned int)))) unsigned int' (vector of 2 'unsigned int' values))}}} all_dependent(four_ints, four_uints, two_uints); // expected-note {{in instantiation of}} all_dependent(four_ints, four_uints, four_uints); } diff --git a/clang/test/SemaCXX/vector.cpp b/clang/test/SemaCXX/vector.cpp --- a/clang/test/SemaCXX/vector.cpp +++ b/clang/test/SemaCXX/vector.cpp @@ -331,8 +331,7 @@ typedef __attribute__((ext_vector_type(4))) int vi4; const int &reference_to_vec_element = vi4(1).x; -// PR12649 -typedef bool bad __attribute__((__vector_size__(16))); // expected-error {{invalid vector element type 'bool'}} +typedef bool good __attribute__((__vector_size__(16))); namespace Templates { template @@ -350,9 +349,7 @@ void Init() { const TemplateVectorType::type Works = {}; const TemplateVectorType::type Works2 = {}; - // expected-error@#1 {{invalid vector element type 'bool'}} - // expected-note@+1 {{in instantiation of template class 'Templates::TemplateVectorType' requested here}} - const TemplateVectorType::type NoBool = {}; + const TemplateVectorType::type BoolWorks = {}; // expected-error@#1 {{invalid vector element type 'int __attribute__((ext_vector_type(4)))' (vector of 4 'int' values)}} // expected-note@+1 {{in instantiation of template class 'Templates::TemplateVectorType' requested here}} const TemplateVectorType::type NoComplex = {};