simoll created this revision. simoll added reviewers: hfinkel, erichkeane, craig.topper, rsandifo-arm, kaz7, k-ishizaka, rengolin. Herald added subscribers: cfe-commits, pengfei, kristof.beyls. Herald added a project: clang. simoll requested review of this revision.
This is the `ext_vector_type` alternative to D81083 <https://reviews.llvm.org/D81083>. This patch extends Clang to allow 'bool' as a valid vector element type (attribute ext_vector_type) in C/C++. This is intended as the canonical type for SIMD masks and facilitates clean vector intrinsic declarations. Vectors of i1 are supported on IR level and below down to many SIMD ISAs, such as AVX512, ARM SVE (fixed vector length) and the VE target (NEC SX-Aurora TSUBASA). The RFC on cfe-dev: https://lists.llvm.org/pipermail/cfe-dev/2020-May/065434.html Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D88905 Files: clang/docs/LanguageExtensions.rst clang/include/clang/AST/Type.h clang/include/clang/Sema/Sema.h clang/lib/AST/ASTContext.cpp clang/lib/AST/TypePrinter.cpp clang/lib/CodeGen/CGDebugInfo.cpp clang/lib/CodeGen/CGExpr.cpp clang/lib/CodeGen/CGExprScalar.cpp clang/lib/CodeGen/CodeGenFunction.cpp clang/lib/CodeGen/CodeGenFunction.h clang/lib/CodeGen/CodeGenTypes.cpp clang/lib/Sema/SemaExpr.cpp clang/lib/Sema/SemaExprCXX.cpp clang/lib/Sema/SemaType.cpp clang/test/AST/ast-print-vector-size-bool.c clang/test/CodeGen/debug-info-vector-bool.c clang/test/CodeGen/vector-alignment.c clang/test/Sema/ext_vector_casts.c clang/test/SemaCXX/constexpr-vectors.cpp clang/test/SemaCXX/vector-bool.cpp clang/test/SemaCXX/vector-conditional.cpp clang/test/SemaOpenCL/ext_vectors.cl
Index: clang/test/SemaOpenCL/ext_vectors.cl =================================================================== --- clang/test/SemaOpenCL/ext_vectors.cl +++ clang/test/SemaOpenCL/ext_vectors.cl @@ -2,6 +2,7 @@ // RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -cl-std=CL2.0 typedef float float4 __attribute__((ext_vector_type(4))); +typedef __attribute__((ext_vector_type(8))) bool BoolVector; // expected-error {{invalid vector element type 'bool'}} void test_ext_vector_accessors(float4 V) { V = V.wzyx; Index: clang/test/SemaCXX/vector-conditional.cpp =================================================================== --- clang/test/SemaCXX/vector-conditional.cpp +++ 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__((ext_vector_type(8))); 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); } Index: clang/test/SemaCXX/vector-bool.cpp =================================================================== --- /dev/null +++ clang/test/SemaCXX/vector-bool.cpp @@ -0,0 +1,80 @@ +// 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__((ext_vector_type(8))); + +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}} +} + +// Don't allow bool vector conversions +void Conversions() { + (void)((char)eight_bools); // expected-error@79 {{C-style cast from vector 'EightBools' (vector of 8 'bool' values) to scalar 'char' of different size}} +} Index: clang/test/SemaCXX/constexpr-vectors.cpp =================================================================== --- clang/test/SemaCXX/constexpr-vectors.cpp +++ clang/test/SemaCXX/constexpr-vectors.cpp @@ -614,3 +614,19 @@ constexpr auto Y = CmpSub(a, b); // CHECK: store <4 x float> <float 1.200000e+01, float 1.700000e+01, float -1.000000e+00, float -1.000000e+00> } + +using EightBoolsExtVector __attribute__((ext_vector_type(8))) = bool; +void BoolVecUsage() { + constexpr auto a = EightBoolsExtVector{true, false, true, false} < + EightBoolsExtVector{false, false, true, true}; + constexpr auto b = EightBoolsExtVector{true, false, true, false} <= + EightBoolsExtVector{false, false, true, true}; + constexpr auto c = EightBoolsExtVector{true, false, true, false} == + EightBoolsExtVector{false, false, true, true}; + constexpr auto d = EightBoolsExtVector{true, false, true, false} != + EightBoolsExtVector{false, false, true, true}; + constexpr auto e = EightBoolsExtVector{true, false, true, false} >= + EightBoolsExtVector{false, false, true, true}; + constexpr auto f = EightBoolsExtVector{true, false, true, false} > + EightBoolsExtVector{false, false, true, true}; +} Index: clang/test/Sema/ext_vector_casts.c =================================================================== --- clang/test/Sema/ext_vector_casts.c +++ clang/test/Sema/ext_vector_casts.c @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -fsyntax-only -verify -flax-vector-conversions=none -Wconversion %s -typedef __attribute__((ext_vector_type(8))) _Bool BoolVector; // expected-error {{invalid vector element type '_Bool'}} +typedef __attribute__((ext_vector_type(8))) _Bool BoolVector; typedef __attribute__(( ext_vector_type(2) )) float float2; typedef __attribute__(( ext_vector_type(3) )) float float3; Index: clang/test/CodeGen/vector-alignment.c =================================================================== --- clang/test/CodeGen/vector-alignment.c +++ clang/test/CodeGen/vector-alignment.c @@ -22,6 +22,9 @@ // SSE: @v2 {{.*}}, align 16 // AVX: @v2 {{.*}}, align 32 // AVX512: @v2 {{.*}}, align 32 +typedef __attribute__((__ext_vector_type__(16))) _Bool v2b_type; +v2b_type v2b; +// ALL: @v2b {{.*}}, align 2 // Alignment above target max alignment with no aligned attribute should align // based on the target max. @@ -33,6 +36,11 @@ // SSE: @v4 {{.*}}, align 16 // AVX: @v4 {{.*}}, align 32 // AVX512: @v4 {{.*}}, align 64 +typedef __attribute__((__ext_vector_type__(8192))) _Bool v4b_type; +v4b_type 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 +51,9 @@ // ALL: @v7 {{.*}}, align 16 double __attribute__((vector_size(32), aligned(64))) v8; // ALL: @v8 {{.*}}, align 64 +typedef __attribute__((ext_vector_type(256), aligned(128))) _Bool v8b_type; +v8b_type v8b; +// ALL: @v8b {{.*}}, align 128 // Check non-power of 2 widths. double __attribute__((vector_size(24))) v9; @@ -53,9 +64,17 @@ // SSE: @v10 {{.*}}, align 16 // AVX: @v10 {{.*}}, align 32 // AVX512: @v10 {{.*}}, align 64 +typedef __attribute__((ext_vector_type(248))) _Bool v10b_type; +v10b_type 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 +typedef __attribute__((ext_vector_type(248), aligned(4))) _Bool v12b_type; +v12b_type v12b; +// ALL: @v12b {{.*}}, align 4 Index: clang/test/CodeGen/debug-info-vector-bool.c =================================================================== --- /dev/null +++ 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__((ext_vector_type(512))); + +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" Index: clang/test/AST/ast-print-vector-size-bool.c =================================================================== --- /dev/null +++ clang/test/AST/ast-print-vector-size-bool.c @@ -0,0 +1,4 @@ +// RUN: %clang_cc1 -ast-print %s -o - | FileCheck %s + +// CHECK: typedef _Bool bool32 __attribute__((ext_vector_type(32))); +typedef _Bool bool32 __attribute__((ext_vector_type(32))); Index: clang/lib/Sema/SemaType.cpp =================================================================== --- clang/lib/Sema/SemaType.cpp +++ clang/lib/Sema/SemaType.cpp @@ -2585,9 +2585,12 @@ // reserved data type under OpenCL v2.0 s6.1.4), we don't support selects // on bitvectors, and we have no well-defined ABI for bitvectors, so vectors // of bool aren't allowed. + // + // We explictly allow bool elements in ext_vector_type for C/C++. + bool IsNoBoolVecLang = getLangOpts().OpenCL || getLangOpts().OpenCLCPlusPlus; if ((!T->isDependentType() && !T->isIntegerType() && !T->isRealFloatingType()) || - T->isBooleanType()) { + (IsNoBoolVecLang && T->isBooleanType())) { Diag(AttrLoc, diag::err_attribute_invalid_vector_type) << T; return QualType(); } Index: clang/lib/Sema/SemaExprCXX.cpp =================================================================== --- clang/lib/Sema/SemaExprCXX.cpp +++ clang/lib/Sema/SemaExprCXX.cpp @@ -5911,14 +5911,14 @@ // extension. static bool isValidVectorForConditionalCondition(ASTContext &Ctx, QualType CondTy) { - if (!CondTy->isVectorType() || CondTy->isExtVectorType()) + const auto *VecVT = CondTy->getAs<VectorType>(); + if (!VecVT || (VecVT->isExtVectorType() && !VecVT->isExtVectorBoolean())) return false; const QualType EltTy = cast<VectorType>(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, @@ -5940,13 +5940,14 @@ // FIXME: In the future we should define what the Extvector conditional // operator looks like. - if (LHSVT && isa<ExtVectorType>(LHSVT)) { + // We explicitly allow this for ext_vector_type boolean as a Clang extension. + if (LHSVT && isa<ExtVectorType>(LHSVT) && !LHSVT->isExtVectorBoolean()) { Diag(QuestionLoc, diag::err_conditional_vector_operand_type) << /*isExtVector*/ true << LHSType; return {}; } - if (RHSVT && isa<ExtVectorType>(RHSVT)) { + if (RHSVT && isa<ExtVectorType>(RHSVT) && !RHSVT->isExtVectorBoolean()) { Diag(QuestionLoc, diag::err_conditional_vector_operand_type) << /*isExtVector*/ true << RHSType; return {}; @@ -5963,7 +5964,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 +6284,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 Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -7200,11 +7200,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 &IsBitVector) { // Vectors are simple. + IsBitVector = false; if (const VectorType *vecType = type->getAs<VectorType>()) { len = vecType->getNumElements(); + IsBitVector = vecType->isExtVectorBoolean(); eltType = vecType->getElementType(); assert(eltType->isScalarType()); return true; @@ -7239,14 +7241,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 = true; // 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,10 +8025,14 @@ // result as specified in OpenCL v1.1 s6.3.i. if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) { + bool IsBoolVecLang = + !S.getLangOpts().OpenCL && !S.getLangOpts().OpenCLCPlusPlus; QualType VecResTy = S.CheckVectorOperands(LHS, RHS, QuestionLoc, - /*isCompAssign*/false, - /*AllowBothBool*/true, - /*AllowBoolConversions*/false); + /*isCompAssign*/ false, + /*AllowBothBool*/ true, + /*AllowBoolConversions*/ false, + /*AllowBooleanOperation*/ IsBoolVecLang, + /*ReportInvalid*/ true); if (VecResTy.isNull()) return QualType(); // The result type must match the condition type as specified in // OpenCL v1.1 s6.11.6. @@ -8083,9 +8096,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); @@ -9784,10 +9799,17 @@ return false; } +static bool IsScalarOrVectorBool(QualType Ty) { + return Ty->isBooleanType() || + (Ty->isVectorType() && Ty->getAs<VectorType>()->isExtVectorBoolean()); +} + 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()) @@ -9808,14 +9830,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 && IsScalarOrVectorBool(LHSType) && + IsScalarOrVectorBool(RHSType)) + return ReportInvalid ? InvalidOperands(Loc, LHS, RHS) : QualType(); // If the vector types are identical, return. if (Context.hasSameType(LHSType, RHSType)) @@ -10080,8 +10107,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); @@ -10110,8 +10139,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); } @@ -10396,10 +10427,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; } @@ -10496,10 +10529,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; } @@ -10737,6 +10772,15 @@ const VectorType *RHSVecTy = RHSType->getAs<VectorType>(); QualType RHSEleType = RHSVecTy ? RHSVecTy->getElementType() : RHSType; + // Do not allow shifts for boolean vectors. + if ((LHSVecTy && LHSVecTy->isExtVectorBoolean()) || + (RHSVecTy && RHSVecTy->isExtVectorBoolean())) { + 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) @@ -11924,7 +11968,9 @@ return Context.getExtVectorType(Context.LongLongTy, VTy->getNumElements()); } - if (TypeSize == Context.getTypeSize(Context.LongLongTy)) + if (VTy->isExtVectorBoolean()) + return Context.getExtVectorType(Context.BoolTy, VTy->getNumElements()); + else if (TypeSize == Context.getTypeSize(Context.LongLongTy)) return Context.getVectorType(Context.LongLongTy, VTy->getNumElements(), VectorType::GenericVector); else if (TypeSize == Context.getTypeSize(Context.LongTy)) @@ -11956,9 +12002,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; @@ -12105,8 +12154,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 && @@ -12199,6 +12250,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) { @@ -12207,13 +12272,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); } Index: clang/lib/CodeGen/CodeGenTypes.cpp =================================================================== --- clang/lib/CodeGen/CodeGenTypes.cpp +++ clang/lib/CodeGen/CodeGenTypes.cpp @@ -91,6 +91,15 @@ llvm::Type *R = ConvertType(T); + // Check for the boolean vector case + const auto *VT = T->getAs<VectorType>(); + if (VT && VT->isExtVectorBoolean()) { + auto *FixedVT = dyn_cast<llvm::FixedVectorType>(R); + // Pad to at least one byte. + uint64_t BytePadded = std::max<uint64_t>(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()) || @@ -669,9 +678,12 @@ } case Type::ExtVector: case Type::Vector: { - const VectorType *VT = cast<VectorType>(Ty); - ResultType = llvm::FixedVectorType::get(ConvertType(VT->getElementType()), - VT->getNumElements()); + const auto *VT = cast<VectorType>(Ty); + // ext_vector_type of Bool is really a vector of bits + llvm::Type *IRElemTy = VT->isExtVectorBoolean() + ? llvm::Type::getInt1Ty(getLLVMContext()) + : ConvertType(VT->getElementType()); + ResultType = llvm::FixedVectorType::get(IRElemTy, VT->getNumElements()); break; } case Type::ConstantMatrix: { Index: clang/lib/CodeGen/CodeGenFunction.h =================================================================== --- clang/lib/CodeGen/CodeGenFunction.h +++ 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); Index: clang/lib/CodeGen/CodeGenFunction.cpp =================================================================== --- clang/lib/CodeGen/CodeGenFunction.cpp +++ 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<llvm::FixedVectorType>(SrcVec->getType()); + unsigned NumElementsSrc = SrcTy->getNumElements(); + if (NumElementsSrc == NumElementsDst) { + return SrcVec; + } + + std::vector<int> 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); +} Index: clang/lib/CodeGen/CGExprScalar.cpp =================================================================== --- clang/lib/CodeGen/CGExprScalar.cpp +++ clang/lib/CodeGen/CGExprScalar.cpp @@ -1917,6 +1917,14 @@ return true; } +static bool isExtVectorBool(QualType Ty) { + const auto *ClangVecTy = Ty->getAs<VectorType>(); + if (!ClangVecTy) + return false; + + return ClangVecTy->isExtVectorBoolean(); +} + // VisitCastExpr - Emit code for an explicit or implicit cast. Implicit casts // have to handle a more broad range of conversions than explicit casts, as they // handle things like function to ptr-to-function decay etc. @@ -1958,7 +1966,7 @@ case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: case CK_BitCast: { - Value *Src = Visit(const_cast<Expr*>(E)); + Value *Src = Visit(const_cast<Expr *>(E)); llvm::Type *SrcTy = Src->getType(); llvm::Type *DstTy = ConvertType(DestTy); if (SrcTy->isPtrOrPtrVectorTy() && DstTy->isPtrOrPtrVectorTy() && @@ -2031,7 +2039,31 @@ return EmitLoadOfLValue(DestLV, CE->getExprLoc()); } - return Builder.CreateBitCast(Src, DstTy); + // SExt/Trunc ext_vector_type boolean vectors to fit the expected type + auto *VecSrcTy = dyn_cast<llvm::VectorType>(Src->getType()); + auto *VecDstTy = dyn_cast<llvm::VectorType>(DstTy); + bool VectorElementCast = + VecSrcTy && VecDstTy && + (VecSrcTy->getElementCount() == VecDstTy->getElementCount()); + + if (isExtVectorBool(E->getType())) { + // 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 (isExtVectorBool(DestTy)) { + auto *PlainIntTy = + llvm::VectorType::get(Builder.getIntNTy(SrcTy->getScalarSizeInBits()), + VecSrcTy->getElementCount()); + Src = Builder.CreateTrunc(Src, PlainIntTy); + } + return Src; } case CK_AddressSpaceConversion: { Expr::EvalResult Result; @@ -4585,6 +4617,11 @@ ? cast<llvm::FixedVectorType>(DstTy)->getNumElements() : 0; + // Use bit vector expansion for generic boolean vectors + if (isExtVectorBool(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) { Index: clang/lib/CodeGen/CGExpr.cpp =================================================================== --- clang/lib/CodeGen/CGExpr.cpp +++ 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<llvm::FixedVectorType>(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<int>{0, 1, 2}, "extractVec"); - return EmitFromMemory(V, Ty); - } + const auto *ClangVecTy = Ty->getAs<VectorType>(); + if (ClangVecTy) { + // Boolean vectors use `iN` as storage type + if (ClangVecTy->isExtVectorBoolean()) { + llvm::Type *ValTy = ConvertType(Ty); + unsigned ValNumElems = + cast<llvm::FixedVectorType>(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 --> <P x i1> + auto *PaddedVecTy = llvm::FixedVectorType::get( + Builder.getInt1Ty(), RawIntTy->getPrimitiveSizeInBits()); + llvm::Value *V = Builder.CreateBitCast(RawIntV, PaddedVecTy); + // Shuffle <P x i1> --> <N x i1> (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<llvm::FixedVectorType>(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<int>{0, 1, 2}, "extractVec"); + return EmitFromMemory(V, Ty); } } @@ -1751,6 +1768,13 @@ return Value; } +static bool isBooleanVector(QualType Ty) { + const auto *VecTy = Ty->getAs<VectorType>(); + if (!VecTy) + return false; + return VecTy->isExtVectorBoolean(); +} + 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 (isBooleanVector(Ty)) { + const auto *RawIntTy = Value->getType(); + // Bitcast iP --> <P x i1> + auto *PaddedVecTy = llvm::FixedVectorType::get( + Builder.getInt1Ty(), RawIntTy->getPrimitiveSizeInBits()); + auto *V = Builder.CreateBitCast(Value, PaddedVecTy); + // Shuffle <P x i1> --> <N x i1> (N is the actual bit size) + llvm::Type *ValTy = ConvertType(Ty); + unsigned ValNumElems = cast<llvm::FixedVectorType>(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<llvm::VectorType>(SrcTy); + llvm::Type *SrcTy = Value->getType(); + const auto *ClangVecTy = Ty->getAs<VectorType>(); + if (ClangVecTy) { + auto *VecTy = dyn_cast<llvm::FixedVectorType>(SrcTy); + if (VecTy && ClangVecTy->isExtVectorBoolean()) { + auto *MemIntTy = + cast<llvm::IntegerType>(Addr.getType()->getPointerElementType()); + // Expand to the memory bit width + unsigned MemNumElems = MemIntTy->getPrimitiveSizeInBits(); + // <N x i1> --> <P x i1> + Value = emitBoolVecConversion(Value, MemNumElems, "insertvec"); + // <P x i1> --> iP + Value = Builder.CreateBitCast(Value, MemIntTy); + } else if (!CGM.getCodeGenOpts().PreserveVec3Type) { // Handle vec3 special. if (VecTy && cast<llvm::FixedVectorType>(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<llvm::IntegerType>(Vec->getType()); + if (IRStoreTy) { + auto *IRVecTy = llvm::FixedVectorType::get( + Builder.getInt1Ty(), IRStoreTy->getPrimitiveSizeInBits()); + Vec = Builder.CreateBitCast(Vec, IRVecTy); + // iN --> <N x i1> + } Vec = Builder.CreateInsertElement(Vec, Src.getScalarVal(), Dst.getVectorIdx(), "vecins"); + if (IRStoreTy) { + // <N x i1> --> <iN> + Vec = Builder.CreateBitCast(Vec, IRStoreTy); + } Builder.CreateStore(Vec, Dst.getVectorAddress(), Dst.isVolatileQualified()); return; Index: clang/lib/CodeGen/CGDebugInfo.cpp =================================================================== --- clang/lib/CodeGen/CGDebugInfo.cpp +++ clang/lib/CodeGen/CGDebugInfo.cpp @@ -2768,6 +2768,23 @@ llvm::DIType *CGDebugInfo::CreateType(const VectorType *Ty, llvm::DIFile *Unit) { + if (Ty->isExtVectorBoolean()) { + // Boolean ext_vector_type(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<VectorType>(), Unit); + } + llvm::DIType *ElementTy = getOrCreateType(Ty->getElementType(), Unit); int64_t Count = Ty->getNumElements(); Index: clang/lib/AST/TypePrinter.cpp =================================================================== --- clang/lib/AST/TypePrinter.cpp +++ 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->isExtVectorBoolean()) { + OS << " * sizeof("; + print(T->getElementType(), OS, StringRef()); + OS << ")"; + } + OS << "))) "; printBefore(T->getElementType(), OS); break; } Index: clang/lib/AST/ASTContext.cpp =================================================================== --- clang/lib/AST/ASTContext.cpp +++ clang/lib/AST/ASTContext.cpp @@ -1926,8 +1926,11 @@ case Type::Vector: { const auto *VT = cast<VectorType>(T); TypeInfo EltInfo = getTypeInfo(VT->getElementType()); - Width = EltInfo.Width * VT->getNumElements(); - Align = Width; + Width = VT->isExtVectorBoolean() ? VT->getNumElements() + : EltInfo.Width * VT->getNumElements(); + // enforce at least byte alignment + Align = std::max<unsigned>(8, 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. if (Align & (Align-1)) { Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ 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, Index: clang/include/clang/AST/Type.h =================================================================== --- clang/include/clang/AST/Type.h +++ clang/include/clang/AST/Type.h @@ -3256,6 +3256,10 @@ return VectorKind(VectorTypeBits.VecKind); } + bool isExtVectorBoolean() const { + return (getTypeClass() == ExtVector) && getElementType()->isBooleanType(); + } + void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getElementType(), getNumElements(), getTypeClass(), getVectorKind()); Index: clang/docs/LanguageExtensions.rst =================================================================== --- clang/docs/LanguageExtensions.rst +++ clang/docs/LanguageExtensions.rst @@ -433,6 +433,66 @@ 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 +--------------- + +Clang also supports the ext_vector_type attribute with boolean element types in +C and C++. For example: + +.. code-block:: c++ + + // legal for Clang, error for GCC: + typedef bool bool4 __attribute__((ext_vector_type(4))); + // Objects of bool8 type hold 8 bits, sizeof(bool8) == 1 + + bool4 foo(bool4 a) { + bool4 v; + v = a; + return v; + } + +Boolean vectors are a Clang extension of the ext 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 bits in the vector. The +boolean vector is dense and each bit in the boolean vector is one vector +element. + +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 +544,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 +554,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 ============
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits