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,61 @@ return v; } + +GCC vector types are created using the ``vector_size`` attribute. Different +than GCC, Clang also allows the attribute to be used with boolean element types. +For example: + +.. code-block:: c++ + + typedef int int4 __attribute__((vector_size(16))); + + int4 foo(int4 a) { + int4 v; + v = a; + return v; + } + + +Boolean Vectors +--------------- + +.. code-block:: c++ + + // legal for Clang, error for GCC: + typedef bool bool8 __attribute__((vector_size(8))); + // Objects of bool8 type hold 8 bits, sizeof(bool8) == 1 + + bool8 foo(bool8 a) { + bool8 v; + v = a; + return v; + } + +Boolean vectors are a Clang extension of the GCC vector type +(`attribute(vector_size)`). Boolean vectors are intended, though not +guaranteed, to map to vector mask registers. 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 size parameter of a boolean vector type is the number of +bits in the vector (for all non-bool vectors, the number refers to the number +of bytes in the vector). + +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). +* Bitwise `~`, `|`, `&`, `^` and `~` are the only allowed operators on boolean + vectors. + +The memory representation of a boolean vector is the smallest fitting +power-of-two integer with at least eight bits (`sizeof(char)`)'. The alignment +is the alignment of that integer type. This permits the use of these types in +allocated arrays using the common ``sizeof(Array)/sizeof(ElementType)`` +pattern. + + Vector Literals --------------- @@ -446,7 +501,7 @@ .. code-block:: c++ - typedef int v4si __attribute__((__vector_size__(16))); + typedef int v4si __attribute__((__vector_size__(4))); typedef float float4 __attribute__((ext_vector_type(4))); typedef float float2 __attribute__((ext_vector_type(2))); @@ -484,6 +539,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`. @@ -494,6 +550,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/ASTContext.h b/clang/include/clang/AST/ASTContext.h --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -3138,4 +3138,6 @@ return Value; } +unsigned getBoolVectorPaddedSize(unsigned TypeNumBits); + #endif // LLVM_CLANG_AST_ASTCONTEXT_H 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 @@ -11202,7 +11202,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); 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 @@ -103,6 +103,20 @@ Float16Rank, HalfRank, FloatRank, DoubleRank, LongDoubleRank, Float128Rank }; +unsigned getBoolVectorPaddedSize(unsigned TypeNumBits) { + const unsigned MinimalSize = 8; // FIXME Target->getCharWidth() + TypeNumBits = std::max<>(MinimalSize, TypeNumBits); + + // Pad to the next power of two if above + bool IsNotPowerOfTwo = (TypeNumBits & (TypeNumBits - 1)); + if (IsNotPowerOfTwo) { + TypeNumBits = llvm::NextPowerOf2(TypeNumBits); + } + + assert(TypeNumBits != 0); + return TypeNumBits; +} + /// \returns location that is relevant when searching for Doc comments related /// to \p D. static SourceLocation getDeclLocForCommentSearch(const Decl *D, @@ -1915,11 +1929,17 @@ break; } - case Type::ExtVector: - case Type::Vector: { + case Type::Vector: + case Type::ExtVector: { const auto *VT = cast(T); - TypeInfo EltInfo = getTypeInfo(VT->getElementType()); - Width = EltInfo.Width * VT->getNumElements(); + bool IsBoolVector = VT->getElementType()->isBooleanType(); + // 'vector_size' bool vectors are supported + if (IsBoolVector && (T->getTypeClass() == Type::Vector)) { + Width = getBoolVectorPaddedSize(VT->getNumElements()); + } else { + TypeInfo EltInfo = getTypeInfo(VT->getElementType()); + Width = 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: { - // 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 << ")))) "; + if (T->getElementType()->isBooleanType()) { + // For a vector of boolean, the vector_size parameter is the number of + // bits. + OS << "__attribute__((__vector_size__(" << T->getNumElements() << "))) "; + } else { + // 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 << ")))) "; + } printBefore(T->getElementType(), OS); break; } @@ -696,9 +701,13 @@ OS << "__attribute__((__vector_size__("; if (T->getSizeExpr()) T->getSizeExpr()->printPretty(OS, nullptr, Policy); - OS << " * sizeof("; - print(T->getElementType(), OS, StringRef()); - OS << ")))) "; + if (T->getElementType()->isBooleanType()) { + OS << "))) "; + } else { + OS << " * sizeof("; + print(T->getElementType(), OS, StringRef()); + OS << ")))) "; + } printBefore(T->getElementType(), OS); break; } 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 @@ -1669,27 +1669,47 @@ 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); - } + auto ClangVecTy = Ty->getAs(); + if (ClangVecTy) { + QualType ClangElemTy = ClangVecTy->getElementType(); + // Boolean vectors use `iN` as storage type + if (ClangVecTy->getVectorKind() == VectorType::GenericVector && + ClangElemTy->isBooleanType()) { + 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"); + auto RawIntTy = RawIntV->getType(); + assert(RawIntTy->isIntegerTy() && "compressed iN storage for bitvectors"); + // Bitcast iP -->

+ auto PaddedVecTy = llvm::VectorType::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 *IRVecTy = cast(EltTy); + + if (!CGM.getCodeGenOpts().PreserveVec3Type && + IRVecTy->getNumElements() == 3) { + + // Bitcast to vec4 type. + llvm::VectorType *vec4Ty = + llvm::VectorType::get(IRVecTy->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); } } @@ -1785,18 +1805,29 @@ 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(); + auto ClangVecTy = Ty->getAs(); + if (ClangVecTy) { + QualType ClangElemTy = ClangVecTy->getElementType(); + auto *IRVecTy = dyn_cast(SrcTy); + if (ClangElemTy->isBooleanType() && + ClangVecTy->getVectorKind() == VectorType::GenericVector) { + 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 && VecTy->getNumElements() == 3) { + if (IRVecTy && IRVecTy->getNumElements() == 3) { // Our source is a vec3, do a shuffle vector to make it a vec4. - Value = Builder.CreateShuffleVector(Value, llvm::UndefValue::get(VecTy), - ArrayRef{0, 1, 2, -1}, - "extractVec"); - SrcTy = llvm::FixedVectorType::get(VecTy->getElementType(), 4); + Value = Builder.CreateShuffleVector( + Value, llvm::UndefValue::get(IRVecTy), ArrayRef{0, 1, 2, -1}, + "extractVec"); + SrcTy = llvm::FixedVectorType::get(IRVecTy->getElementType(), 4); } if (Addr.getElementType() != SrcTy) { Addr = Builder.CreateElementBitCast(Addr, SrcTy, "storetmp"); @@ -2018,8 +2049,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::VectorType::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 @@ -2071,7 +2071,30 @@ CGF.getDebugInfo()-> addHeapAllocSiteMetadata(CI, CE->getType(), 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()); + if (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 (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; @@ -4639,6 +4662,17 @@ return Builder.CreateIntToPtr(Src, DstTy, Name); } +static bool IsGenericBoolVector(QualType Ty) { + auto ClangVecTy = dyn_cast(Ty); + if (!ClangVecTy) + return false; + + if (ClangVecTy->getVectorKind() != VectorType::GenericVector) + return false; + + return ClangVecTy->getElementType()->isBooleanType(); +} + Value *ScalarExprEmitter::VisitAsTypeExpr(AsTypeExpr *E) { Value *Src = CGF.EmitScalarExpr(E->getSrcExpr()); llvm::Type *DstTy = ConvertType(E->getType()); @@ -4649,6 +4683,11 @@ unsigned NumElementsDst = isa(DstTy) ? cast(DstTy)->getNumElements() : 0; + // Use bit vector expansion for generic boolean vectors + if (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) { @@ -4668,7 +4707,7 @@ // get a vec3. if (NumElementsSrc != 3 && NumElementsDst == 3) { if (!CGF.CGM.getCodeGenOpts().PreserveVec3Type) { - auto *Vec4Ty = llvm::FixedVectorType::get( + auto Vec4Ty = llvm::VectorType::get( cast(DstTy)->getElementType(), 4); Src = createCastsForTypeOfSameSize(Builder, CGF.CGM.getDataLayout(), Src, Vec4Ty); diff --git a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp --- a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -586,7 +586,8 @@ void CGRecordLowering::clipTailPadding() { std::vector::iterator Prior = Members.begin(); - CharUnits Tail = getSize(Prior->Data); + CharUnits Tail = + getSize(Prior->Data); // FIXME assumes `i8` multiples for boolean vector! for (std::vector::iterator Member = Prior + 1, MemberEnd = Members.end(); Member != MemberEnd; ++Member) { 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 @@ -4344,6 +4344,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 @@ -2453,3 +2453,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,18 @@ llvm::Type *R = ConvertType(T); + // Check for the boolean vector case + auto FixedVT = dyn_cast(R); + if (T->isVectorType() && FixedVT && + FixedVT->getElementType()->isIntegerTy(1)) { + + // Find the smallest power-of-two integer that accomodates the boolean + // vector. eg <17 x i1> is stored as i32 <8 x i1> is stored as i8 <3 x i1> + // is stored as i8 + uint64_t PaddedSize = getBoolVectorPaddedSize(FixedVT->getNumElements()); + return llvm::IntegerType::get(FixedVT->getContext(), PaddedSize); + } + // 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()) || R->isIntegerTy(1)) @@ -649,8 +661,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::VectorType::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 @@ -8030,9 +8030,10 @@ 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, + /*AllowBooleanOperator*/ false); if (VecResTy.isNull()) return QualType(); // The result type must match the condition type as specified in // OpenCL v1.1 s6.11.6. @@ -8096,9 +8097,10 @@ // 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, + /*AllowBooleanOperator*/ false); QualType ResTy = UsualArithmeticConversions(LHS, RHS, QuestionLoc, ACK_Conditional); @@ -9775,10 +9777,17 @@ return false; } +static bool IsScalarOrVectorBool(QualType Ty) { + return Ty->isBooleanType() || + (Ty->isVectorType() && + Ty->getAs()->getElementType()->isBooleanType()); +} + QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign, bool AllowBothBool, - bool AllowBoolConversions) { + bool AllowBoolConversions, + bool AllowBoolOperation) { if (!IsCompAssign) { LHS = DefaultFunctionArrayLvalueConversion(LHS.get()); if (LHS.isInvalid()) @@ -9804,6 +9813,11 @@ RHSVecType && RHSVecType->getVectorKind() == VectorType::AltiVecBool) return InvalidOperands(Loc, LHS, RHS); + // This operation may not be performed on boolean vectors. + if (!AllowBoolOperation && IsScalarOrVectorBool(LHSType) && + IsScalarOrVectorBool(RHSType)) + return InvalidOperands(Loc, LHS, RHS); + // If the vector types are identical, return. if (Context.hasSameType(LHSType, RHSType)) return LHSType; @@ -10051,8 +10065,9 @@ 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); QualType compType = UsualArithmeticConversions( LHS, RHS, Loc, IsCompAssign ? ACK_CompAssign : ACK_Arithmetic); @@ -10078,8 +10093,9 @@ 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); return InvalidOperands(Loc, LHS, RHS); } @@ -10364,10 +10380,11 @@ 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); if (CompLHSTy) *CompLHSTy = compType; return compType; } @@ -10464,10 +10481,11 @@ 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); if (CompLHSTy) *CompLHSTy = compType; return compType; } @@ -11886,6 +11904,9 @@ else if (TypeSize == Context.getTypeSize(Context.ShortTy)) return Context.getVectorType(Context.ShortTy, VTy->getNumElements(), VectorType::GenericVector); + else if (TypeSize == Context.getTypeSize(Context.BoolTy)) + return Context.getVectorType(Context.BoolTy, VTy->getNumElements(), + VectorType::GenericVector); assert(TypeSize == Context.getTypeSize(Context.CharTy) && "Unhandled vector element size in vector compare"); return Context.getVectorType(Context.CharTy, VTy->getNumElements(), @@ -11906,9 +11927,11 @@ // 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*/ false); if (vType.isNull()) return vType; @@ -12055,8 +12078,9 @@ // 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); if (vType.isNull()) return InvalidOperands(Loc, LHS, RHS); if (getLangOpts().OpenCL && getLangOpts().OpenCLVersion < 120 && @@ -12115,6 +12139,20 @@ return InvalidOperands(Loc, LHS, RHS); } +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) { @@ -12123,13 +12161,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); + return CheckVectorOperands( + LHS, RHS, Loc, IsCompAssign, + /*AllowBothBool*/ true, + /*AllowBoolConversions*/ getLangOpts().ZVector, + /*AllowBooleanOperation*/ LegalBoolVecOperator); 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 @@ -5947,7 +5947,8 @@ } else if (LHSVT || RHSVT) { ResultType = CheckVectorOperands( LHS, RHS, QuestionLoc, /*isCompAssign*/ false, /*AllowBothBool*/ true, - /*AllowBoolConversions*/ false); + /*AllowBoolConversions*/ false, + /*AllowBoolOperator*/ false); if (ResultType.isNull()) return {}; } else { @@ -6265,9 +6266,10 @@ // 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, + /*AllowBoolOperator*/ false); // -- 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 @@ -2464,10 +2464,10 @@ 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->isBuiltinType() || (!CurType->isIntegerType() && !CurType->isRealFloatingType()))) { Diag(AttrLoc, diag::err_attribute_invalid_vector_type) << CurType; return QualType(); @@ -2496,8 +2496,14 @@ << SizeExpr->getSourceRange() << "vector"; return QualType(); } - uint64_t VectorSizeBits = VecSize.getZExtValue() * 8; - unsigned TypeSize = static_cast(Context.getTypeSize(CurType)); + + uint64_t VectorSizeBits = + CurType->isBooleanType() + ? VecSize.getZExtValue() + : VecSize.getZExtValue() * 8; // FIXME "bitsof(CharUnit)" + unsigned TypeSize = CurType->isBooleanType() + ? 1 + : static_cast(Context.getTypeSize(CurType)); if (VectorSizeBits == 0) { Diag(AttrLoc, diag::err_attribute_zero_size) @@ -7549,13 +7555,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/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 = {};