Author: Florian Hahn Date: 2021-03-09T13:08:52Z New Revision: fc8d3766d721ebc075e16814e48adf48034ea858
URL: https://github.com/llvm/llvm-project/commit/fc8d3766d721ebc075e16814e48adf48034ea858 DIFF: https://github.com/llvm/llvm-project/commit/fc8d3766d721ebc075e16814e48adf48034ea858.diff LOG: [ExtVectorType] Support conditional select operator for C++. This patch implements the conditional select operator for ext_vector_types in C++. It does so by using the same semantics as for C. D71463 added support for the conditional select operator for VectorType in C++. Unfortunately the semantics between ext_vector_type in C are different to VectorType in C++. Select for ext_vector_type is based on the MSB of the condition vector, whereas for VectorType it is `!= 0`. This unfortunately means that the behavior is inconsistent between ExtVectorType and VectorType, but I think using the C semantics for ExtVectorType in C++ as well should be less surprising for users. Reviewed By: erichkeane, aaron.ballman Differential Revision: https://reviews.llvm.org/D98055 Added: clang/test/CodeGenCXX/ext-vector-type-conditional.cpp clang/test/CodeGenCXX/vector-size-conditional.cpp clang/test/SemaCXX/ext-vector-type-conditional.cpp clang/test/SemaCXX/vector-size-conditional.cpp Modified: clang/include/clang/Basic/DiagnosticSemaKinds.td clang/include/clang/Sema/Sema.h clang/lib/Sema/SemaExprCXX.cpp Removed: clang/test/CodeGenCXX/vector-conditional.cpp clang/test/SemaCXX/vector-conditional.cpp ################################################################################ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 79eeed869ba6..7076274dcb6b 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -7423,9 +7423,10 @@ def err_conditional_vector_element_size : Error< 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<"enumeration type %0 is not allowed in a vector conditional">; +def err_conditional_vector_cond_result_mismatch + : Error<"cannot mix vectors and extended vectors in a vector conditional">; +def err_conditional_vector_mismatched : Error<"vector operands to the vector conditional must be the same type " "% diff {($ and $)|}0,1}">; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index e561aaaca7bb..a919740aa662 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -11557,9 +11557,9 @@ class Sema final { 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 CheckVectorConditionalTypes(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/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 8da913035c8f..6a79d621f5de 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -5970,19 +5970,18 @@ static bool ConvertForConditional(Sema &Self, ExprResult &E, QualType T) { // extension. static bool isValidVectorForConditionalCondition(ASTContext &Ctx, QualType CondTy) { - if (!CondTy->isVectorType() || CondTy->isExtVectorType()) + 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) { +QualType Sema::CheckVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS, + ExprResult &RHS, + SourceLocation QuestionLoc) { LHS = DefaultFunctionArrayLvalueConversion(LHS.get()); RHS = DefaultFunctionArrayLvalueConversion(RHS.get()); @@ -5997,24 +5996,17 @@ QualType Sema::CheckGNUVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS, 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 (isa<ExtVectorType>(CondVT) != isa<ExtVectorType>(LHSVT)) { + Diag(QuestionLoc, diag::err_conditional_vector_cond_result_mismatch) + << /*isExtVector*/ isa<ExtVectorType>(CondVT); + return {}; + } + // If both are vector types, they must be the same type. if (!Context.hasSameType(LHSType, RHSType)) { - Diag(QuestionLoc, diag::err_conditional_vector_mismatched_vectors) + Diag(QuestionLoc, diag::err_conditional_vector_mismatched) << LHSType << RHSType; return {}; } @@ -6039,18 +6031,22 @@ QualType Sema::CheckGNUVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS, if (ResultElementTy->isEnumeralType()) { Diag(QuestionLoc, diag::err_conditional_vector_operand_type) - << /*isExtVector*/ false << ResultElementTy; + << ResultElementTy; return {}; } - ResultType = Context.getVectorType( - ResultElementTy, CondType->castAs<VectorType>()->getNumElements(), - VectorType::GenericVector); + if (CondType->isExtVectorType()) + ResultType = + Context.getExtVectorType(ResultElementTy, CondVT->getNumElements()); + else + ResultType = Context.getVectorType( + ResultElementTy, CondVT->getNumElements(), VectorType::GenericVector); LHS = ImpCastExprToType(LHS.get(), ResultType, CK_VectorSplat); RHS = ImpCastExprToType(RHS.get(), ResultType, CK_VectorSplat); } assert(!ResultType.isNull() && ResultType->isVectorType() && + (!CondType->isExtVectorType() || ResultType->isExtVectorType()) && "Result should have been a vector type"); auto *ResultVectorTy = ResultType->castAs<VectorType>(); QualType ResultElementTy = ResultVectorTy->getElementType(); @@ -6077,15 +6073,21 @@ QualType Sema::CheckGNUVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS, /// 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]). +/// This function also implements GCC's vector extension and the +/// OpenCL/ext_vector_type extension for conditionals. The vector extensions +/// permit 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. +/// +/// The expressions are evaluated diff erently for GCC's and OpenCL's extensions. +/// For the GCC extension, the ?: operator is evaluated as +/// (a[0] != 0 ? b[0] : c[0], .. , a[n] != 0 ? b[n] : c[n]). +/// For the OpenCL extensions, the ?: operator is evaluated as +/// (most-significant-bit-set(a[0]) ? b[0] : c[0], .. , +/// most-significant-bit-set(a[n]) ? b[n] : c[n]). QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprResult &RHS, ExprValueKind &VK, ExprObjectKind &OK, @@ -6169,7 +6171,7 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, // Neither is void. if (IsVectorConditional) - return CheckGNUVectorConditionalTypes(Cond, LHS, RHS, QuestionLoc); + return CheckVectorConditionalTypes(Cond, LHS, RHS, QuestionLoc); // C++11 [expr.cond]p3 // Otherwise, if the second and third operand have diff erent types, and diff --git a/clang/test/CodeGenCXX/ext-vector-type-conditional.cpp b/clang/test/CodeGenCXX/ext-vector-type-conditional.cpp new file mode 100644 index 000000000000..573b8ea2e74a --- /dev/null +++ b/clang/test/CodeGenCXX/ext-vector-type-conditional.cpp @@ -0,0 +1,267 @@ +// RUN: %clang_cc1 %s -triple x86_64-linux-gnu -Wno-unused -std=c++11 -emit-llvm -o - | FileCheck %s + +using FourShorts = short __attribute__((ext_vector_type(4))); +using TwoInts = int __attribute__((ext_vector_type(2))); +using TwoUInts = unsigned __attribute__((ext_vector_type(2))); +using FourInts = int __attribute__((ext_vector_type(4))); +using FourUInts = unsigned __attribute__((ext_vector_type(4))); +using TwoLongLong = long long __attribute__((ext_vector_type(2))); +using FourLongLong = long long __attribute__((ext_vector_type(4))); +using TwoFloats = float __attribute__((ext_vector_type(2))); +using FourFloats = float __attribute__((ext_vector_type(4))); +using TwoDoubles = double __attribute__((ext_vector_type(2))); +using FourDoubles = double __attribute__((ext_vector_type(4))); + +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: [[NEG:%.+]] = icmp slt <2 x i32> [[COND]], zeroinitializer + // CHECK: [[SEXT:%.+]] = sext <2 x i1> [[NEG]] to <2 x i32> + // CHECK: [[XOR:%.+]] = xor <2 x i32> [[SEXT]], <i32 -1, i32 -1> + // CHECK: [[RHS_AND:%.+]] = and <2 x i32> [[RHS]], [[XOR]] + // CHECK: [[LHS_AND:%.+]] = and <2 x i32> [[LHS]], [[SEXT]] + // CHECK: = or <2 x i32> [[RHS_AND]], [[LHS_AND]] + + 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: [[NEG:%.+]] = icmp slt <2 x i32> [[COND]], zeroinitializer + // CHECK: [[SEXT:%.+]] = sext <2 x i1> [[NEG]] to <2 x i32> + // CHECK: [[XOR:%.+]] = xor <2 x i32> [[SEXT]], <i32 -1, i32 -1> + // CHECK: [[RHS_EXT:%.+]] = bitcast <2 x float> [[RHS]] to <2 x i32> + // CHECK: [[LHS_EXT:%.+]] = bitcast <2 x float> [[LHS]] to <2 x i32> + // CHECK: [[RHS_AND:%.+]] = and <2 x i32> [[RHS_EXT]], [[XOR]] + // CHECK: [[LHS_AND:%.+]] = and <2 x i32> [[LHS_EXT]], [[SEXT]] + // CHECK: [[OR:%.+]] = or <2 x i32> [[RHS_AND]], [[LHS_AND]] + // CHECK: = bitcast <2 x i32> [[OR]] to <2 x float> + + 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: [[NEG:%.+]] = icmp slt <2 x i64> [[COND]], zeroinitializer + // CHECK: [[SEXT:%.+]] = sext <2 x i1> [[NEG]] to <2 x i64> + // CHECK: [[XOR:%.+]] = xor <2 x i64> [[SEXT]], <i64 -1, i64 -1> + // CHECK: [[RHS_EXT:%.+]] = bitcast <2 x double> [[RHS]] to <2 x i64> + // CHECK: [[LHS_EXT:%.+]] = bitcast <2 x double> [[LHS]] to <2 x i64> + // CHECK: [[RHS_AND:%.+]] = and <2 x i64> [[RHS_EXT]], [[XOR]] + // CHECK: [[LHS_AND:%.+]] = and <2 x i64> [[LHS_EXT]], [[SEXT]] + // CHECK: [[OR:%.+]] = or <2 x i64> [[RHS_AND]], [[LHS_AND]] + // CHECK: = bitcast <2 x i64> [[OR]] to <2 x double> +} + +// 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> poison, i16 [[LHS]], i32 0 + // CHECK: [[LHS_SPLAT:%.+]] = shufflevector <4 x i16> [[LHS_SPLAT_INSERT]], <4 x i16> poison, <4 x i32> zeroinitializer + // CHECK: [[RHS:%.+]] = load i16 + // CHECK: [[RHS_SPLAT_INSERT:%.+]] = insertelement <4 x i16> poison, i16 [[RHS]], i32 0 + // CHECK: [[RHS_SPLAT:%.+]] = shufflevector <4 x i16> [[RHS_SPLAT_INSERT]], <4 x i16> poison, <4 x i32> zeroinitializer + // CHECK: [[NEG:%.+]] = icmp slt <4 x i16> [[COND]], zeroinitializer + // CHECK: [[SEXT:%.+]] = sext <4 x i1> [[NEG]] to <4 x i16> + // CHECK: [[XOR:%.+]] = xor <4 x i16> [[SEXT]], <i16 -1, i16 -1, i16 -1, i16 -1> + // CHECK: [[RHS_AND:%.+]] = and <4 x i16> [[RHS_SPLAT]], [[XOR]] + // CHECK: [[LHS_AND:%.+]] = and <4 x i16> [[LHS_SPLAT]], [[SEXT]] + // CHECK: = or <4 x i16> [[RHS_AND]], [[LHS_AND]] + + four_shorts ? some_ushort : some_ushort; + // CHECK: [[COND:%.+]] = load <4 x i16> + // CHECK: [[LHS:%.+]] = load i16 + // CHECK: [[LHS_SPLAT_INSERT:%.+]] = insertelement <4 x i16> poison, i16 [[LHS]], i32 0 + // CHECK: [[LHS_SPLAT:%.+]] = shufflevector <4 x i16> [[LHS_SPLAT_INSERT]], <4 x i16> poison, <4 x i32> zeroinitializer + // CHECK: [[RHS:%.+]] = load i16 + // CHECK: [[RHS_SPLAT_INSERT:%.+]] = insertelement <4 x i16> poison, i16 [[RHS]], i32 0 + // CHECK: [[RHS_SPLAT:%.+]] = shufflevector <4 x i16> [[RHS_SPLAT_INSERT]], <4 x i16> poison, <4 x i32> zeroinitializer + // CHECK: [[NEG:%.+]] = icmp slt <4 x i16> [[COND]], zeroinitializer + // CHECK: [[SEXT:%.+]] = sext <4 x i1> [[NEG]] to <4 x i16> + // CHECK: [[XOR:%.+]] = xor <4 x i16> [[SEXT]], <i16 -1, i16 -1, i16 -1, i16 -1> + // CHECK: [[RHS_AND:%.+]] = and <4 x i16> [[RHS_SPLAT]], [[XOR]] + // CHECK: [[LHS_AND:%.+]] = and <4 x i16> [[LHS_SPLAT]], [[SEXT]] + // CHECK: = or <4 x i16> [[RHS_AND]], [[LHS_AND]] + + 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> poison, i32 [[LHS_ZEXT]], i32 0 + // CHECK: [[LHS_SPLAT:%.+]] = shufflevector <4 x i32> [[LHS_SPLAT_INSERT]], <4 x i32> poison, <4 x i32> zeroinitializer + // CHECK: [[RHS:%.+]] = load i16 + // CHECK: [[RHS_SEXT:%.+]] = sext i16 [[RHS]] to i32 + // CHECK: [[RHS_SPLAT_INSERT:%.+]] = insertelement <4 x i32> poison, i32 [[RHS_SEXT]], i32 0 + // CHECK: [[RHS_SPLAT:%.+]] = shufflevector <4 x i32> [[RHS_SPLAT_INSERT]], <4 x i32> poison, <4 x i32> zeroinitializer + // CHECK: [[NEG:%.+]] = icmp slt <4 x i32> [[COND]], zeroinitializer + // CHECK: [[SEXT:%.+]] = sext <4 x i1> [[NEG]] to <4 x i32> + // CHECK: [[XOR:%.+]] = xor <4 x i32> [[SEXT]], <i32 -1, i32 -1, i32 -1, i32 -1> + // CHECK: [[RHS_AND:%.+]] = and <4 x i32> [[RHS_SPLAT]], [[XOR]] + // CHECK: [[LHS_AND:%.+]] = and <4 x i32> [[LHS_SPLAT]], [[SEXT]] + // CHECK: = or <4 x i32> [[RHS_AND]], [[LHS_AND]] + + 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> poison, float [[LHS_CONV]], i32 0 + // CHECK: [[LHS_SPLAT:%.+]] = shufflevector <4 x float> [[LHS_SPLAT_INSERT]], <4 x float> poison, <4 x i32> zeroinitializer + // CHECK: [[RHS:%.+]] = load float + // CHECK: [[RHS_SPLAT_INSERT:%.+]] = insertelement <4 x float> poison, float [[RHS]], i32 0 + // CHECK: [[RHS_SPLAT:%.+]] = shufflevector <4 x float> [[RHS_SPLAT_INSERT]], <4 x float> poison, <4 x i32> zeroinitializer + // CHECK: [[NEG:%.+]] = icmp slt <4 x i32> [[COND]], zeroinitializer + // CHECK: [[SEXT:%.+]] = sext <4 x i1> [[NEG]] to <4 x i32> + // CHECK: [[XOR:%.+]] = xor <4 x i32> [[SEXT]], <i32 -1, i32 -1, i32 -1, i32 -1> + // CHECK: [[RHS_CAST:%.+]] = bitcast <4 x float> [[RHS_SPLAT]] to <4 x i32> + // CHECK: [[LHS_CAST:%.+]] = bitcast <4 x float> [[LHS_SPLAT]] to <4 x i32> + // CHECK: [[RHS_AND:%.+]] = and <4 x i32> [[RHS_CAST]], [[XOR]] + // CHECK: [[LHS_AND:%.+]] = and <4 x i32> [[LHS_CAST]], [[SEXT]] + // CHECK: = or <4 x i32> [[RHS_AND]], [[LHS_AND]] + + four_ll ? some_double : some_ll; + // CHECK: [[COND:%.+]] = load <4 x i64> + // CHECK: [[LHS:%.+]] = load double + // CHECK: [[LHS_SPLAT_INSERT:%.+]] = insertelement <4 x double> poison, double [[LHS]], i32 0 + // CHECK: [[LHS_SPLAT:%.+]] = shufflevector <4 x double> [[LHS_SPLAT_INSERT]], <4 x double> poison, <4 x i32> zeroinitializer + // CHECK: [[RHS:%.+]] = load i64 + // CHECK: [[RHS_CONV:%.+]] = sitofp i64 [[RHS]] to double + // CHECK: [[RHS_SPLAT_INSERT:%.+]] = insertelement <4 x double> poison, double [[RHS_CONV]], i32 0 + // CHECK: [[RHS_SPLAT:%.+]] = shufflevector <4 x double> [[RHS_SPLAT_INSERT]], <4 x double> poison, <4 x i32> zeroinitializer + // CHECK: [[NEG:%.+]] = icmp slt <4 x i64> [[COND]], zeroinitializer + // CHECK: [[SEXT:%.+]] = sext <4 x i1> [[NEG]] to <4 x i64> + // CHECK: [[XOR:%.+]] = xor <4 x i64> [[SEXT]], <i64 -1, i64 -1, i64 -1, i64 -1> + // CHECK: [[RHS_CAST:%.+]] = bitcast <4 x double> [[RHS_SPLAT]] to <4 x i64> + // CHECK: [[LHS_CAST:%.+]] = bitcast <4 x double> [[LHS_SPLAT]] to <4 x i64> + // CHECK: [[RHS_AND:%.+]] = and <4 x i64> [[RHS_CAST]], [[XOR]] + // CHECK: [[LHS_AND:%.+]] = and <4 x i64> [[LHS_CAST]], [[SEXT]] + // CHECK: = or <4 x i64> [[RHS_AND]], [[LHS_AND]] + + four_ints ? some_int : some_short; + // CHECK: [[COND:%.+]] = load <4 x i32> + // CHECK: [[LHS:%.+]] = load i32 + // CHECK: [[LHS_SPLAT_INSERT:%.+]] = insertelement <4 x i32> poison, i32 [[LHS]], i32 0 + // CHECK: [[LHS_SPLAT:%.+]] = shufflevector <4 x i32> [[LHS_SPLAT_INSERT]], <4 x i32> poison, <4 x i32> zeroinitializer + // CHECK: [[RHS:%.+]] = load i16 + // CHECK: [[RHS_SEXT:%.+]] = sext i16 [[RHS]] to i32 + // CHECK: [[RHS_SPLAT_INSERT:%.+]] = insertelement <4 x i32> poison, i32 [[RHS_SEXT]], i32 0 + // CHECK: [[RHS_SPLAT:%.+]] = shufflevector <4 x i32> [[RHS_SPLAT_INSERT]], <4 x i32> poison, <4 x i32> zeroinitializer + // CHECK: [[NEG:%.+]] = icmp slt <4 x i32> [[COND]], zeroinitializer + // CHECK: [[SEXT:%.+]] = sext <4 x i1> [[NEG]] to <4 x i32> + // CHECK: [[XOR:%.+]] = xor <4 x i32> [[SEXT]], <i32 -1, i32 -1, i32 -1, i32 -1> + // CHECK: [[RHS_AND:%.+]] = and <4 x i32> [[RHS_SPLAT]], [[XOR]] + // CHECK: [[LHS_AND:%.+]] = and <4 x i32> [[LHS_SPLAT]], [[SEXT]] + // CHECK: = or <4 x i32> [[RHS_AND]], [[LHS_AND]] +} + +// 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> poison, i32 [[RHS]], i32 0 + // CHECK: [[RHS_SPLAT:%.+]] = shufflevector <4 x i32> [[RHS_SPLAT_INSERT]], <4 x i32> poison, <4 x i32> zeroinitializer + // CHECK: [[NEG:%.+]] = icmp slt <4 x i32> [[COND]], zeroinitializer + // CHECK: [[SEXT:%.+]] = sext <4 x i1> [[NEG]] to <4 x i32> + // CHECK: [[XOR:%.+]] = xor <4 x i32> [[SEXT]], <i32 -1, i32 -1, i32 -1, i32 -1> + // CHECK: [[RHS_AND:%.+]] = and <4 x i32> [[RHS_SPLAT]], [[XOR]] + // CHECK: [[LHS_AND:%.+]] = and <4 x i32> [[LHS]], [[SEXT]] + // CHECK: = or <4 x i32> [[RHS_AND]], [[LHS_AND]] + + four_ints ? four_ints : 5; + // CHECK: [[COND:%.+]] = load <4 x i32> + // CHECK: [[LHS:%.+]] = load <4 x i32> + // CHECK: [[NEG:%.+]] = icmp slt <4 x i32> [[COND]], zeroinitializer + // CHECK: [[SEXT:%.+]] = sext <4 x i1> [[NEG]] to <4 x i32> + // CHECK: [[XOR:%.+]] = xor <4 x i32> [[SEXT]], <i32 -1, i32 -1, i32 -1, i32 -1> + // CHECK: [[RHS_AND:%.+]] = and <4 x i32> <i32 5, i32 5, i32 5, i32 5>, [[XOR]] + // CHECK: [[LHS_AND:%.+]] = and <4 x i32> [[LHS]], [[SEXT]] + // CHECK: = or <4 x i32> [[RHS_AND]], [[LHS_AND]] + + 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> poison, float [[RHS]], i32 0 + // CHECK: [[RHS_SPLAT:%.+]] = shufflevector <4 x float> [[RHS_SPLAT_INSERT]], <4 x float> poison, <4 x i32> zeroinitializer + // CHECK: [[NEG:%.+]] = icmp slt <4 x i32> [[COND]], zeroinitializer + // CHECK: [[SEXT:%.+]] = sext <4 x i1> [[NEG]] to <4 x i32> + // CHECK: [[XOR:%.+]] = xor <4 x i32> [[SEXT]], <i32 -1, i32 -1, i32 -1, i32 -1> + // CHECK: [[RHS_CAST:%.+]] = bitcast <4 x float> [[RHS_SPLAT]] to <4 x i32> + // CHECK: [[LHS_CAST:%.+]] = bitcast <4 x float> [[LHS]] to <4 x i32> + // CHECK: [[RHS_AND:%.+]] = and <4 x i32> [[RHS_CAST]], [[XOR]] + // CHECK: [[LHS_AND:%.+]] = and <4 x i32> [[LHS_CAST]], [[SEXT]] + // CHECK: = or <4 x i32> [[RHS_AND]], [[LHS_AND]] + + four_ll ? four_doubles : 6.0; + // CHECK: [[COND:%.+]] = load <4 x i64> + // CHECK: [[LHS:%.+]] = load <4 x double> + // CHECK: [[NEG:%.+]] = icmp slt <4 x i64> [[COND]], zeroinitializer + // CHECK: [[SEXT:%.+]] = sext <4 x i1> [[NEG]] to <4 x i64> + // CHECK: [[XOR:%.+]] = xor <4 x i64> [[SEXT]], <i64 -1, i64 -1, i64 -1, i64 -1> + // CHECK: [[LHS_CAST:%.+]] = bitcast <4 x double> [[LHS]] to <4 x i64> + // CHECK: [[RHS_AND:%.+]] = and <4 x i64> <i64 4618441417868443648, i64 4618441417868443648, i64 4618441417868443648, i64 4618441417868443648>, [[XOR]] + // CHECK: [[LHS_AND:%.+]] = and <4 x i64> [[LHS_CAST]], [[SEXT]] + // CHECK: = or <4 x i64> [[RHS_AND]], [[LHS_AND]] + + four_ll ? four_ll : 6; + // CHECK: [[COND:%.+]] = load <4 x i64> + // CHECK: [[LHS:%.+]] = load <4 x i64> + // CHECK: [[NEG:%.+]] = icmp slt <4 x i64> [[COND]], zeroinitializer + // CHECK: [[SEXT:%.+]] = sext <4 x i1> [[NEG]] to <4 x i64> + // CHECK: [[XOR:%.+]] = xor <4 x i64> [[SEXT]], <i64 -1, i64 -1, i64 -1, i64 -1> + // CHECK: [[RHS_AND:%.+]] = and <4 x i64> <i64 6, i64 6, i64 6, i64 6>, [[XOR]] + // CHECK: [[LHS_AND:%.+]] = and <4 x i64> [[LHS]], [[SEXT]] + // CHECK: [[OR:%.+]] = or <4 x i64> [[RHS_AND]], [[LHS_AND]] + + 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> poison, i64 [[RHS_CONV]], i32 0 + // CHECK: [[RHS_SPLAT:%.+]] = shufflevector <4 x i64> [[RHS_SPLAT_INSERT]], <4 x i64> poison, <4 x i32> zeroinitializer + // CHECK: [[NEG:%.+]] = icmp slt <4 x i64> [[COND]], zeroinitializer + // CHECK: [[SEXT:%.+]] = sext <4 x i1> [[NEG]] to <4 x i64> + // CHECK: [[XOR:%.+]] = xor <4 x i64> [[SEXT]], <i64 -1, i64 -1, i64 -1, i64 -1> + // CHECK: [[RHS_AND:%.+]] = and <4 x i64> [[RHS_SPLAT]], [[XOR]] + // CHECK: [[LHS_AND:%.+]] = and <4 x i64> [[LHS]], [[SEXT]] + // CHECK: [[OR:%.+]] = or <4 x i64> [[RHS_AND]], [[LHS_AND]] + + 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> poison, i64 [[RHS]], i32 0 + // CHECK: [[RHS_SPLAT:%.+]] = shufflevector <4 x i64> [[RHS_SPLAT_INSERT]], <4 x i64> poison, <4 x i32> zeroinitializer + // CHECK: [[NEG:%.+]] = icmp slt <4 x i64> [[COND]], zeroinitializer + // CHECK: [[SEXT:%.+]] = sext <4 x i1> [[NEG]] to <4 x i64> + // CHECK: [[XOR:%.+]] = xor <4 x i64> [[SEXT]], <i64 -1, i64 -1, i64 -1, i64 -1> + // CHECK: [[RHS_AND:%.+]] = and <4 x i64> [[RHS_SPLAT]], [[XOR]] + // CHECK: [[LHS_AND:%.+]] = and <4 x i64> [[LHS]], [[SEXT]] + // CHECK: [[OR:%.+]] = or <4 x i64> [[RHS_AND]], [[LHS_AND]] +} diff --git a/clang/test/CodeGenCXX/vector-conditional.cpp b/clang/test/CodeGenCXX/vector-size-conditional.cpp similarity index 100% rename from clang/test/CodeGenCXX/vector-conditional.cpp rename to clang/test/CodeGenCXX/vector-size-conditional.cpp diff --git a/clang/test/SemaCXX/ext-vector-type-conditional.cpp b/clang/test/SemaCXX/ext-vector-type-conditional.cpp new file mode 100644 index 000000000000..b2e125b350cc --- /dev/null +++ b/clang/test/SemaCXX/ext-vector-type-conditional.cpp @@ -0,0 +1,194 @@ +// 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 diff erent from +// int, so it specifies a triple. + +using FourShorts = short __attribute__((ext_vector_type(4))); +using TwoInts = int __attribute__((ext_vector_type(2))); +using TwoUInts = unsigned __attribute__((ext_vector_type(2))); +using FourInts = int __attribute__((ext_vector_type(4))); +using FourUInts = unsigned __attribute__((ext_vector_type(4))); +using TwoLongLong = long long __attribute__((ext_vector_type(2))); +using FourLongLong = long long __attribute__((ext_vector_type(4))); +using TwoFloats = float __attribute__((ext_vector_type(2))); +using FourFloats = float __attribute__((ext_vector_type(4))); +using TwoDoubles = double __attribute__((ext_vector_type(2))); +using FourDoubles = double __attribute__((ext_vector_type(4))); + +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 'double __attribute__((ext_vector_type(4)))' (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 'long long __attribute__((ext_vector_type(4)))' (vector of 4 'long long' values) do not have elements of the same size}} + (void)(four_ints ?: 3.0); // expected-error {{annot convert between vector values of diff erent size ('FourInts' (vector of 4 'int' values) and 'double')}} + (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 'int __attribute__((ext_vector_type(4)))' (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 'int __attribute__((ext_vector_type(4)))' (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 'short __attribute__((ext_vector_type(4)))' (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))}} + + (void)(four_ints ? four_uints : 3.0f); // expected-error {{cannot convert between vector values of diff erent size ('FourUInts' (vector of 4 'unsigned int' values) and 'float')}} + (void)(four_ints ? four_ints : 3.0f); // expected-error {{cannot convert between vector values of diff erent size ('FourInts' (vector of 4 'int' values) and 'float')}} + + // 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 vector values of diff erent size ('FourUInts' (vector of 4 'unsigned int' values) and 'E')}} + (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'}} + + (void)(two_ints ? two_ints : us); + (void)(four_shorts ? four_shorts : uss); + (void)(four_ints ? four_floats : us); + (void)(four_ints ? four_floats : sint); +} + +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@158 {{vector operands to the vector conditional must be the same type ('unsigned int __attribute__((ext_vector_type(4)))' (vector of 4 'unsigned int' values) and 'double __attribute__((ext_vector_type(4)))' (vector of 4 'double' values))}}} + all_dependent(four_ints, four_uints, four_doubles); // expected-note {{in instantiation of}} + + // expected-error@158 {{vector operands to the vector conditional must be the same type ('unsigned int __attribute__((ext_vector_type(4)))' (vector of 4 'unsigned int' values) and 'unsigned int __attribute__((ext_vector_type(2)))' (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); +} + +using FourShortsVS = short __attribute__((__vector_size__(8))); + +void mix_vector_types() { + FourShortsVS vs; + (vs == 1 ? four_shorts : four_shorts); + // expected-error@-1 {{cannot mix vectors and extended vectors in a vector conditional}} + + (four_shorts == 1 ? vs : vs); + // expected-error@-1 {{cannot mix vectors and extended vectors in a vector conditional}} + + (four_shorts == 1 ? four_shorts : vs); + // expected-error@-1 {{vector operands to the vector conditional must be the same type ('FourShorts' (vector of 4 'short' values) and 'FourShortsVS' (vector of 4 'short' values))}} + + (four_shorts == 1 ? vs : four_shorts); + // expected-error@-1 {{cannot mix vectors and extended vectors in a vector conditional}} + + (vs == 1 ? vs : four_shorts); + // expected-error@-1 {{vector operands to the vector conditional must be the same type ('FourShortsVS' (vector of 4 'short' values) and 'FourShorts' (vector of 4 'short' values))}} + + (vs == 1 ? four_shorts : vs); + // expected-error@-1 {{cannot mix vectors and extended vectors in a vector conditional}} +} diff --git a/clang/test/SemaCXX/vector-conditional.cpp b/clang/test/SemaCXX/vector-size-conditional.cpp similarity index 100% rename from clang/test/SemaCXX/vector-conditional.cpp rename to clang/test/SemaCXX/vector-size-conditional.cpp _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits