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,68 @@ 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 +--------------- + +Different than 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 +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 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. 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 --------------- @@ -484,6 +546,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 +556,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 @@ -3245,6 +3245,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/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -11305,7 +11305,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 @@ -1969,7 +1969,8 @@ case Type::Vector: { const auto *VT = cast(T); TypeInfo EltInfo = getTypeInfo(VT->getElementType()); - Width = EltInfo.Width * VT->getNumElements(); + Width = 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 @@ -647,8 +647,7 @@ 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() + OS << "__attribute__((__vector_size__(" << T->getNumElements() << " * sizeof("; print(T->getElementType(), OS, StringRef()); OS << ")))) "; 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 @@ -2742,6 +2742,23 @@ llvm::DIType *CGDebugInfo::CreateType(const VectorType *Ty, llvm::DIFile *Unit) { + if (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 @@ -1680,27 +1680,45 @@ 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 (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 *IRVecTy = cast(EltTy); + + if (!CGM.getCodeGenOpts().PreserveVec3Type && + IRVecTy->getNumElements() == 3) { + + // Bitcast to vec4 type. + llvm::VectorType *vec4Ty = + llvm::FixedVectorType::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); } } @@ -1744,6 +1762,13 @@ return Value; } +static bool isBooleanVector(QualType Ty) { + 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)) { @@ -1751,6 +1776,17 @@ "wrong value rep of bool"); return Builder.CreateTrunc(Value, Builder.getInt1Ty(), "tobool"); } + if (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; } @@ -1796,18 +1832,27 @@ 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 *IRVecTy = dyn_cast(SrcTy); + if (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 && 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"); @@ -2029,8 +2074,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 @@ -2079,7 +2079,30 @@ } } - 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) { + const 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) { @@ -4669,7 +4708,7 @@ if (NumElementsSrc != 3 && NumElementsDst == 3) { if (!CGF.CGM.getCodeGenOpts().PreserveVec3Type) { auto *Vec4Ty = llvm::FixedVectorType::get( - cast(DstTy)->getElementType(), 4); + cast(DstTy)->getElementType(), 4); Src = createCastsForTypeOfSameSize(Builder, CGF.CGM.getDataLayout(), Src, Vec4Ty); } 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 @@ -4460,6 +4460,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 @@ -2494,3 +2494,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,16 @@ llvm::Type *R = ConvertType(T); + // Check for the boolean vector case + auto *FixedVT = dyn_cast(R); + if (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()) || @@ -708,8 +718,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 @@ -8009,9 +8009,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. @@ -8075,9 +8076,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); @@ -9768,10 +9770,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()) @@ -9797,6 +9806,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; @@ -10044,8 +10058,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); if (!IsDiv && (LHS.get()->getType()->isConstantMatrixType() || RHS.get()->getType()->isConstantMatrixType())) return CheckMatrixMultiplyOperands(LHS, RHS, Loc, IsCompAssign); @@ -10074,8 +10089,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); } @@ -10360,10 +10376,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; } @@ -10460,10 +10477,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; } @@ -11893,6 +11911,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(), @@ -11913,9 +11934,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; @@ -12062,8 +12085,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 && @@ -12156,6 +12180,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) { @@ -12164,13 +12202,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 @@ -5946,7 +5946,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 { @@ -6264,9 +6265,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,6 +2496,7 @@ << SizeExpr->getSourceRange() << "vector"; return QualType(); } + uint64_t VectorSizeBits = VecSize->getZExtValue() * 8; unsigned TypeSize = static_cast(Context.getTypeSize(CurType)); @@ -2517,7 +2518,8 @@ return QualType(); } - return Context.getVectorType(CurType, VectorSizeBits / TypeSize, + uint64_t ElemSizeBits = CurType->isBooleanType() ? 1 : TypeSize; + return Context.getVectorType(CurType, VectorSizeBits / ElemSizeBits, VectorType::GenericVector); } @@ -7562,13 +7564,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/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 -emit-llvm -debug-info-kind=limited %s -o - | FileCheck %s +typedef _Bool bool32 __attribute__((__vector_size__(4))); + +bool32 b; + +// Test that we get an char array type. +// CHECK: !DICompositeType(tag: DW_TAG_array_type, +// CHECK-SAME: baseType: ![[CHAR:[0-9]+]] +// CHECK-SAME: size: 32 +// CHECK-SAME: DIFlagVector +// CHECK: ![[CHAR]] = !DIBasicType(name: "char" 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 @@ -204,35 +204,35 @@ constexpr auto w = FourCharsVecSize{1, 2, 3, 4} < FourCharsVecSize{4, 3, 2, 1}; - // CHECK: store <4 x i8> + // CHECK: store i8 bitcast (<8 x i1> to i8) constexpr auto x = FourCharsVecSize{1, 2, 3, 4} > FourCharsVecSize{4, 3, 2, 1}; - // CHECK: store <4 x i8> + // CHECK: store i8 bitcast (<8 x i1> to i8) constexpr auto y = FourCharsVecSize{1, 2, 3, 4} <= FourCharsVecSize{4, 3, 3, 1}; - // CHECK: store <4 x i8> + // CHECK: store i8 bitcast (<8 x i1> to i8) constexpr auto z = FourCharsVecSize{1, 2, 3, 4} >= FourCharsVecSize{4, 3, 3, 1}; - // CHECK: store <4 x i8> + // CHECK: store i8 bitcast (<8 x i1> to i8) constexpr auto A = FourCharsVecSize{1, 2, 3, 4} == FourCharsVecSize{4, 3, 3, 1}; - // CHECK: store <4 x i8> + // CHECK: store i8 bitcast (<8 x i1> to i8) constexpr auto B = FourCharsVecSize{1, 2, 3, 4} != FourCharsVecSize{4, 3, 3, 1}; - // CHECK: store <4 x i8> + // CHECK: store i8 bitcast (<8 x i1> to i8) constexpr auto C = FourCharsVecSize{1, 2, 3, 4} < 3; - // CHECK: store <4 x i8> + // CHECK: store i8 bitcast (<8 x i1> to i8) constexpr auto D = FourCharsVecSize{1, 2, 3, 4} > 3; - // CHECK: store <4 x i8> + // CHECK: store i8 bitcast (<8 x i1> to i8) constexpr auto E = FourCharsVecSize{1, 2, 3, 4} <= 3; - // CHECK: store <4 x i8> + // CHECK: store i8 bitcast (<8 x i1> to i8) constexpr auto F = FourCharsVecSize{1, 2, 3, 4} >= 3; - // CHECK: store <4 x i8> + // CHECK: store i8 bitcast (<8 x i1> to i8) constexpr auto G = FourCharsVecSize{1, 2, 3, 4} == 3; - // CHECK: store <4 x i8> + // CHECK: store i8 bitcast (<8 x i1> to i8) constexpr auto H = FourCharsVecSize{1, 2, 3, 4} != 3; - // CHECK: store <4 x i8> + // CHECK: store i8 bitcast (<8 x i1> to i8) constexpr auto I = FourCharsVecSize{1, 2, 3, 4} & FourCharsVecSize{4, 3, 2, 1}; @@ -252,15 +252,15 @@ constexpr auto O = FourCharsVecSize{5, 0, 6, 0} && FourCharsVecSize{5, 5, 0, 0}; - // CHECK: store <4 x i8> + // CHECK: store i8 bitcast (<8 x i1> to i8) constexpr auto P = FourCharsVecSize{5, 0, 6, 0} || FourCharsVecSize{5, 5, 0, 0}; - // CHECK: store <4 x i8> + // CHECK: store i8 bitcast (<8 x i1> to i8) constexpr auto Q = FourCharsVecSize{5, 0, 6, 0} && 3; - // CHECK: store <4 x i8> + // CHECK: store i8 bitcast (<8 x i1> to i8) constexpr auto R = FourCharsVecSize{5, 0, 6, 0} || 3; - // CHECK: store <4 x i8> + // CHECK: store i8 bitcast (<8 x i1> to i8) constexpr auto T = CmpMul(a, b); // CHECK: store <4 x i8> 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 = {};