summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/docs/LanguageExtensions.rst43
-rw-r--r--clang/include/clang/AST/Expr.h35
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td8
-rw-r--r--clang/include/clang/Sema/Sema.h3
-rw-r--r--clang/lib/AST/ExprConstant.cpp1
-rw-r--r--clang/lib/CodeGen/CGExprScalar.cpp15
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp162
-rw-r--r--clang/test/CodeGenCXX/vector-conditional.cpp231
-rw-r--r--clang/test/Sema/vector-gcc-compat.cpp2
-rw-r--r--clang/test/SemaCXX/vector-conditional.cpp172
10 files changed, 621 insertions, 51 deletions
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 0bd87903f34..f1df9dd93f9 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -465,28 +465,33 @@ The table below shows the support for each operation by vector extension. A
dash indicates that an operation is not accepted according to a corresponding
specification.
-============================== ======= ======= ======= =======
- Operator OpenCL AltiVec GCC NEON
-============================== ======= ======= ======= =======
-[] yes yes yes --
-unary operators +, -- yes yes yes --
-++, -- -- yes yes yes --
-+,--,*,/,% yes yes yes --
-bitwise operators &,|,^,~ yes yes yes --
->>,<< yes yes yes --
-!, &&, || yes -- -- --
-==, !=, >, <, >=, <= yes yes -- --
-= yes yes yes yes
-:? yes -- -- --
-sizeof yes yes yes yes
-C-style cast yes yes yes no
-reinterpret_cast yes no yes no
-static_cast yes no yes no
-const_cast no no no no
-============================== ======= ======= ======= =======
+============================== ======= ======= ============= =======
+ Operator OpenCL AltiVec GCC NEON
+============================== ======= ======= ============= =======
+[] yes yes yes --
+unary operators +, -- yes yes yes --
+++, -- -- yes yes yes --
++,--,*,/,% yes yes yes --
+bitwise operators &,|,^,~ yes yes yes --
+>>,<< yes yes yes --
+!, &&, || yes -- yes [#]_ --
+==, !=, >, <, >=, <= yes yes yes --
+= yes yes yes yes
+:? [#]_ yes -- yes --
+sizeof yes yes yes yes
+C-style cast yes yes yes no
+reinterpret_cast yes no yes no
+static_cast yes no yes no
+const_cast no no no no
+============================== ======= ======= ============= =======
See also :ref:`langext-__builtin_shufflevector`, :ref:`langext-__builtin_convertvector`.
+.. [#] unary operator ! is not implemented, however && and || are.
+.. [#] While OpenCL and GCC vectors both implement the comparison operator(?:) as a
+ 'select', they operate somewhat differently. OpenCL selects based on signedness of
+ the condition operands, but GCC vectors use normal bool conversions (that is, != 0).
+
Half-Precision Floating Point
=============================
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index fa9557808b4..16956c27a11 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -3736,22 +3736,25 @@ class ConditionalOperator : public AbstractConditionalOperator {
friend class ASTStmtReader;
public:
ConditionalOperator(Expr *cond, SourceLocation QLoc, Expr *lhs,
- SourceLocation CLoc, Expr *rhs,
- QualType t, ExprValueKind VK, ExprObjectKind OK)
- : AbstractConditionalOperator(ConditionalOperatorClass, t, VK, OK,
- // FIXME: the type of the conditional operator doesn't
- // depend on the type of the conditional, but the standard
- // seems to imply that it could. File a bug!
- (lhs->isTypeDependent() || rhs->isTypeDependent()),
- (cond->isValueDependent() || lhs->isValueDependent() ||
- rhs->isValueDependent()),
- (cond->isInstantiationDependent() ||
- lhs->isInstantiationDependent() ||
- rhs->isInstantiationDependent()),
- (cond->containsUnexpandedParameterPack() ||
- lhs->containsUnexpandedParameterPack() ||
- rhs->containsUnexpandedParameterPack()),
- QLoc, CLoc) {
+ SourceLocation CLoc, Expr *rhs, QualType t,
+ ExprValueKind VK, ExprObjectKind OK)
+ : AbstractConditionalOperator(
+ ConditionalOperatorClass, t, VK, OK,
+ // The type of the conditional operator depends on the type
+ // of the conditional to support the GCC vector conditional
+ // extension. Additionally, [temp.dep.expr] does specify state that
+ // this should be dependent on ALL sub expressions.
+ (cond->isTypeDependent() || lhs->isTypeDependent() ||
+ rhs->isTypeDependent()),
+ (cond->isValueDependent() || lhs->isValueDependent() ||
+ rhs->isValueDependent()),
+ (cond->isInstantiationDependent() ||
+ lhs->isInstantiationDependent() ||
+ rhs->isInstantiationDependent()),
+ (cond->containsUnexpandedParameterPack() ||
+ lhs->containsUnexpandedParameterPack() ||
+ rhs->containsUnexpandedParameterPack()),
+ QLoc, CLoc) {
SubExprs[COND] = cond;
SubExprs[LHS] = lhs;
SubExprs[RHS] = rhs;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index b56bfa24ff0..d27691d2112 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6944,6 +6944,14 @@ def err_conditional_vector_size : Error<
def err_conditional_vector_element_size : Error<
"vector condition type %0 and result type %1 do not have elements of the "
"same size">;
+def err_conditional_vector_has_void : Error<
+ "GNU vector conditional operand cannot be %select{void|a throw expression}0">;
+def err_conditional_vector_operand_type
+ : Error<"%select{enumeration|extended vector}0 type %1 is not allowed in a "
+ "vector conditional">;
+def err_conditional_vector_mismatched_vectors
+ : Error<"vector operands to the vector conditional must be the same type "
+ "%diff{($ and $)|}0,1}">;
def err_throw_incomplete : Error<
"cannot throw object of incomplete type %0">;
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index b95a5017d90..5aea6102c0e 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -10683,6 +10683,9 @@ public:
QualType CXXCheckConditionalOperands( // C++ 5.16
ExprResult &cond, ExprResult &lhs, ExprResult &rhs,
ExprValueKind &VK, ExprObjectKind &OK, SourceLocation questionLoc);
+ QualType CheckGNUVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS,
+ ExprResult &RHS,
+ SourceLocation QuestionLoc);
QualType FindCompositePointerType(SourceLocation Loc, Expr *&E1, Expr *&E2,
bool ConvertArgs = true);
QualType FindCompositePointerType(SourceLocation Loc,
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 8a074538612..c4b27b5d1da 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -9378,6 +9378,7 @@ namespace {
bool VisitUnaryImag(const UnaryOperator *E);
// FIXME: Missing: unary -, unary ~, binary add/sub/mul/div,
// binary comparisons, binary and/or/xor,
+ // conditional operator (for GNU conditional select),
// shufflevector, ExtVectorElementExpr
};
} // end anonymous namespace
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 31487accf41..3f23fe11e4f 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -4311,6 +4311,21 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
return tmp5;
}
+ if (condExpr->getType()->isVectorType()) {
+ CGF.incrementProfileCounter(E);
+
+ llvm::Value *CondV = CGF.EmitScalarExpr(condExpr);
+ llvm::Value *LHS = Visit(lhsExpr);
+ llvm::Value *RHS = Visit(rhsExpr);
+
+ llvm::Type *CondType = ConvertType(condExpr->getType());
+ auto *VecTy = cast<llvm::VectorType>(CondType);
+ llvm::Value *ZeroVec = llvm::Constant::getNullValue(VecTy);
+
+ CondV = Builder.CreateICmpNE(CondV, ZeroVec, "vector_cond");
+ return Builder.CreateSelect(CondV, LHS, RHS, "vector_select");
+ }
+
// If this is a really simple expression (like x ? 4 : 5), emit this as a
// select instead of as control flow. We can only do this if it is cheap and
// safe to evaluate the LHS and RHS unconditionally.
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index e9d075c4c40..a73e6906fce 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -5747,38 +5747,157 @@ static bool ConvertForConditional(Sema &Self, ExprResult &E, QualType T) {
return false;
}
+// Check the condition operand of ?: to see if it is valid for the GCC
+// extension.
+static bool isValidVectorForConditionalCondition(ASTContext &Ctx,
+ QualType CondTy) {
+ if (!CondTy->isVectorType() || CondTy->isExtVectorType())
+ 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);
+}
+
+QualType Sema::CheckGNUVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS,
+ ExprResult &RHS,
+ SourceLocation QuestionLoc) {
+ LHS = DefaultFunctionArrayLvalueConversion(LHS.get());
+ RHS = DefaultFunctionArrayLvalueConversion(RHS.get());
+
+ QualType CondType = Cond.get()->getType();
+ const auto *CondVT = CondType->getAs<VectorType>();
+ QualType CondElementTy = CondVT->getElementType();
+ unsigned CondElementCount = CondVT->getNumElements();
+ QualType LHSType = LHS.get()->getType();
+ const auto *LHSVT = LHSType->getAs<VectorType>();
+ QualType RHSType = RHS.get()->getType();
+ const auto *RHSVT = RHSType->getAs<VectorType>();
+
+ QualType ResultType;
+
+ // FIXME: In the future we should define what the Extvector conditional
+ // operator looks like.
+ if (LHSVT && isa<ExtVectorType>(LHSVT)) {
+ Diag(QuestionLoc, diag::err_conditional_vector_operand_type)
+ << /*isExtVector*/ true << LHSType;
+ return {};
+ }
+
+ if (RHSVT && isa<ExtVectorType>(RHSVT)) {
+ Diag(QuestionLoc, diag::err_conditional_vector_operand_type)
+ << /*isExtVector*/ true << RHSType;
+ return {};
+ }
+
+ if (LHSVT && RHSVT) {
+ // If both are vector types, they must be the same type.
+ if (!Context.hasSameType(LHSType, RHSType)) {
+ Diag(QuestionLoc, diag::err_conditional_vector_mismatched_vectors)
+ << LHSType << RHSType;
+ return {};
+ }
+ ResultType = LHSType;
+ } else if (LHSVT || RHSVT) {
+ ResultType = CheckVectorOperands(
+ LHS, RHS, QuestionLoc, /*isCompAssign*/ false, /*AllowBothBool*/ true,
+ /*AllowBoolConversions*/ false);
+ if (ResultType.isNull())
+ return {};
+ } else {
+ // Both are scalar.
+ QualType ResultElementTy;
+ LHSType = LHSType.getCanonicalType().getUnqualifiedType();
+ RHSType = RHSType.getCanonicalType().getUnqualifiedType();
+
+ if (Context.hasSameType(LHSType, RHSType))
+ ResultElementTy = LHSType;
+ else
+ ResultElementTy =
+ UsualArithmeticConversions(LHS, RHS, QuestionLoc, ACK_Conditional);
+
+ if (ResultElementTy->isEnumeralType()) {
+ Diag(QuestionLoc, diag::err_conditional_vector_operand_type)
+ << /*isExtVector*/ false << ResultElementTy;
+ return {};
+ }
+ ResultType = Context.getVectorType(
+ ResultElementTy, CondType->getAs<VectorType>()->getNumElements(),
+ VectorType::GenericVector);
+
+ LHS = ImpCastExprToType(LHS.get(), ResultType, CK_VectorSplat);
+ RHS = ImpCastExprToType(RHS.get(), ResultType, CK_VectorSplat);
+ }
+
+ assert(!ResultType.isNull() && ResultType->isVectorType() &&
+ "Result should have been a vector type");
+ QualType ResultElementTy = ResultType->getAs<VectorType>()->getElementType();
+ unsigned ResultElementCount =
+ ResultType->getAs<VectorType>()->getNumElements();
+
+ if (ResultElementCount != CondElementCount) {
+ Diag(QuestionLoc, diag::err_conditional_vector_size) << CondType
+ << ResultType;
+ return {};
+ }
+
+ if (Context.getTypeSize(ResultElementTy) !=
+ Context.getTypeSize(CondElementTy)) {
+ Diag(QuestionLoc, diag::err_conditional_vector_element_size) << CondType
+ << ResultType;
+ return {};
+ }
+
+ return ResultType;
+}
+
/// Check the operands of ?: under C++ semantics.
///
/// See C++ [expr.cond]. Note that LHS is never null, even for the GNU x ?: y
/// extension. In this case, LHS == Cond. (But they're not aliases.)
+///
+/// This function also implements GCC's vector extension for conditionals.
+/// GCC's vector extension permits the use of a?b:c where the type of
+/// a is that of a integer vector with the same number of elements and
+/// size as the vectors of b and c. If one of either b or c is a scalar
+/// it is implicitly converted to match the type of the vector.
+/// Otherwise the expression is ill-formed. If both b and c are scalars,
+/// then b and c are checked and converted to the type of a if possible.
+/// Unlike the OpenCL ?: operator, the expression is evaluated as
+/// (a[0] != 0 ? b[0] : c[0], .. , a[n] != 0 ? b[n] : c[n]).
QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
ExprResult &RHS, ExprValueKind &VK,
ExprObjectKind &OK,
SourceLocation QuestionLoc) {
- // FIXME: Handle C99's complex types, vector types, block pointers and Obj-C++
- // interface pointers.
+ // FIXME: Handle C99's complex types, block pointers and Obj-C++ interface
+ // pointers.
+
+ // Assume r-value.
+ VK = VK_RValue;
+ OK = OK_Ordinary;
+ bool IsVectorConditional =
+ isValidVectorForConditionalCondition(Context, Cond.get()->getType());
// C++11 [expr.cond]p1
// The first expression is contextually converted to bool.
- //
- // FIXME; GCC's vector extension permits the use of a?b:c where the type of
- // a is that of a integer vector with the same number of elements and
- // size as the vectors of b and c. If one of either b or c is a scalar
- // it is implicitly converted to match the type of the vector.
- // Otherwise the expression is ill-formed. If both b and c are scalars,
- // then b and c are checked and converted to the type of a if possible.
- // Unlike the OpenCL ?: operator, the expression is evaluated as
- // (a[0] != 0 ? b[0] : c[0], .. , a[n] != 0 ? b[n] : c[n]).
if (!Cond.get()->isTypeDependent()) {
- ExprResult CondRes = CheckCXXBooleanCondition(Cond.get());
+ ExprResult CondRes = IsVectorConditional
+ ? DefaultFunctionArrayLvalueConversion(Cond.get())
+ : CheckCXXBooleanCondition(Cond.get());
if (CondRes.isInvalid())
return QualType();
Cond = CondRes;
+ } else {
+ // To implement C++, the first expression typically doesn't alter the result
+ // type of the conditional, however the GCC compatible vector extension
+ // changes the result type to be that of the conditional. Since we cannot
+ // know if this is a vector extension here, delay the conversion of the
+ // LHS/RHS below until later.
+ return Context.DependentTy;
}
- // Assume r-value.
- VK = VK_RValue;
- OK = OK_Ordinary;
// Either of the arguments dependent?
if (LHS.get()->isTypeDependent() || RHS.get()->isTypeDependent())
@@ -5797,6 +5916,17 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// and value category of the other.
bool LThrow = isa<CXXThrowExpr>(LHS.get()->IgnoreParenImpCasts());
bool RThrow = isa<CXXThrowExpr>(RHS.get()->IgnoreParenImpCasts());
+
+ // Void expressions aren't legal in the vector-conditional expressions.
+ if (IsVectorConditional) {
+ SourceRange DiagLoc =
+ LVoid ? LHS.get()->getSourceRange() : RHS.get()->getSourceRange();
+ bool IsThrow = LVoid ? LThrow : RThrow;
+ Diag(DiagLoc.getBegin(), diag::err_conditional_vector_has_void)
+ << DiagLoc << IsThrow;
+ return QualType();
+ }
+
if (LThrow != RThrow) {
Expr *NonThrow = LThrow ? RHS.get() : LHS.get();
VK = NonThrow->getValueKind();
@@ -5819,6 +5949,8 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
}
// Neither is void.
+ if (IsVectorConditional)
+ return CheckGNUVectorConditionalTypes(Cond, LHS, RHS, QuestionLoc);
// C++11 [expr.cond]p3
// Otherwise, if the second and third operand have different types, and
diff --git a/clang/test/CodeGenCXX/vector-conditional.cpp b/clang/test/CodeGenCXX/vector-conditional.cpp
new file mode 100644
index 00000000000..117f93859a7
--- /dev/null
+++ b/clang/test/CodeGenCXX/vector-conditional.cpp
@@ -0,0 +1,231 @@
+// RUN: %clang_cc1 %s -triple x86_64-linux-gnu -Wno-unused -std=c++11 -emit-llvm -o - | FileCheck %s
+
+using FourShorts = short __attribute__((__vector_size__(8)));
+using TwoInts = int __attribute__((__vector_size__(8)));
+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)));
+
+FourShorts four_shorts;
+TwoInts two_ints;
+TwoUInts two_uints;
+FourInts four_ints;
+FourUInts four_uints;
+TwoLongLong two_ll;
+FourLongLong four_ll;
+TwoFloats two_floats;
+FourFloats four_floats;
+TwoDoubles two_doubles;
+FourDoubles four_doubles;
+
+short some_short;
+unsigned short some_ushort;
+int some_int;
+float some_float;
+unsigned int some_uint;
+long long some_ll;
+unsigned long long some_ull;
+double some_double;
+
+// CHECK: TwoVectorOps
+void TwoVectorOps() {
+ two_ints ? two_ints : two_ints;
+ // CHECK: %[[COND:.+]] = load <2 x i32>
+ // CHECK: %[[LHS:.+]] = load <2 x i32>
+ // CHECK: %[[RHS:.+]] = load <2 x i32>
+ // CHECK: %[[NEZERO:.+]] = icmp ne <2 x i32> %[[COND]], zeroinitializer
+ // CHECK: %[[SELECT:.+]] = select <2 x i1> %[[NEZERO]], <2 x i32> %[[LHS]], <2 x i32> %[[RHS]]
+
+ two_ints ? two_floats : two_floats;
+ // CHECK: %[[COND:.+]] = load <2 x i32>
+ // CHECK: %[[LHS:.+]] = load <2 x float>
+ // CHECK: %[[RHS:.+]] = load <2 x float>
+ // CHECK: %[[NEZERO:.+]] = icmp ne <2 x i32> %[[COND]], zeroinitializer
+ // CHECK: %[[SELECT:.+]] = select <2 x i1> %[[NEZERO]], <2 x float> %[[LHS]], <2 x float> %[[RHS]]
+
+ two_ll ? two_doubles : two_doubles;
+ // CHECK: %[[COND:.+]] = load <2 x i64>
+ // CHECK: %[[LHS:.+]] = load <2 x double>
+ // CHECK: %[[RHS:.+]] = load <2 x double>
+ // CHECK: %[[NEZERO:.+]] = icmp ne <2 x i64> %[[COND]], zeroinitializer
+ // CHECK: %[[SELECT:.+]] = select <2 x i1> %[[NEZERO]], <2 x double> %[[LHS]], <2 x double> %[[RHS]]
+}
+
+// CHECK: TwoScalarOps
+void TwoScalarOps() {
+ four_shorts ? some_short : some_short;
+ // CHECK: %[[COND:.+]] = load <4 x i16>
+ // CHECK: %[[LHS:.+]] = load i16
+ // CHECK: %[[LHS_SPLAT_INSERT:.+]] = insertelement <4 x i16> undef, i16 %[[LHS]], i32 0
+ // CHECK: %[[LHS_SPLAT:.+]] = shufflevector <4 x i16> %[[LHS_SPLAT_INSERT]], <4 x i16> undef, <4 x i32> zeroinitializer
+ // CHECK: %[[RHS:.+]] = load i16
+ // CHECK: %[[RHS_SPLAT_INSERT:.+]] = insertelement <4 x i16> undef, i16 %[[RHS]], i32 0
+ // CHECK: %[[RHS_SPLAT:.+]] = shufflevector <4 x i16> %[[RHS_SPLAT_INSERT]], <4 x i16> undef, <4 x i32> zeroinitializer
+ // CHECK: %[[NEZERO:.+]] = icmp ne <4 x i16> %[[COND]], zeroinitializer
+ // CHECK: %[[SELECT:.+]] = select <4 x i1> %[[NEZERO]], <4 x i16> %[[LHS_SPLAT]], <4 x i16> %[[RHS_SPLAT]]
+
+ four_shorts ? some_ushort : some_ushort;
+ // CHECK: %[[COND:.+]] = load <4 x i16>
+ // CHECK: %[[LHS:.+]] = load i16
+ // CHECK: %[[LHS_SPLAT_INSERT:.+]] = insertelement <4 x i16> undef, i16 %[[LHS]], i32 0
+ // CHECK: %[[LHS_SPLAT:.+]] = shufflevector <4 x i16> %[[LHS_SPLAT_INSERT]], <4 x i16> undef, <4 x i32> zeroinitializer
+ // CHECK: %[[RHS:.+]] = load i16
+ // CHECK: %[[RHS_SPLAT_INSERT:.+]] = insertelement <4 x i16> undef, i16 %[[RHS]], i32 0
+ // CHECK: %[[RHS_SPLAT:.+]] = shufflevector <4 x i16> %[[RHS_SPLAT_INSERT]], <4 x i16> undef, <4 x i32> zeroinitializer
+ // CHECK: %[[NEZERO:.+]] = icmp ne <4 x i16> %[[COND]], zeroinitializer
+ // CHECK: %[[SELECT:.+]] = select <4 x i1> %[[NEZERO]], <4 x i16> %[[LHS_SPLAT]], <4 x i16> %[[RHS_SPLAT]]
+
+ four_ints ? some_ushort : some_short;
+ // CHECK: %[[COND:.+]] = load <4 x i32>
+ // CHECK: %[[LHS:.+]] = load i16
+ // CHECK: %[[LHS_ZEXT:.+]] = zext i16 %[[LHS]] to i32
+ // CHECK: %[[LHS_SPLAT_INSERT:.+]] = insertelement <4 x i32> undef, i32 %[[LHS_ZEXT]], i32 0
+ // CHECK: %[[LHS_SPLAT:.+]] = shufflevector <4 x i32> %[[LHS_SPLAT_INSERT]], <4 x i32> undef, <4 x i32> zeroinitializer
+ // CHECK: %[[RHS:.+]] = load i16
+ // CHECK: %[[RHS_SEXT:.+]] = sext i16 %[[RHS]] to i32
+ // CHECK: %[[RHS_SPLAT_INSERT:.+]] = insertelement <4 x i32> undef, i32 %[[RHS_SEXT]], i32 0
+ // CHECK: %[[RHS_SPLAT:.+]] = shufflevector <4 x i32> %[[RHS_SPLAT_INSERT]], <4 x i32> undef, <4 x i32> zeroinitializer
+ // CHECK: %[[NEZERO:.+]] = icmp ne <4 x i32> %[[COND]], zeroinitializer
+ // CHECK: %[[SELECT:.+]] = select <4 x i1> %[[NEZERO]], <4 x i32> %[[LHS_SPLAT]], <4 x i32> %[[RHS_SPLAT]]
+
+ four_ints ? some_int : some_float;
+ // CHECK: %[[COND:.+]] = load <4 x i32>
+ // CHECK: %[[LHS:.+]] = load i32
+ // CHECK: %[[LHS_CONV:.+]] = sitofp i32 %[[LHS]] to float
+ // CHECK: %[[LHS_SPLAT_INSERT:.+]] = insertelement <4 x float> undef, float %[[LHS_CONV]], i32 0
+ // CHECK: %[[LHS_SPLAT:.+]] = shufflevector <4 x float> %[[LHS_SPLAT_INSERT]], <4 x float> undef, <4 x i32> zeroinitializer
+ // CHECK: %[[RHS:.+]] = load float
+ // CHECK: %[[RHS_SPLAT_INSERT:.+]] = insertelement <4 x float> undef, float %[[RHS]], i32 0
+ // CHECK: %[[RHS_SPLAT:.+]] = shufflevector <4 x float> %[[RHS_SPLAT_INSERT]], <4 x float> undef, <4 x i32> zeroinitializer
+ // CHECK: %[[NEZERO:.+]] = icmp ne <4 x i32> %[[COND]], zeroinitializer
+ // CHECK: %[[SELECT:.+]] = select <4 x i1> %[[NEZERO]], <4 x float> %[[LHS_SPLAT]], <4 x float> %[[RHS_SPLAT]]
+
+ four_ll ? some_double : some_ll;
+ // CHECK: %[[COND:.+]] = load <4 x i64>
+ // CHECK: %[[LHS:.+]] = load double
+ // CHECK: %[[LHS_SPLAT_INSERT:.+]] = insertelement <4 x double> undef, double %[[LHS]], i32 0
+ // CHECK: %[[LHS_SPLAT:.+]] = shufflevector <4 x double> %[[LHS_SPLAT_INSERT]], <4 x double> undef, <4 x i32> zeroinitializer
+ // CHECK: %[[RHS:.+]] = load i64
+ // CHECK: %[[RHS_CONV:.+]] = sitofp i64 %[[RHS]] to double
+ // CHECK: %[[RHS_SPLAT_INSERT:.+]] = insertelement <4 x double> undef, double %[[RHS_CONV]], i32 0
+ // CHECK: %[[RHS_SPLAT:.+]] = shufflevector <4 x double> %[[RHS_SPLAT_INSERT]], <4 x double> undef, <4 x i32> zeroinitializer
+ // CHECK: %[[NEZERO:.+]] = icmp ne <4 x i64> %[[COND]], zeroinitializer
+ // CHECK: %[[SELECT:.+]] = select <4 x i1> %[[NEZERO]], <4 x double> %[[LHS_SPLAT]], <4 x double> %[[RHS_SPLAT]]
+
+ four_ints ? some_int : some_short;
+ // CHECK: %[[COND:.+]] = load <4 x i32>
+ // CHECK: %[[LHS:.+]] = load i32
+ // CHECK: %[[LHS_SPLAT_INSERT:.+]] = insertelement <4 x i32> undef, i32 %[[LHS]], i32 0
+ // CHECK: %[[LHS_SPLAT:.+]] = shufflevector <4 x i32> %[[LHS_SPLAT_INSERT]], <4 x i32> undef, <4 x i32> zeroinitializer
+ // CHECK: %[[RHS:.+]] = load i16
+ // CHECK: %[[RHS_SEXT:.+]] = sext i16 %[[RHS]] to i32
+ // CHECK: %[[RHS_SPLAT_INSERT:.+]] = insertelement <4 x i32> undef, i32 %[[RHS_SEXT]], i32 0
+ // CHECK: %[[RHS_SPLAT:.+]] = shufflevector <4 x i32> %[[RHS_SPLAT_INSERT]], <4 x i32> undef, <4 x i32> zeroinitializer
+ // CHECK: %[[NEZERO:.+]] = icmp ne <4 x i32> %[[COND]], zeroinitializer
+ // CHECK: %[[SELECT:.+]] = select <4 x i1> %[[NEZERO]], <4 x i32> %[[LHS_SPLAT]], <4 x i32> %[[RHS_SPLAT]]
+}
+
+// CHECK: OneScalarOp
+void OneScalarOp() {
+ four_ints ? four_ints : some_int;
+ // CHECK: %[[COND:.+]] = load <4 x i32>
+ // CHECK: %[[LHS:.+]] = load <4 x i32>
+ // CHECK: %[[RHS:.+]] = load i32
+ // CHECK: %[[RHS_SPLAT_INSERT:.+]] = insertelement <4 x i32> undef, i32 %[[RHS]], i32 0
+ // CHECK: %[[RHS_SPLAT:.+]] = shufflevector <4 x i32> %[[RHS_SPLAT_INSERT]], <4 x i32> undef, <4 x i32> zeroinitializer
+ // CHECK: %[[NEZERO:.+]] = icmp ne <4 x i32> %[[COND]], zeroinitializer
+ // CHECK: %[[SELECT:.+]] = select <4 x i1> %[[NEZERO]], <4 x i32> %[[LHS]], <4 x i32> %[[RHS_SPLAT]]
+
+ four_ints ? four_ints : 5;
+ // CHECK: %[[COND:.+]] = load <4 x i32>
+ // CHECK: %[[LHS:.+]] = load <4 x i32>
+ // CHECK: %[[NEZERO:.+]] = icmp ne <4 x i32> %[[COND]], zeroinitializer
+ // CHECK: %[[SELECT:.+]] = select <4 x i1> %[[NEZERO]], <4 x i32> %[[LHS]], <4 x i32> <i32 5, i32 5, i32 5, i32 5>
+
+ four_ints ?: some_float;
+ // CHECK: %[[COND:.+]] = load <4 x i32>
+ // CHECK: %[[RHS:.+]] = load float
+ // CHECK: %[[RHS_CONV:.+]] = fptosi float %[[RHS]] to i32
+ // CHECK: %[[RHS_SPLAT_INSERT:.+]] = insertelement <4 x i32> undef, i32 %[[RHS_CONV]], i32 0
+ // CHECK: %[[RHS_SPLAT:.+]] = shufflevector <4 x i32> %[[RHS_SPLAT_INSERT]], <4 x i32> undef, <4 x i32> zeroinitializer
+ // CHECK: %[[NEZERO:.+]] = icmp ne <4 x i32> %[[COND]], zeroinitializer
+ // CHECK: %[[SELECT:.+]] = select <4 x i1> %[[NEZERO]], <4 x i32> %[[COND]], <4 x i32> %[[RHS_SPLAT]]
+
+ four_ints ? four_ints : 5.0f;
+ // CHECK: %[[COND:.+]] = load <4 x i32>
+ // CHECK: %[[LHS:.+]] = load <4 x i32>
+ // CHECK: %[[NEZERO:.+]] = icmp ne <4 x i32> %[[COND]], zeroinitializer
+ // CHECK: %[[SELECT:.+]] = select <4 x i1> %[[NEZERO]], <4 x i32> %[[LHS]], <4 x i32> <i32 5, i32 5, i32 5, i32 5>
+
+ four_ints ? some_float : four_ints;
+ // CHECK: %[[COND:.+]] = load <4 x i32>
+ // CHECK: %[[LHS:.+]] = load float
+ // CHECK: %[[LHS_CONV:.+]] = fptosi float %[[LHS]] to i32
+ // CHECK: %[[LHS_SPLAT_INSERT:.+]] = insertelement <4 x i32> undef, i32 %[[LHS_CONV]], i32 0
+ // CHECK: %[[LHS_SPLAT:.+]] = shufflevector <4 x i32> %[[LHS_SPLAT_INSERT]], <4 x i32> undef, <4 x i32> zeroinitializer
+ // CHECK: %[[RHS:.+]] = load <4 x i32>
+ // CHECK: %[[NEZERO:.+]] = icmp ne <4 x i32> %[[COND]], zeroinitializer
+ // CHECK: %[[SELECT:.+]] = select <4 x i1> %[[NEZERO]], <4 x i32> %[[LHS_SPLAT]], <4 x i32> %[[RHS]]
+
+ four_ints ? four_floats : some_float;
+ // CHECK: %[[COND:.+]] = load <4 x i32>
+ // CHECK: %[[LHS:.+]] = load <4 x float>
+ // CHECK: %[[RHS:.+]] = load float
+ // CHECK: %[[RHS_SPLAT_INSERT:.+]] = insertelement <4 x float> undef, float %[[RHS]], i32 0
+ // CHECK: %[[RHS_SPLAT:.+]] = shufflevector <4 x float> %[[RHS_SPLAT_INSERT]], <4 x float> undef, <4 x i32> zeroinitializer
+ // CHECK: %[[NEZERO:.+]] = icmp ne <4 x i32> %[[COND]], zeroinitializer
+ // CHECK: %[[SELECT:.+]] = select <4 x i1> %[[NEZERO]], <4 x float> %[[LHS]], <4 x float> %[[RHS_SPLAT]]
+
+ four_ll ? four_doubles : 6.0;
+ // CHECK: %[[COND:.+]] = load <4 x i64>
+ // CHECK: %[[LHS:.+]] = load <4 x double>
+ // CHECK: %[[NEZERO:.+]] = icmp ne <4 x i64> %[[COND]], zeroinitializer
+ // CHECK: %[[SELECT:.+]] = select <4 x i1> %[[NEZERO]], <4 x double> %[[LHS]], <4 x double> <double 6.{{.+}}, double 6.{{.+}}, double 6.{{.+}}>
+
+ four_ll ? four_ll : 6.0;
+ // CHECK: %[[COND:.+]] = load <4 x i64>
+ // CHECK: %[[LHS:.+]] = load <4 x i64>
+ // CHECK: %[[NEZERO:.+]] = icmp ne <4 x i64> %[[COND]], zeroinitializer
+ // CHECK: %[[SELECT:.+]] = select <4 x i1> %[[NEZERO]], <4 x i64> %[[LHS]], <4 x i64> <i64 6, i64 6, i64 6, i64 6>
+
+ four_ll ? four_ll : 6;
+ // CHECK: %[[COND:.+]] = load <4 x i64>
+ // CHECK: %[[LHS:.+]] = load <4 x i64>
+ // CHECK: %[[NEZERO:.+]] = icmp ne <4 x i64> %[[COND]], zeroinitializer
+ // CHECK: %[[SELECT:.+]] = select <4 x i1> %[[NEZERO]], <4 x i64> %[[LHS]], <4 x i64> <i64 6, i64 6, i64 6, i64 6>
+
+ four_ll ? four_ll : some_int;
+ // CHECK: %[[COND:.+]] = load <4 x i64>
+ // CHECK: %[[LHS:.+]] = load <4 x i64>
+ // CHECK: %[[RHS:.+]] = load i32
+ // CHECK: %[[RHS_CONV:.+]] = sext i32 %[[RHS]] to i64
+ // CHECK: %[[RHS_SPLAT_INSERT:.+]] = insertelement <4 x i64> undef, i64 %[[RHS_CONV]], i32 0
+ // CHECK: %[[RHS_SPLAT:.+]] = shufflevector <4 x i64> %[[RHS_SPLAT_INSERT]], <4 x i64> undef, <4 x i32> zeroinitializer
+ // CHECK: %[[NEZERO:.+]] = icmp ne <4 x i64> %[[COND]], zeroinitializer
+ // CHECK: %[[SELECT:.+]] = select <4 x i1> %[[NEZERO]], <4 x i64> %[[LHS]], <4 x i64> %[[RHS_SPLAT]]
+
+ four_ll ? four_ll : some_ll;
+ // CHECK: %[[COND:.+]] = load <4 x i64>
+ // CHECK: %[[LHS:.+]] = load <4 x i64>
+ // CHECK: %[[RHS:.+]] = load i64
+ // CHECK: %[[RHS_SPLAT_INSERT:.+]] = insertelement <4 x i64> undef, i64 %[[RHS]], i32 0
+ // CHECK: %[[RHS_SPLAT:.+]] = shufflevector <4 x i64> %[[RHS_SPLAT_INSERT]], <4 x i64> undef, <4 x i32> zeroinitializer
+ // CHECK: %[[NEZERO:.+]] = icmp ne <4 x i64> %[[COND]], zeroinitializer
+ // CHECK: %[[SELECT:.+]] = select <4 x i1> %[[NEZERO]], <4 x i64> %[[LHS]], <4 x i64> %[[RHS_SPLAT]]
+
+ four_ll ? four_ll : some_double;
+ // CHECK: %[[COND:.+]] = load <4 x i64>
+ // CHECK: %[[LHS:.+]] = load <4 x i64>
+ // CHECK: %[[RHS:.+]] = load double
+ // CHECK: %[[RHS_CONV:.+]] = fptosi double %[[RHS]] to i64
+ // CHECK: %[[RHS_SPLAT_INSERT:.+]] = insertelement <4 x i64> undef, i64 %[[RHS_CONV]], i32 0
+ // CHECK: %[[RHS_SPLAT:.+]] = shufflevector <4 x i64> %[[RHS_SPLAT_INSERT]], <4 x i64> undef, <4 x i32> zeroinitializer
+ // CHECK: %[[NEZERO:.+]] = icmp ne <4 x i64> %[[COND]], zeroinitializer
+ // CHECK: %[[SELECT:.+]] = select <4 x i1> %[[NEZERO]], <4 x i64> %[[LHS]], <4 x i64> %[[RHS_SPLAT]]
+}
diff --git a/clang/test/Sema/vector-gcc-compat.cpp b/clang/test/Sema/vector-gcc-compat.cpp
index 71497d95eb6..41d50c168c9 100644
--- a/clang/test/Sema/vector-gcc-compat.cpp
+++ b/clang/test/Sema/vector-gcc-compat.cpp
@@ -86,7 +86,7 @@ void logicTest(void) {
v2i64_r = !v2i64_a; // expected-error {{invalid argument type 'v2i64' (vector of 2 'long long' values) to unary expression}}
v2i64_r = ~v2i64_a;
- v2i64_r = v2i64_a ? v2i64_b : v2i64_c; // expected-error {{value of type 'v2i64' (vector of 2 'long long' values) is not contextually convertible to 'bool'}}
+ v2i64_r = v2i64_a ? v2i64_b : v2i64_c;
v2i64_r = v2i64_a & 1;
v2i64_r = v2i64_a | 1;
diff --git a/clang/test/SemaCXX/vector-conditional.cpp b/clang/test/SemaCXX/vector-conditional.cpp
new file mode 100644
index 00000000000..5676d7a3880
--- /dev/null
+++ b/clang/test/SemaCXX/vector-conditional.cpp
@@ -0,0 +1,172 @@
+// 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 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)));
+
+FourShorts four_shorts;
+TwoInts two_ints;
+TwoUInts two_uints;
+FourInts four_ints;
+FourUInts four_uints;
+TwoLongLong two_ll;
+FourLongLong four_ll;
+TwoFloats two_floats;
+FourFloats four_floats;
+TwoDoubles two_doubles;
+FourDoubles four_doubles;
+
+enum E {};
+enum class SE {};
+E e;
+SE se;
+
+// Check the rules of the condition of the conditional operator.
+void Condition() {
+ // Only int types are allowed here, the rest should fail to convert to bool.
+ (void)(four_floats ? 1 : 1); // expected-error {{is not contextually convertible to 'bool'}}}
+ (void)(two_doubles ? 1 : 1); // expected-error {{is not contextually convertible to 'bool'}}}
+}
+
+// Check the rules of the LHS/RHS of the conditional operator.
+void Operands() {
+ (void)(four_ints ? four_ints : throw 1); // expected-error {{GNU vector conditional operand cannot be a throw expression}}
+ (void)(four_ints ? throw 1 : four_ints); // expected-error {{GNU vector conditional operand cannot be a throw expression}}
+ (void)(four_ints ?: throw 1); // expected-error {{GNU vector conditional operand cannot be a throw expression}}
+ (void)(four_ints ? (void)1 : four_ints); // expected-error {{GNU vector conditional operand cannot be void}}
+ (void)(four_ints ?: (void)1); // expected-error {{GNU vector conditional operand cannot be void}}
+
+ // Vector types must be the same element size as the condition.
+ (void)(four_ints ? two_ll : two_ll); // expected-error {{vector condition type 'FourInts' (vector of 4 'int' values) and result type 'TwoLongLong' (vector of 2 'long long' values) do not have the same number of elements}}
+ (void)(four_ints ? four_ll : four_ll); // expected-error {{vector condition type 'FourInts' (vector of 4 'int' values) and result type 'FourLongLong' (vector of 4 'long long' values) do not have elements of the same size}}
+ (void)(four_ints ? two_doubles : two_doubles); // expected-error {{vector condition type 'FourInts' (vector of 4 'int' values) and result type 'TwoDoubles' (vector of 2 'double' values) do not have the same number of elements}}
+ (void)(four_ints ? four_doubles : four_doubles); // expected-error {{vector condition type 'FourInts' (vector of 4 'int' values) and result type 'FourDoubles' (vector of 4 'double' values) do not have elements of the same size}}
+ (void)(four_ints ?: two_ints); // expected-error {{vector operands to the vector conditional must be the same type ('FourInts' (vector of 4 'int' values) and 'TwoInts' (vector of 2 'int' values)}}
+ (void)(four_ints ?: four_doubles); // expected-error {{vector operands to the vector conditional must be the same type ('FourInts' (vector of 4 'int' values) and 'FourDoubles' (vector of 4 'double' values)}}
+
+ // Scalars are promoted, but must be the same element size.
+ (void)(four_ints ? 3.0f : 3.0); // expected-error {{vector condition type 'FourInts' (vector of 4 'int' values) and result type '__attribute__((__vector_size__(4 * sizeof(double)))) double' (vector of 4 'double' values) do not have elements of the same size}}
+ (void)(four_ints ? 5ll : 5); // expected-error {{vector condition type 'FourInts' (vector of 4 'int' values) and result type '__attribute__((__vector_size__(4 * sizeof(long long)))) long long' (vector of 4 'long long' values) do not have elements of the same size}}
+ (void)(four_ints ?: 3.0); // expected-error {{cannot convert between scalar type 'double' and vector type 'FourInts' (vector of 4 'int' values) as implicit conversion would cause truncation}}
+ (void)(four_ints ?: 5ll); // We allow this despite GCc not allowing this since we support integral->vector-integral conversions despite integer rank.
+
+ // This one would be allowed in GCC, but we don't allow vectors of enum. Also,
+ // the error message isn't perfect, since it is only going to be a problem
+ // when both sides are an enum, otherwise it'll be promoted to whatever type
+ // the other side causes.
+ (void)(four_ints ? e : e); // expected-error {{enumeration type 'E' is not allowed in a vector conditional}}
+ (void)(four_ints ? se : se); // expected-error {{enumeration type 'SE' is not allowed in a vector conditional}}
+ (void)(four_shorts ? (short)5 : (unsigned short)5); // expected-error {{vector condition type 'FourShorts' (vector of 4 'short' values) and result type '__attribute__((__vector_size__(4 * sizeof(int)))) int' (vector of 4 'int' values) do not have elements of the same size}}
+
+ // They must also be convertible.
+ (void)(four_ints ? 3.0f : 5u);
+ (void)(four_ints ? 3.0f : 5);
+ unsigned us = 5u;
+ int sint = 5;
+ short shrt = 5;
+ unsigned short uss = 5u;
+ // The following 2 error in GCC for truncation errors, but it seems
+ // unimportant and inconsistent to enforce that rule.
+ (void)(four_ints ? 3.0f : us);
+ (void)(four_ints ? 3.0f : sint);
+
+ // Test promotion:
+ (void)(four_shorts ? uss : shrt); // expected-error {{vector condition type 'FourShorts' (vector of 4 'short' values) and result type '__attribute__((__vector_size__(4 * sizeof(int)))) int' (vector of 4 'int' values) do not have elements of the same size}}
+ (void)(four_shorts ? shrt : shrt); // should be fine.
+ (void)(four_ints ? uss : shrt); // should be fine, since they get promoted to int.
+ (void)(four_ints ? shrt : shrt); //expected-error {{vector condition type 'FourInts' (vector of 4 'int' values) and result type '__attribute__((__vector_size__(4 * sizeof(short)))) short' (vector of 4 'short' values) do not have elements of the same size}}
+
+ // Vectors must be the same type as eachother.
+ (void)(four_ints ? four_uints : four_floats); // expected-error {{vector operands to the vector conditional must be the same type ('FourUInts' (vector of 4 'unsigned int' values) and 'FourFloats' (vector of 4 'float' values))}}
+ (void)(four_ints ? four_uints : four_ints); // expected-error {{vector operands to the vector conditional must be the same type ('FourUInts' (vector of 4 'unsigned int' values) and 'FourInts' (vector of 4 'int' values))}}
+ (void)(four_ints ? four_ints : four_uints); // expected-error {{vector operands to the vector conditional must be the same type ('FourInts' (vector of 4 'int' values) and 'FourUInts' (vector of 4 'unsigned int' values))}}
+
+ // GCC rejects these, but our lax vector conversions don't seem to have a problem with them. Allow conversion of the float to an int as an extension.
+ (void)(four_ints ? four_uints : 3.0f);
+ (void)(four_ints ? four_ints : 3.0f);
+
+ // 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); // should work, non-scoped enum can convert to uint.
+ (void)(four_ints ? four_uints : se); // expected-error {{cannot convert between vector and non-scalar values ('FourUInts' (vector of 4 'unsigned int' values) and 'SE'}}
+ // GCC permits this, but our conversion rules reject this for truncation.
+ (void)(two_ints ? two_ints : us); // expected-error {{cannot convert between scalar type 'unsigned int' and vector type 'TwoInts'}}
+ (void)(four_shorts ? four_shorts : uss); // expected-error {{cannot convert between scalar type 'unsigned short' and vector type 'FourShorts'}}
+ (void)(four_ints ? four_floats : us); // expected-error {{cannot convert between scalar type 'unsigned int' and vector type 'FourFloats'}}
+ (void)(four_ints ? four_floats : sint); // expected-error {{cannot convert between scalar type 'int' and vector type 'FourFloats'}}
+}
+
+template <typename T1, typename T2>
+struct is_same {
+ static constexpr bool value = false;
+};
+template <typename T>
+struct is_same<T, T> {
+ static constexpr bool value = true;
+};
+template <typename T1, typename T2>
+constexpr bool is_same_v = is_same<T1, T2>::value;
+template <typename T>
+T &&declval();
+
+// Check the result types when given two vector types.
+void ResultTypes() {
+ // Vectors must be the same, but result is the type of the LHS/RHS.
+ static_assert(is_same_v<TwoInts, decltype(declval<TwoInts>() ? declval<TwoInts>() : declval<TwoInts>())>);
+ static_assert(is_same_v<TwoFloats, decltype(declval<TwoInts>() ? declval<TwoFloats>() : declval<TwoFloats>())>);
+
+ // When both are scalars, converts to vectors of common type.
+ static_assert(is_same_v<TwoUInts, decltype(declval<TwoInts>() ? declval<int>() : declval<unsigned int>())>);
+
+ // Constant is allowed since it doesn't truncate, and should promote to float.
+ static_assert(is_same_v<TwoFloats, decltype(declval<TwoInts>() ? declval<float>() : 5u)>);
+ static_assert(is_same_v<TwoFloats, decltype(declval<TwoInts>() ? 5 : declval<float>())>);
+
+ // when only 1 is a scalar, it should convert to a compatible type.
+ static_assert(is_same_v<TwoFloats, decltype(declval<TwoInts>() ? declval<TwoFloats>() : declval<float>())>);
+ static_assert(is_same_v<TwoInts, decltype(declval<TwoInts>() ? declval<TwoInts>() : declval<int>())>);
+ static_assert(is_same_v<TwoFloats, decltype(declval<TwoInts>() ? declval<TwoFloats>() : 5)>);
+
+ // For the Binary conditional operator, the result type is either the vector on the RHS (that fits the rules on size/count), or the scalar extended to the correct count.
+ static_assert(is_same_v<TwoInts, decltype(declval<TwoInts>() ?: declval<TwoInts>())>);
+ static_assert(is_same_v<TwoInts, decltype(declval<TwoInts>() ?: declval<int>())>);
+}
+
+template <typename Cond>
+void dependent_cond(Cond C) {
+ (void)(C ? 1 : 2);
+}
+
+template <typename Operand>
+void dependent_operand(Operand C) {
+ (void)(two_ints ? 1 : C);
+ (void)(two_ints ? C : 1);
+ (void)(two_ints ? C : C);
+}
+
+template <typename Cond, typename LHS, typename RHS>
+void all_dependent(Cond C, LHS L, RHS R) {
+ (void)(C ? L : R);
+}
+
+// Check dependent cases.
+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))}}}
+ 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))}}}
+ all_dependent(four_ints, four_uints, two_uints); // expected-note {{in instantiation of}}
+ all_dependent(four_ints, four_uints, four_uints);
+}
OpenPOWER on IntegriCloud