Index: clang/docs/LanguageExtensions.rst =================================================================== --- clang/docs/LanguageExtensions.rst +++ clang/docs/LanguageExtensions.rst @@ -478,7 +478,7 @@ !, &&, || 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 @@ -489,9 +489,11 @@ 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). +.. [#] ternary operator(?:) has different behaviors depending on condition + operand's vector type. If the condition is a GNU vector (i.e. __vector_size__), + 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. Matrix Types ============ Index: clang/lib/CodeGen/CGExprScalar.cpp =================================================================== --- clang/lib/CodeGen/CGExprScalar.cpp +++ clang/lib/CodeGen/CGExprScalar.cpp @@ -4431,8 +4431,8 @@ // OpenCL: If the condition is a vector, we can treat this condition like // the select function. - if (CGF.getLangOpts().OpenCL - && condExpr->getType()->isVectorType()) { + if ((CGF.getLangOpts().OpenCL && condExpr->getType()->isVectorType()) || + condExpr->getType()->isExtVectorType()) { CGF.incrementProfileCounter(E); llvm::Value *CondV = CGF.EmitScalarExpr(condExpr); Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -7480,6 +7480,13 @@ // C99 6.5.15p2 if (CondTy->isScalarType()) return false; + // Only ext vector is allowed + if (const auto *VecCondTy = Cond->getType()->getAs()) { + QualType EleTy = VecCondTy->getElementType(); + if (EleTy->isIntegerType()) + return false; + } + S.Diag(QuestionLoc, diag::err_typecheck_cond_expect_scalar) << CondTy << Cond->getSourceRange(); return true; @@ -7958,10 +7965,21 @@ // 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); + RHS.get()->getType()->isVectorType()) { + QualType VecResTy = CheckVectorOperands(LHS, RHS, QuestionLoc, + /*isCompAssign*/ false, + /*AllowBothBool*/ true, + /*AllowBoolConversions*/ false); + // If the condition is ext vector, we're imposing OpenCL's rule wrt + // condition and result type. + QualType CondTy = Cond.get()->getType(); + if (CondTy->isExtVectorType()) { + if (VecResTy.isNull() || + checkVectorResult(*this, CondTy, VecResTy, QuestionLoc)) + return QualType(); + } + return VecResTy; + } QualType ResTy = UsualArithmeticConversions(LHS, RHS, QuestionLoc, ACK_Conditional); Index: clang/test/Sema/ext_vector_comparisons.c =================================================================== --- clang/test/Sema/ext_vector_comparisons.c +++ clang/test/Sema/ext_vector_comparisons.c @@ -28,3 +28,19 @@ return vec > vec; // no-warning return vec >= vec; // no-warning } + +static int4 test3() { + int4 i0, i1; + + return i0 > i1 ? i0 : i1; // no-error + return i0 ? i0 : i1; // no-error +} + +static float4 test4() { + float4 f0, f1; + + // This would actually generate implicit casting warning + // under Weverything flag but we don't really care here + return f0 > f1 ? f0 : f1; // no-error + return f0 ? f0 : f1; // expected-error {{arithmetic or pointer type is required}} +}