simoll updated this revision to Diff 286971.
simoll edited the summary of this revision.
simoll added a comment.
- Rebased.
- Allow comparisons on boolean vectors.
- Restored result type for vector comparisons on other types.
- Added operator, alignment and constexpr tests.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D81083/new/
https://reviews.llvm.org/D81083
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/SemaCXX/constexpr-vectors.cpp
clang/test/SemaCXX/vector-bool.cpp
clang/test/SemaCXX/vector-conditional.cpp
clang/test/SemaCXX/vector.cpp
Index: clang/test/SemaCXX/vector.cpp
===================================================================
--- clang/test/SemaCXX/vector.cpp
+++ 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 <typename Elt, unsigned long long Size>
@@ -350,9 +349,7 @@
void Init() {
const TemplateVectorType<float, 32>::type Works = {};
const TemplateVectorType<int, 32>::type Works2 = {};
- // expected-error@#1 {{invalid vector element type 'bool'}}
- // expected-note@+1 {{in instantiation of template class 'Templates::TemplateVectorType<bool, 32>' requested here}}
- const TemplateVectorType<bool, 32>::type NoBool = {};
+ const TemplateVectorType<bool, 32>::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<int __attribute__((ext_vector_type(4))), 32>' requested here}}
const TemplateVectorType<vi4, 32>::type NoComplex = {};
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__((__vector_size__(2)));
FourShorts four_shorts;
TwoInts two_ints;
@@ -25,6 +26,8 @@
FourFloats four_floats;
TwoDoubles two_doubles;
FourDoubles four_doubles;
+EightBools eight_bools;
+EightBools other_eight_bools;
enum E {};
enum class SE {};
@@ -95,6 +98,9 @@
(void)(four_ints ? four_uints : 3.0f);
(void)(four_ints ? four_ints : 3.0f);
+ // Allow conditional select on bool vectors.
+ (void)(eight_bools ? eight_bools : other_eight_bools);
+
// When there is a vector and a scalar, conversions must be legal.
(void)(four_ints ? four_floats : 3); // should work, ints can convert to floats.
(void)(four_ints ? four_uints : e); // expected-error {{cannot convert between scalar type 'E' and vector type 'FourUInts'}}
@@ -163,10 +169,10 @@
void Templates() {
dependent_cond(two_ints);
dependent_operand(two_floats);
- // expected-error@159 {{vector operands to the vector conditional must be the same type ('__attribute__((__vector_size__(4 * sizeof(unsigned int)))) unsigned int' (vector of 4 'unsigned int' values) and '__attribute__((__vector_size__(4 * sizeof(double)))) double' (vector of 4 'double' values))}}}
+ // expected-error@165 {{vector operands to the vector conditional must be the same type ('__attribute__((__vector_size__(4 * sizeof(unsigned int)))) unsigned int' (vector of 4 'unsigned int' values) and '__attribute__((__vector_size__(4 * sizeof(double)))) double' (vector of 4 'double' values))}}}
all_dependent(four_ints, four_uints, four_doubles); // expected-note {{in instantiation of}}
- // expected-error@159 {{vector operands to the vector conditional must be the same type ('__attribute__((__vector_size__(4 * sizeof(unsigned int)))) unsigned int' (vector of 4 'unsigned int' values) and '__attribute__((__vector_size__(2 * sizeof(unsigned int)))) unsigned int' (vector of 2 'unsigned int' values))}}}
+ // expected-error@165 {{vector operands to the vector conditional must be the same type ('__attribute__((__vector_size__(4 * sizeof(unsigned int)))) unsigned int' (vector of 4 'unsigned int' values) and '__attribute__((__vector_size__(2 * sizeof(unsigned int)))) unsigned int' (vector of 2 'unsigned int' values))}}}
all_dependent(four_ints, four_uints, two_uints); // expected-note {{in instantiation of}}
all_dependent(four_ints, four_uints, four_uints);
}
Index: clang/test/SemaCXX/vector-bool.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/vector-bool.cpp
@@ -0,0 +1,82 @@
+// RUN: %clang_cc1 -triple x86_64-linux-pc -fsyntax-only -verify -fexceptions -fcxx-exceptions %s -std=c++17
+// Note that this test depends on the size of long-long to be different from
+// int, so it specifies a triple.
+
+using FourShorts = short __attribute__((__vector_size__(8)));
+using TwoInts = int __attribute__((__vector_size__(8)));
+using EightInts = int __attribute__((__vector_size__(32)));
+using TwoUInts = unsigned __attribute__((__vector_size__(8)));
+using FourInts = int __attribute__((__vector_size__(16)));
+using FourUInts = unsigned __attribute__((__vector_size__(16)));
+using TwoLongLong = long long __attribute__((__vector_size__(16)));
+using FourLongLong = long long __attribute__((__vector_size__(32)));
+using TwoFloats = float __attribute__((__vector_size__(8)));
+using FourFloats = float __attribute__((__vector_size__(16)));
+using TwoDoubles = double __attribute__((__vector_size__(16)));
+using FourDoubles = double __attribute__((__vector_size__(32)));
+using EightBools = bool __attribute__((__vector_size__(1)));
+
+EightInts eight_ints;
+EightBools eight_bools;
+EightBools other_eight_bools;
+bool one_bool;
+
+// Check the rules of the LHS/RHS of the conditional operator.
+void Operations() {
+ // Legal binary
+ (void)(eight_bools | other_eight_bools);
+ (void)(eight_bools & other_eight_bools);
+ (void)(eight_bools ^ other_eight_bools);
+ (void)(~eight_bools);
+ (void)(!eight_bools);
+
+ // Legal comparison
+ (void)(eight_bools == other_eight_bools);
+ (void)(eight_bools != other_eight_bools);
+ (void)(eight_bools < other_eight_bools);
+ (void)(eight_bools <= other_eight_bools);
+ (void)(eight_bools > other_eight_bools);
+ (void)(eight_bools >= other_eight_bools);
+
+ // Legal assignments
+ (void)(eight_bools |= other_eight_bools);
+ (void)(eight_bools &= other_eight_bools);
+ (void)(eight_bools ^= other_eight_bools);
+
+ // Illegal operators
+ (void)(eight_bools || other_eight_bools); // expected-error@47 {{invalid operands to binary expression ('EightBools' (vector of 8 'bool' values) and 'EightBools')}}
+ (void)(eight_bools && other_eight_bools); // expected-error@48 {{invalid operands to binary expression ('EightBools' (vector of 8 'bool' values) and 'EightBools')}}
+ (void)(eight_bools + other_eight_bools); // expected-error@49 {{invalid operands to binary expression ('EightBools' (vector of 8 'bool' values) and 'EightBools')}}
+ (void)(eight_bools - other_eight_bools); // expected-error@50 {{invalid operands to binary expression ('EightBools' (vector of 8 'bool' values) and 'EightBools')}}
+ (void)(eight_bools * other_eight_bools); // expected-error@51 {{invalid operands to binary expression ('EightBools' (vector of 8 'bool' values) and 'EightBools')}}
+ (void)(eight_bools << other_eight_bools); // expected-error@52 {{invalid operands to binary expression ('EightBools' (vector of 8 'bool' values) and 'EightBools')}}
+ (void)(eight_bools >> other_eight_bools); // expected-error@53 {{invalid operands to binary expression ('EightBools' (vector of 8 'bool' values) and 'EightBools')}}
+ (void)(eight_bools / other_eight_bools); // expected-error@54 {{invalid operands to binary expression ('EightBools' (vector of 8 'bool' values) and 'EightBools')}}
+ (void)(eight_bools % other_eight_bools); // expected-error@55 {{invalid operands to binary expression ('EightBools' (vector of 8 'bool' values) and 'EightBools')}}
+
+ // Illegal assignment
+ (void)(eight_bools += other_eight_bools); // expected-error@58 {{invalid operands to binary expression ('EightBools' (vector of 8 'bool' values) and 'EightBools')}}
+ (void)(eight_bools -= other_eight_bools); // expected-error@59 {{invalid operands to binary expression ('EightBools' (vector of 8 'bool' values) and 'EightBools')}}
+ (void)(eight_bools *= other_eight_bools); // expected-error@60 {{invalid operands to binary expression ('EightBools' (vector of 8 'bool' values) and 'EightBools')}}
+ (void)(eight_bools <<= other_eight_bools); // expected-error@61 {{invalid operands to binary expression ('EightBools' (vector of 8 'bool' values) and 'EightBools')}}
+ (void)(eight_bools >>= other_eight_bools); // expected-error@62 {{invalid operands to binary expression ('EightBools' (vector of 8 'bool' values) and 'EightBools')}}
+ (void)(eight_bools /= other_eight_bools); // expected-error@63 {{invalid operands to binary expression ('EightBools' (vector of 8 'bool' values) and 'EightBools')}}
+ (void)(eight_bools %= other_eight_bools); // expected-error@64 {{invalid operands to binary expression ('EightBools' (vector of 8 'bool' values) and 'EightBools')}}
+
+ // Illegal in/decrements
+ (void)(eight_bools++); // expected-error@67 {{cannot increment value of type 'EightBools' (vector of 8 'bool' values)}}
+ (void)(++eight_bools); // expected-error@68 {{cannot increment value of type 'EightBools' (vector of 8 'bool' values)}}
+ (void)(eight_bools--); // expected-error@69 {{cannot decrement value of type 'EightBools' (vector of 8 'bool' values)}}
+ (void)(--eight_bools); // expected-error@70 {{cannot decrement value of type 'EightBools' (vector of 8 'bool' values)}}
+
+ // No implicit promotion
+ (void)(eight_bools + eight_ints); // expected-error@73 {{cannot convert between vector type 'EightInts' (vector of 8 'int' values) and vector type 'EightBools' (vector of 8 'bool' values) as implicit conversion would cause truncation}}
+ (void)(eight_ints - eight_bools); // expected-error@74 {{cannot convert between vector type 'EightBools' (vector of 8 'bool' values) and vector type 'EightInts' (vector of 8 'int' values) as implicit conversion would cause truncation}}
+}
+
+// Check the conversion to integral type of same size
+void Conversions() {
+ (void)((char)eight_bools);
+ (void)((unsigned)eight_bools);
+ (void)((bool)eight_bools); // expected-error@80 {{C-style cast from vector 'EightBools' (vector of 8 'bool' values) to scalar 'unsigned int' 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 EightBoolsVecSize __attribute__((vector_size(1))) = bool;
+void BoolVecUsage() {
+ constexpr auto a = EightBoolsVecSize{true, false, true, false} <
+ EightBoolsVecSize{false, false, true, true};
+ constexpr auto b = EightBoolsVecSize{true, false, true, false} <=
+ EightBoolsVecSize{false, false, true, true};
+ constexpr auto c = EightBoolsVecSize{true, false, true, false} ==
+ EightBoolsVecSize{false, false, true, true};
+ constexpr auto d = EightBoolsVecSize{true, false, true, false} !=
+ EightBoolsVecSize{false, false, true, true};
+ constexpr auto e = EightBoolsVecSize{true, false, true, false} >=
+ EightBoolsVecSize{false, false, true, true};
+ constexpr auto f = EightBoolsVecSize{true, false, true, false} >
+ EightBoolsVecSize{false, false, true, true};
+}
Index: clang/test/CodeGen/vector-alignment.c
===================================================================
--- clang/test/CodeGen/vector-alignment.c
+++ clang/test/CodeGen/vector-alignment.c
@@ -22,6 +22,8 @@
// SSE: @v2 {{.*}}, align 16
// AVX: @v2 {{.*}}, align 32
// AVX512: @v2 {{.*}}, align 32
+_Bool __attribute__((vector_size(2))) v2b;
+// ALL: @v2b {{.*}}, align 2
// Alignment above target max alignment with no aligned attribute should align
// based on the target max.
@@ -33,6 +35,10 @@
// SSE: @v4 {{.*}}, align 16
// AVX: @v4 {{.*}}, align 32
// AVX512: @v4 {{.*}}, align 64
+_Bool __attribute__((vector_size(1024))) v4b;
+// SSE: @v4b {{.*}}, align 16
+// AVX: @v4b {{.*}}, align 32
+// AVX512: @v4b {{.*}}, align 64
// Aliged attribute should always override.
double __attribute__((vector_size(16), aligned(16))) v5;
@@ -43,6 +49,8 @@
// ALL: @v7 {{.*}}, align 16
double __attribute__((vector_size(32), aligned(64))) v8;
// ALL: @v8 {{.*}}, align 64
+_Bool __attribute__((vector_size(32), aligned(128))) v8b;
+// ALL: @v8b {{.*}}, align 128
// Check non-power of 2 widths.
double __attribute__((vector_size(24))) v9;
@@ -53,9 +61,15 @@
// SSE: @v10 {{.*}}, align 16
// AVX: @v10 {{.*}}, align 32
// AVX512: @v10 {{.*}}, align 64
+_Bool __attribute__((vector_size(31))) v10b;
+// SSE: @v10b {{.*}}, align 16
+// AVX: @v10b {{.*}}, align 32
+// AVX512: @v10b {{.*}}, align 32
// Check non-power of 2 widths with aligned attribute.
double __attribute__((vector_size(24), aligned(64))) v11;
// ALL: @v11 {{.*}}, align 64
double __attribute__((vector_size(80), aligned(16))) v12;
// ALL: @v12 {{.*}}, align 16
+_Bool __attribute__((vector_size(31), aligned(4))) v12b;
+// ALL: @v12b {{.*}}, align 4
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 -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"
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 __attribute__((__vector_size__(32 * sizeof(_Bool)))) _Bool bool256;
+typedef _Bool bool256 __attribute__((vector_size(32)));
Index: clang/lib/Sema/SemaType.cpp
===================================================================
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -2515,10 +2515,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();
@@ -2568,7 +2568,8 @@
return QualType();
}
- return Context.getVectorType(CurType, VectorSizeBits / TypeSize,
+ uint64_t ElemSizeBits = CurType->isBooleanType() ? 1 : TypeSize;
+ return Context.getVectorType(CurType, VectorSizeBits / ElemSizeBits,
VectorType::GenericVector);
}
@@ -7613,13 +7614,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.
Index: clang/lib/Sema/SemaExprCXX.cpp
===================================================================
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -5897,9 +5897,8 @@
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,
@@ -5944,7 +5943,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 {
@@ -6262,9 +6263,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,6 +7200,8 @@
// Vectors are simple.
if (const VectorType *vecType = type->getAs<VectorType>()) {
len = vecType->getNumElements();
+ if (vecType->isVectorSizeBoolean())
+ len = std::max<uint64_t>(1, len / 8);
eltType = vecType->getElementType();
assert(eltType->isScalarType());
return true;
@@ -8012,9 +8014,11 @@
if (LHS.get()->getType()->isVectorType() ||
RHS.get()->getType()->isVectorType()) {
QualType VecResTy = S.CheckVectorOperands(LHS, RHS, QuestionLoc,
- /*isCompAssign*/false,
- /*AllowBothBool*/true,
- /*AllowBoolConversions*/false);
+ /*isCompAssign*/ false,
+ /*AllowBothBool*/ true,
+ /*AllowBoolConversions*/ false,
+ /*AllowBooleanOperation*/ false,
+ /*ReportInvalid*/ true);
if (VecResTy.isNull()) return QualType();
// The result type must match the condition type as specified in
// OpenCL v1.1 s6.11.6.
@@ -8078,9 +8082,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);
@@ -9771,10 +9777,18 @@
return false;
}
+static bool IsScalarOrVectorBool(QualType Ty) {
+ return Ty->isBooleanType() ||
+ (Ty->isVectorType() &&
+ Ty->getAs<VectorType>()->getElementType()->isBooleanType());
+}
+
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())
@@ -9795,14 +9809,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))
@@ -10051,8 +10070,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);
@@ -10081,8 +10102,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);
}
@@ -10367,10 +10390,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;
}
@@ -10467,10 +10492,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;
}
@@ -10708,6 +10735,15 @@
const VectorType *RHSVecTy = RHSType->getAs<VectorType>();
QualType RHSEleType = RHSVecTy ? RHSVecTy->getElementType() : RHSType;
+ // Do not allow shifts for vector_size boolean vectors.
+ if ((LHSVecTy && LHSVecTy->isVectorSizeBoolean()) ||
+ (RHSVecTy && RHSVecTy->isVectorSizeBoolean())) {
+ S.Diag(Loc, diag::err_typecheck_invalid_operands)
+ << LHS.get()->getType() << RHS.get()->getType()
+ << LHS.get()->getSourceRange();
+ return QualType();
+ }
+
// The operands need to be integers.
if (!LHSEleType->isIntegerType()) {
S.Diag(Loc, diag::err_typecheck_expect_int)
@@ -11895,7 +11931,10 @@
return Context.getExtVectorType(Context.LongLongTy, VTy->getNumElements());
}
- if (TypeSize == Context.getTypeSize(Context.LongLongTy))
+ if (VTy->isVectorSizeBoolean())
+ return Context.getVectorType(Context.BoolTy, VTy->getNumElements(),
+ VectorType::GenericVector);
+ else if (TypeSize == Context.getTypeSize(Context.LongLongTy))
return Context.getVectorType(Context.LongLongTy, VTy->getNumElements(),
VectorType::GenericVector);
else if (TypeSize == Context.getTypeSize(Context.LongTy))
@@ -11927,9 +11966,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;
@@ -12076,8 +12118,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 &&
@@ -12170,6 +12214,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) {
@@ -12178,13 +12236,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,16 @@
llvm::Type *R = ConvertType(T);
+ // Check for the boolean vector case
+ auto *FixedVT = dyn_cast<llvm::FixedVectorType>(R);
+ if (T->isVectorType() && FixedVT &&
+ FixedVT->getElementType()->isIntegerTy(1)) {
+
+ // 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,8 +679,10 @@
case Type::ExtVector:
case Type::Vector: {
const VectorType *VT = cast<VectorType>(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: {
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ 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);
Index: clang/lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.cpp
+++ 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<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
@@ -2080,7 +2080,30 @@
}
}
- return Builder.CreateBitCast(Src, DstTy);
+ // SExt/Trunc 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 (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;
@@ -4638,6 +4661,14 @@
return Builder.CreateIntToPtr(Src, DstTy, Name);
}
+static bool IsGenericBoolVector(QualType Ty) {
+ const auto *ClangVecTy = dyn_cast<VectorType>(Ty);
+ if (!ClangVecTy)
+ return false;
+
+ return ClangVecTy->isVectorSizeBoolean();
+}
+
Value *ScalarExprEmitter::VisitAsTypeExpr(AsTypeExpr *E) {
Value *Src = CGF.EmitScalarExpr(E->getSrcExpr());
llvm::Type *DstTy = ConvertType(E->getType());
@@ -4648,6 +4679,11 @@
unsigned NumElementsDst = isa<llvm::VectorType>(DstTy) ?
cast<llvm::VectorType>(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) {
Index: clang/lib/CodeGen/CGExpr.cpp
===================================================================
--- clang/lib/CodeGen/CGExpr.cpp
+++ 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<llvm::VectorType>(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->isVectorSizeBoolean()) {
+ 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 *IRVecTy = cast<llvm::VectorType>(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<int>{0, 1, 2}, "extractVec");
+ return EmitFromMemory(V, Ty);
}
}
@@ -1744,6 +1762,13 @@
return Value;
}
+static bool isBooleanVector(QualType Ty) {
+ auto *VecTy = Ty->getAs<VectorType>();
+ 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 --> <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;
}
@@ -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<llvm::VectorType>(SrcTy);
+ llvm::Type *SrcTy = Value->getType();
+ const auto *ClangVecTy = Ty->getAs<VectorType>();
+ if (ClangVecTy) {
+ auto *IRVecTy = dyn_cast<llvm::FixedVectorType>(SrcTy);
+ if (ClangVecTy->isVectorSizeBoolean()) {
+ 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 && 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<int>{0, 1, 2, -1},
- "extractVec");
- SrcTy = llvm::FixedVectorType::get(VecTy->getElementType(), 4);
+ Value = Builder.CreateShuffleVector(
+ Value, llvm::UndefValue::get(IRVecTy), ArrayRef<int>{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<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
@@ -2743,6 +2743,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<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,11 +645,12 @@
printBefore(T->getElementType(), OS);
break;
case VectorType::GenericVector: {
+ auto NumVectorElems = T->getNumElements();
+ auto ElemSizeMultiple =
+ T->isVectorSizeBoolean() ? NumVectorElems / 8 : NumVectorElems;
// 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(";
+ OS << "__attribute__((__vector_size__(" << ElemSizeMultiple << " * sizeof(";
print(T->getElementType(), OS, StringRef());
OS << ")))) ";
printBefore(T->getElementType(), OS);
Index: clang/lib/AST/ASTContext.cpp
===================================================================
--- clang/lib/AST/ASTContext.cpp
+++ clang/lib/AST/ASTContext.cpp
@@ -1969,7 +1969,8 @@
case Type::Vector: {
const auto *VT = cast<VectorType>(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.
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -11333,7 +11333,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
@@ -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());
Index: clang/docs/LanguageExtensions.rst
===================================================================
--- clang/docs/LanguageExtensions.rst
+++ 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
+---------------
+
+Unlike GCC, Clang also allows the attribute to be used with boolean
+element types. For example:
+
+.. code-block:: c++
+
+ // legal for Clang, error for GCC:
+ typedef bool bool8 __attribute__((vector_size(1)));
+ // Objects of bool8 type hold 8 bits, sizeof(bool8) == 1
+
+ typedef bool bool32 __attribute__((vector_size(4)));
+ // Objects of bool32 type hold 32 bits, sizeof(bool32) == 4
+
+ bool8 foo(bool8 a) {
+ bool8 v;
+ v = a;
+ return v;
+ }
+
+Boolean vectors are a Clang extension of the GCC vector type. Boolean vectors
+are intended, though not guaranteed, to map to vector mask registers. The
+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).
+* Only the operators `!`, `~`, `|`, `&` and `^` are allowed on boolean vectors.
+
+The memory representation of a 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 +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
============
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits