[clang] 8bc29d1 - [clang][AArch64][SVE] Implement conditional operator for SVE vectors

David Truby via cfe-commits cfe-commits at lists.llvm.org
Tue May 3 06:10:44 PDT 2022


Author: David Truby
Date: 2022-05-03T13:10:32Z
New Revision: 8bc29d14273b05b05d5a56e34c07948dc2c770d3

URL: https://github.com/llvm/llvm-project/commit/8bc29d14273b05b05d5a56e34c07948dc2c770d3
DIFF: https://github.com/llvm/llvm-project/commit/8bc29d14273b05b05d5a56e34c07948dc2c770d3.diff

LOG: [clang][AArch64][SVE] Implement conditional operator for SVE vectors

This patch adds support for the conditional (ternary) operator on SVE
scalable vector types in C++, matching the behaviour for NEON vector
types. Like the conditional operator for NEON types, this is disabled in
C mode.

Differential Revision: https://reviews.llvm.org/D124091

Added: 
    clang/test/CodeGenCXX/aarch64-sve-vector-conditional-op.cpp
    clang/test/SemaCXX/aarch64-sve-vector-conditional-op.cpp

Modified: 
    clang/include/clang/Sema/Sema.h
    clang/lib/CodeGen/CGExprScalar.cpp
    clang/lib/Sema/SemaExprCXX.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 114725498c982..7d33b5047a677 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11974,6 +11974,10 @@ class Sema final {
   QualType CheckVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS,
                                        ExprResult &RHS,
                                        SourceLocation QuestionLoc);
+
+  QualType CheckSizelessVectorConditionalTypes(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/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index d3fe04d5a7915..2343c7e4afbbe 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -4642,7 +4642,8 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
     return tmp5;
   }
 
-  if (condExpr->getType()->isVectorType()) {
+  if (condExpr->getType()->isVectorType() ||
+      condExpr->getType()->isVLSTBuiltinType()) {
     CGF.incrementProfileCounter(E);
 
     llvm::Value *CondV = CGF.EmitScalarExpr(condExpr);

diff  --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 2af4a85c91c21..27ec863e7a35e 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -23,6 +23,7 @@
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/TypeLoc.h"
 #include "clang/Basic/AlignedAllocation.h"
+#include "clang/Basic/DiagnosticSema.h"
 #include "clang/Basic/PartialDiagnostic.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Basic/TypeTraits.h"
@@ -40,6 +41,7 @@
 #include "llvm/ADT/APInt.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/TypeSize.h"
 using namespace clang;
 using namespace sema;
 
@@ -6108,6 +6110,16 @@ static bool isValidVectorForConditionalCondition(ASTContext &Ctx,
   return EltTy->isIntegralType(Ctx);
 }
 
+static bool isValidSizelessVectorForConditionalCondition(ASTContext &Ctx,
+                                                         QualType CondTy) {
+  if (!CondTy->isVLSTBuiltinType())
+    return false;
+  const QualType EltTy =
+      cast<BuiltinType>(CondTy.getCanonicalType())->getSveEltType(Ctx);
+  assert(!EltTy->isEnumeralType() && "Vectors cant be enum types");
+  return EltTy->isIntegralType(Ctx);
+}
+
 QualType Sema::CheckVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS,
                                            ExprResult &RHS,
                                            SourceLocation QuestionLoc) {
@@ -6199,6 +6211,89 @@ QualType Sema::CheckVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS,
   return ResultType;
 }
 
+QualType Sema::CheckSizelessVectorConditionalTypes(ExprResult &Cond,
+                                                   ExprResult &LHS,
+                                                   ExprResult &RHS,
+                                                   SourceLocation QuestionLoc) {
+  LHS = DefaultFunctionArrayLvalueConversion(LHS.get());
+  RHS = DefaultFunctionArrayLvalueConversion(RHS.get());
+
+  QualType CondType = Cond.get()->getType();
+  const auto *CondBT = CondType->castAs<BuiltinType>();
+  QualType CondElementTy = CondBT->getSveEltType(Context);
+  llvm::ElementCount CondElementCount =
+      Context.getBuiltinVectorTypeInfo(CondBT).EC;
+
+  QualType LHSType = LHS.get()->getType();
+  const auto *LHSBT =
+      LHSType->isVLSTBuiltinType() ? LHSType->getAs<BuiltinType>() : nullptr;
+  QualType RHSType = RHS.get()->getType();
+  const auto *RHSBT =
+      RHSType->isVLSTBuiltinType() ? RHSType->getAs<BuiltinType>() : nullptr;
+
+  QualType ResultType;
+
+  if (LHSBT && RHSBT) {
+    // If both are sizeless vector types, they must be the same type.
+    if (!Context.hasSameType(LHSType, RHSType)) {
+      Diag(QuestionLoc, diag::err_conditional_vector_mismatched)
+          << LHSType << RHSType;
+      return QualType();
+    }
+    ResultType = LHSType;
+  } else if (LHSBT || RHSBT) {
+    ResultType = CheckSizelessVectorOperands(
+        LHS, RHS, QuestionLoc, /*IsCompAssign*/ false, ACK_Conditional);
+    if (ResultType.isNull())
+      return QualType();
+  } else {
+    // Both are scalar so splat
+    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)
+          << ResultElementTy;
+      return QualType();
+    }
+
+    ResultType = Context.getScalableVectorType(
+        ResultElementTy, CondElementCount.getKnownMinValue());
+
+    LHS = ImpCastExprToType(LHS.get(), ResultType, CK_VectorSplat);
+    RHS = ImpCastExprToType(RHS.get(), ResultType, CK_VectorSplat);
+  }
+
+  assert(!ResultType.isNull() && ResultType->isVLSTBuiltinType() &&
+         "Result should have been a vector type");
+  auto *ResultBuiltinTy = ResultType->castAs<BuiltinType>();
+  QualType ResultElementTy = ResultBuiltinTy->getSveEltType(Context);
+  llvm::ElementCount ResultElementCount =
+      Context.getBuiltinVectorTypeInfo(ResultBuiltinTy).EC;
+
+  if (ResultElementCount != CondElementCount) {
+    Diag(QuestionLoc, diag::err_conditional_vector_size)
+        << CondType << ResultType;
+    return QualType();
+  }
+
+  if (Context.getTypeSize(ResultElementTy) !=
+      Context.getTypeSize(CondElementTy)) {
+    Diag(QuestionLoc, diag::err_conditional_vector_element_size)
+        << CondType << ResultType;
+    return QualType();
+  }
+
+  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
@@ -6232,10 +6327,14 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
   bool IsVectorConditional =
       isValidVectorForConditionalCondition(Context, Cond.get()->getType());
 
+  bool IsSizelessVectorConditional =
+      isValidSizelessVectorForConditionalCondition(Context,
+                                                   Cond.get()->getType());
+
   // C++11 [expr.cond]p1
   //   The first expression is contextually converted to bool.
   if (!Cond.get()->isTypeDependent()) {
-    ExprResult CondRes = IsVectorConditional
+    ExprResult CondRes = IsVectorConditional || IsSizelessVectorConditional
                              ? DefaultFunctionArrayLvalueConversion(Cond.get())
                              : CheckCXXBooleanCondition(Cond.get());
     if (CondRes.isInvalid())
@@ -6304,6 +6403,9 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
   if (IsVectorConditional)
     return CheckVectorConditionalTypes(Cond, LHS, RHS, QuestionLoc);
 
+  if (IsSizelessVectorConditional)
+    return CheckSizelessVectorConditionalTypes(Cond, LHS, RHS, QuestionLoc);
+
   // C++11 [expr.cond]p3
   //   Otherwise, if the second and third operand have 
diff erent types, and
   //   either has (cv) class type [...] an attempt is made to convert each of

diff  --git a/clang/test/CodeGenCXX/aarch64-sve-vector-conditional-op.cpp b/clang/test/CodeGenCXX/aarch64-sve-vector-conditional-op.cpp
new file mode 100644
index 0000000000000..e5f1311471acd
--- /dev/null
+++ b/clang/test/CodeGenCXX/aarch64-sve-vector-conditional-op.cpp
@@ -0,0 +1,224 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve \
+// RUN: -fallow-half-arguments-and-returns -disable-O0-optnone \
+// RUN:  -emit-llvm -o - %s | opt -S -sroa | FileCheck %s
+
+// REQUIRES: aarch64-registered-target
+
+#include <arm_sve.h>
+
+// CHECK-LABEL: @_Z9cond_boolu10__SVBool_tu10__SVBool_t(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[CMP:%.*]] = icmp ult <vscale x 16 x i1> [[A:%.*]], [[B:%.*]]
+// CHECK-NEXT:    [[VECTOR_COND:%.*]] = icmp ne <vscale x 16 x i1> [[CMP]], zeroinitializer
+// CHECK-NEXT:    [[VECTOR_SELECT:%.*]] = select <vscale x 16 x i1> [[VECTOR_COND]], <vscale x 16 x i1> [[A]], <vscale x 16 x i1> [[B]]
+// CHECK-NEXT:    ret <vscale x 16 x i1> [[VECTOR_SELECT]]
+//
+svbool_t cond_bool(svbool_t a, svbool_t b) {
+    return a < b ? a : b;
+}
+
+// CHECK-LABEL: @_Z7cond_i8u10__SVInt8_tu10__SVInt8_t(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[CMP:%.*]] = icmp ult <vscale x 16 x i8> [[A:%.*]], [[B:%.*]]
+// CHECK-NEXT:    [[CONV:%.*]] = zext <vscale x 16 x i1> [[CMP]] to <vscale x 16 x i8>
+// CHECK-NEXT:    [[VECTOR_COND:%.*]] = icmp ne <vscale x 16 x i8> [[CONV]], zeroinitializer
+// CHECK-NEXT:    [[VECTOR_SELECT:%.*]] = select <vscale x 16 x i1> [[VECTOR_COND]], <vscale x 16 x i8> [[A]], <vscale x 16 x i8> [[B]]
+// CHECK-NEXT:    ret <vscale x 16 x i8> [[VECTOR_SELECT]]
+//
+svint8_t cond_i8(svint8_t a, svint8_t b) {
+    return a < b ? a : b;
+}
+
+// CHECK-LABEL: @_Z7cond_u8u11__SVUint8_tu11__SVUint8_t(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[CMP:%.*]] = icmp ult <vscale x 16 x i8> [[A:%.*]], [[B:%.*]]
+// CHECK-NEXT:    [[CONV:%.*]] = zext <vscale x 16 x i1> [[CMP]] to <vscale x 16 x i8>
+// CHECK-NEXT:    [[VECTOR_COND:%.*]] = icmp ne <vscale x 16 x i8> [[CONV]], zeroinitializer
+// CHECK-NEXT:    [[VECTOR_SELECT:%.*]] = select <vscale x 16 x i1> [[VECTOR_COND]], <vscale x 16 x i8> [[A]], <vscale x 16 x i8> [[B]]
+// CHECK-NEXT:    ret <vscale x 16 x i8> [[VECTOR_SELECT]]
+//
+svuint8_t cond_u8(svuint8_t a, svuint8_t b) {
+    return a < b ? a : b;
+}
+
+// CHECK-LABEL: @_Z8cond_i16u11__SVInt16_tu11__SVInt16_t(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[CMP:%.*]] = icmp ult <vscale x 8 x i16> [[A:%.*]], [[B:%.*]]
+// CHECK-NEXT:    [[CONV:%.*]] = zext <vscale x 8 x i1> [[CMP]] to <vscale x 8 x i16>
+// CHECK-NEXT:    [[VECTOR_COND:%.*]] = icmp ne <vscale x 8 x i16> [[CONV]], zeroinitializer
+// CHECK-NEXT:    [[VECTOR_SELECT:%.*]] = select <vscale x 8 x i1> [[VECTOR_COND]], <vscale x 8 x i16> [[A]], <vscale x 8 x i16> [[B]]
+// CHECK-NEXT:    ret <vscale x 8 x i16> [[VECTOR_SELECT]]
+//
+svint16_t cond_i16(svint16_t a, svint16_t b) {
+    return a < b ? a : b;
+}
+
+// CHECK-LABEL: @_Z8cond_u16u12__SVUint16_tu12__SVUint16_t(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[CMP:%.*]] = icmp ult <vscale x 8 x i16> [[A:%.*]], [[B:%.*]]
+// CHECK-NEXT:    [[CONV:%.*]] = zext <vscale x 8 x i1> [[CMP]] to <vscale x 8 x i16>
+// CHECK-NEXT:    [[VECTOR_COND:%.*]] = icmp ne <vscale x 8 x i16> [[CONV]], zeroinitializer
+// CHECK-NEXT:    [[VECTOR_SELECT:%.*]] = select <vscale x 8 x i1> [[VECTOR_COND]], <vscale x 8 x i16> [[A]], <vscale x 8 x i16> [[B]]
+// CHECK-NEXT:    ret <vscale x 8 x i16> [[VECTOR_SELECT]]
+//
+svuint16_t cond_u16(svuint16_t a, svuint16_t b) {
+    return a < b ? a : b;
+}
+
+// CHECK-LABEL: @_Z8cond_i32u11__SVInt32_tu11__SVInt32_t(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[CMP:%.*]] = icmp ult <vscale x 4 x i32> [[A:%.*]], [[B:%.*]]
+// CHECK-NEXT:    [[CONV:%.*]] = zext <vscale x 4 x i1> [[CMP]] to <vscale x 4 x i32>
+// CHECK-NEXT:    [[VECTOR_COND:%.*]] = icmp ne <vscale x 4 x i32> [[CONV]], zeroinitializer
+// CHECK-NEXT:    [[VECTOR_SELECT:%.*]] = select <vscale x 4 x i1> [[VECTOR_COND]], <vscale x 4 x i32> [[A]], <vscale x 4 x i32> [[B]]
+// CHECK-NEXT:    ret <vscale x 4 x i32> [[VECTOR_SELECT]]
+//
+svint32_t cond_i32(svint32_t a, svint32_t b) {
+    return a < b ? a : b;
+}
+
+// CHECK-LABEL: @_Z8cond_u32u12__SVUint32_tu12__SVUint32_t(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[CMP:%.*]] = icmp ult <vscale x 4 x i32> [[A:%.*]], [[B:%.*]]
+// CHECK-NEXT:    [[CONV:%.*]] = zext <vscale x 4 x i1> [[CMP]] to <vscale x 4 x i32>
+// CHECK-NEXT:    [[VECTOR_COND:%.*]] = icmp ne <vscale x 4 x i32> [[CONV]], zeroinitializer
+// CHECK-NEXT:    [[VECTOR_SELECT:%.*]] = select <vscale x 4 x i1> [[VECTOR_COND]], <vscale x 4 x i32> [[A]], <vscale x 4 x i32> [[B]]
+// CHECK-NEXT:    ret <vscale x 4 x i32> [[VECTOR_SELECT]]
+//
+svuint32_t cond_u32(svuint32_t a, svuint32_t b) {
+    return a < b ? a : b;
+}
+
+// CHECK-LABEL: @_Z8cond_i64u11__SVInt64_tu11__SVInt64_t(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[CMP:%.*]] = icmp ult <vscale x 2 x i64> [[A:%.*]], [[B:%.*]]
+// CHECK-NEXT:    [[CONV:%.*]] = zext <vscale x 2 x i1> [[CMP]] to <vscale x 2 x i64>
+// CHECK-NEXT:    [[VECTOR_COND:%.*]] = icmp ne <vscale x 2 x i64> [[CONV]], zeroinitializer
+// CHECK-NEXT:    [[VECTOR_SELECT:%.*]] = select <vscale x 2 x i1> [[VECTOR_COND]], <vscale x 2 x i64> [[A]], <vscale x 2 x i64> [[B]]
+// CHECK-NEXT:    ret <vscale x 2 x i64> [[VECTOR_SELECT]]
+//
+svint64_t cond_i64(svint64_t a, svint64_t b) {
+    return a < b ? a : b;
+}
+
+// CHECK-LABEL: @_Z8cond_u64u12__SVUint64_tu12__SVUint64_t(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[CMP:%.*]] = icmp ult <vscale x 2 x i64> [[A:%.*]], [[B:%.*]]
+// CHECK-NEXT:    [[CONV:%.*]] = zext <vscale x 2 x i1> [[CMP]] to <vscale x 2 x i64>
+// CHECK-NEXT:    [[VECTOR_COND:%.*]] = icmp ne <vscale x 2 x i64> [[CONV]], zeroinitializer
+// CHECK-NEXT:    [[VECTOR_SELECT:%.*]] = select <vscale x 2 x i1> [[VECTOR_COND]], <vscale x 2 x i64> [[A]], <vscale x 2 x i64> [[B]]
+// CHECK-NEXT:    ret <vscale x 2 x i64> [[VECTOR_SELECT]]
+//
+svuint64_t cond_u64(svuint64_t a, svuint64_t b) {
+    return a < b ? a : b;
+}
+
+// CHECK-LABEL: @_Z8cond_f16u13__SVFloat16_tu13__SVFloat16_t(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[CMP:%.*]] = fcmp olt <vscale x 8 x half> [[A:%.*]], [[B:%.*]]
+// CHECK-NEXT:    [[CONV:%.*]] = zext <vscale x 8 x i1> [[CMP]] to <vscale x 8 x i16>
+// CHECK-NEXT:    [[VECTOR_COND:%.*]] = icmp ne <vscale x 8 x i16> [[CONV]], zeroinitializer
+// CHECK-NEXT:    [[VECTOR_SELECT:%.*]] = select <vscale x 8 x i1> [[VECTOR_COND]], <vscale x 8 x half> [[A]], <vscale x 8 x half> [[B]]
+// CHECK-NEXT:    ret <vscale x 8 x half> [[VECTOR_SELECT]]
+//
+svfloat16_t cond_f16(svfloat16_t a, svfloat16_t b) {
+    return a < b ? a : b;
+}
+
+// CHECK-LABEL: @_Z8cond_f32u13__SVFloat32_tu13__SVFloat32_t(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[CMP:%.*]] = fcmp olt <vscale x 4 x float> [[A:%.*]], [[B:%.*]]
+// CHECK-NEXT:    [[CONV:%.*]] = zext <vscale x 4 x i1> [[CMP]] to <vscale x 4 x i32>
+// CHECK-NEXT:    [[VECTOR_COND:%.*]] = icmp ne <vscale x 4 x i32> [[CONV]], zeroinitializer
+// CHECK-NEXT:    [[VECTOR_SELECT:%.*]] = select <vscale x 4 x i1> [[VECTOR_COND]], <vscale x 4 x float> [[A]], <vscale x 4 x float> [[B]]
+// CHECK-NEXT:    ret <vscale x 4 x float> [[VECTOR_SELECT]]
+//
+svfloat32_t cond_f32(svfloat32_t a, svfloat32_t b) {
+    return a < b ? a : b;
+}
+
+// CHECK-LABEL: @_Z8cond_f64u13__SVFloat64_tu13__SVFloat64_t(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[CMP:%.*]] = fcmp olt <vscale x 2 x double> [[A:%.*]], [[B:%.*]]
+// CHECK-NEXT:    [[CONV:%.*]] = zext <vscale x 2 x i1> [[CMP]] to <vscale x 2 x i64>
+// CHECK-NEXT:    [[VECTOR_COND:%.*]] = icmp ne <vscale x 2 x i64> [[CONV]], zeroinitializer
+// CHECK-NEXT:    [[VECTOR_SELECT:%.*]] = select <vscale x 2 x i1> [[VECTOR_COND]], <vscale x 2 x double> [[A]], <vscale x 2 x double> [[B]]
+// CHECK-NEXT:    ret <vscale x 2 x double> [[VECTOR_SELECT]]
+//
+svfloat64_t cond_f64(svfloat64_t a, svfloat64_t b) {
+    return a < b ? a : b;
+}
+
+// CHECK-LABEL: @_Z14cond_i32_splatu11__SVInt32_t(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[CMP:%.*]] = icmp ult <vscale x 4 x i32> [[A:%.*]], zeroinitializer
+// CHECK-NEXT:    [[CONV:%.*]] = zext <vscale x 4 x i1> [[CMP]] to <vscale x 4 x i32>
+// CHECK-NEXT:    [[VECTOR_COND:%.*]] = icmp ne <vscale x 4 x i32> [[CONV]], zeroinitializer
+// CHECK-NEXT:    [[VECTOR_SELECT:%.*]] = select <vscale x 4 x i1> [[VECTOR_COND]], <vscale x 4 x i32> [[A]], <vscale x 4 x i32> zeroinitializer
+// CHECK-NEXT:    ret <vscale x 4 x i32> [[VECTOR_SELECT]]
+//
+svint32_t cond_i32_splat(svint32_t a) {
+    return a < 0 ? a : 0;
+}
+
+// CHECK-LABEL: @_Z14cond_u32_splatu12__SVUint32_t(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[CMP:%.*]] = icmp ult <vscale x 4 x i32> [[A:%.*]], shufflevector (<vscale x 4 x i32> insertelement (<vscale x 4 x i32> poison, i32 1, i32 0), <vscale x 4 x i32> poison, <vscale x 4 x i32> zeroinitializer)
+// CHECK-NEXT:    [[CONV:%.*]] = zext <vscale x 4 x i1> [[CMP]] to <vscale x 4 x i32>
+// CHECK-NEXT:    [[VECTOR_COND:%.*]] = icmp ne <vscale x 4 x i32> [[CONV]], zeroinitializer
+// CHECK-NEXT:    [[VECTOR_SELECT:%.*]] = select <vscale x 4 x i1> [[VECTOR_COND]], <vscale x 4 x i32> [[A]], <vscale x 4 x i32> shufflevector (<vscale x 4 x i32> insertelement (<vscale x 4 x i32> poison, i32 1, i32 0), <vscale x 4 x i32> poison, <vscale x 4 x i32> zeroinitializer)
+// CHECK-NEXT:    ret <vscale x 4 x i32> [[VECTOR_SELECT]]
+//
+svuint32_t cond_u32_splat(svuint32_t a) {
+    return a < 1u ? a : 1u;
+}
+
+// CHECK-LABEL: @_Z14cond_i64_splatu11__SVInt64_t(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[CMP:%.*]] = icmp ult <vscale x 2 x i64> [[A:%.*]], zeroinitializer
+// CHECK-NEXT:    [[CONV:%.*]] = zext <vscale x 2 x i1> [[CMP]] to <vscale x 2 x i64>
+// CHECK-NEXT:    [[VECTOR_COND:%.*]] = icmp ne <vscale x 2 x i64> [[CONV]], zeroinitializer
+// CHECK-NEXT:    [[VECTOR_SELECT:%.*]] = select <vscale x 2 x i1> [[VECTOR_COND]], <vscale x 2 x i64> [[A]], <vscale x 2 x i64> zeroinitializer
+// CHECK-NEXT:    ret <vscale x 2 x i64> [[VECTOR_SELECT]]
+//
+svint64_t cond_i64_splat(svint64_t a) {
+    return a < 0l ? a : 0l;
+}
+
+// CHECK-LABEL: @_Z14cond_u64_splatu12__SVUint64_t(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[CMP:%.*]] = icmp ult <vscale x 2 x i64> [[A:%.*]], shufflevector (<vscale x 2 x i64> insertelement (<vscale x 2 x i64> poison, i64 1, i32 0), <vscale x 2 x i64> poison, <vscale x 2 x i32> zeroinitializer)
+// CHECK-NEXT:    [[CONV:%.*]] = zext <vscale x 2 x i1> [[CMP]] to <vscale x 2 x i64>
+// CHECK-NEXT:    [[VECTOR_COND:%.*]] = icmp ne <vscale x 2 x i64> [[CONV]], zeroinitializer
+// CHECK-NEXT:    [[VECTOR_SELECT:%.*]] = select <vscale x 2 x i1> [[VECTOR_COND]], <vscale x 2 x i64> [[A]], <vscale x 2 x i64> shufflevector (<vscale x 2 x i64> insertelement (<vscale x 2 x i64> poison, i64 1, i32 0), <vscale x 2 x i64> poison, <vscale x 2 x i32> zeroinitializer)
+// CHECK-NEXT:    ret <vscale x 2 x i64> [[VECTOR_SELECT]]
+//
+svuint64_t cond_u64_splat(svuint64_t a) {
+    return a < 1ul ? a : 1ul;
+}
+
+// CHECK-LABEL: @_Z14cond_f32_splatu13__SVFloat32_t(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[CMP:%.*]] = fcmp olt <vscale x 4 x float> [[A:%.*]], zeroinitializer
+// CHECK-NEXT:    [[CONV:%.*]] = zext <vscale x 4 x i1> [[CMP]] to <vscale x 4 x i32>
+// CHECK-NEXT:    [[VECTOR_COND:%.*]] = icmp ne <vscale x 4 x i32> [[CONV]], zeroinitializer
+// CHECK-NEXT:    [[VECTOR_SELECT:%.*]] = select <vscale x 4 x i1> [[VECTOR_COND]], <vscale x 4 x float> [[A]], <vscale x 4 x float> zeroinitializer
+// CHECK-NEXT:    ret <vscale x 4 x float> [[VECTOR_SELECT]]
+//
+svfloat32_t cond_f32_splat(svfloat32_t a) {
+    return a < 0.f ? a : 0.f;
+}
+
+// CHECK-LABEL: @_Z14cond_f64_splatu13__SVFloat64_t(
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[CMP:%.*]] = fcmp olt <vscale x 2 x double> [[A:%.*]], zeroinitializer
+// CHECK-NEXT:    [[CONV:%.*]] = zext <vscale x 2 x i1> [[CMP]] to <vscale x 2 x i64>
+// CHECK-NEXT:    [[VECTOR_COND:%.*]] = icmp ne <vscale x 2 x i64> [[CONV]], zeroinitializer
+// CHECK-NEXT:    [[VECTOR_SELECT:%.*]] = select <vscale x 2 x i1> [[VECTOR_COND]], <vscale x 2 x double> [[A]], <vscale x 2 x double> zeroinitializer
+// CHECK-NEXT:    ret <vscale x 2 x double> [[VECTOR_SELECT]]
+//
+svfloat64_t cond_f64_splat(svfloat64_t a) {
+    return a < 0. ? a : 0.;
+}
+

diff  --git a/clang/test/SemaCXX/aarch64-sve-vector-conditional-op.cpp b/clang/test/SemaCXX/aarch64-sve-vector-conditional-op.cpp
new file mode 100644
index 0000000000000..a8fbf9ea3860e
--- /dev/null
+++ b/clang/test/SemaCXX/aarch64-sve-vector-conditional-op.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -verify -triple aarch64-none-linux-gnu -target-feature +sve -fallow-half-arguments-and-returns -fsyntax-only %s
+
+// REQUIRES: aarch64-registered-target
+
+#include <arm_sve.h>
+
+void cond(svint8_t i8, svint16_t i16, svint32_t i32, svint64_t i64,
+          svuint8_t u8, svuint16_t u16, svuint32_t u32, svuint64_t u64,
+          svfloat16_t f16, svfloat32_t f32, svfloat64_t f64,
+          svbool_t b) {
+  (void) i8 < i8 ? i16 : i16; // expected-error{{invalid operands to binary expression}}
+  (void) i8 < i8 ? i32 : i32; // expected-error{{invalid operands to binary expression}}
+  (void) i8 < i8 ? i64 : i64; // expected-error{{invalid operands to binary expression}}
+
+  (void) i16 < i16 ? i16 : i8; // expected-error{{invalid operands to binary expression}}
+  (void) i16 < i16 ? i16 : i32; // expected-error{{invalid operands to binary expression}}
+  (void) i16 < i16 ? i16 : i64; // expected-error{{invalid operands to binary expression}}
+
+  (void) i16 < i16 ? i8 : i16; // expected-error{{invalid operands to binary expression}}
+  (void) i16 < i16 ? i32 : i16; // expected-error{{invalid operands to binary expression}}
+  (void) i16 < i16 ? i64 : i16; // expected-error{{invalid operands to binary expression}}
+}
\ No newline at end of file


        


More information about the cfe-commits mailing list