[clang] b30c166 - Implement constexpr BinaryOperator for vector types

Erich Keane via cfe-commits cfe-commits at lists.llvm.org
Mon Jun 22 07:05:56 PDT 2020


Author: Erich Keane
Date: 2020-06-22T07:05:43-07:00
New Revision: b30c16670e428d09a0854a8f418e46a3e705e4d1

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

LOG: Implement constexpr BinaryOperator for vector types

These operations do member-wise versions of the all of the listed
operations.  This patch implements all of the binaryoperators for these
types. Note that the test is required to use codegen as I could not come
up with a good way to validate the values without the array-subscript
operator implemented (which is likely a much more involved change).

Differential Reivision: https://reviews.llvm.org/D79755

Added: 
    clang/test/SemaCXX/constexpr-vectors.cpp

Modified: 
    clang/lib/AST/ExprConstant.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 640bdd0d45e5..45a2fd2a53d2 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -2664,6 +2664,155 @@ static bool handleFloatFloatBinOp(EvalInfo &Info, const Expr *E,
   return true;
 }
 
+static bool handleLogicalOpForVector(const APInt &LHSValue,
+                                     BinaryOperatorKind Opcode,
+                                     const APInt &RHSValue, APInt &Result) {
+  bool LHS = (LHSValue != 0);
+  bool RHS = (RHSValue != 0);
+
+  if (Opcode == BO_LAnd)
+    Result = LHS && RHS;
+  else
+    Result = LHS || RHS;
+  return true;
+}
+static bool handleLogicalOpForVector(const APFloat &LHSValue,
+                                     BinaryOperatorKind Opcode,
+                                     const APFloat &RHSValue, APInt &Result) {
+  bool LHS = !LHSValue.isZero();
+  bool RHS = !RHSValue.isZero();
+
+  if (Opcode == BO_LAnd)
+    Result = LHS && RHS;
+  else
+    Result = LHS || RHS;
+  return true;
+}
+
+static bool handleLogicalOpForVector(const APValue &LHSValue,
+                                     BinaryOperatorKind Opcode,
+                                     const APValue &RHSValue, APInt &Result) {
+  // The result is always an int type, however operands match the first.
+  if (LHSValue.getKind() == APValue::Int)
+    return handleLogicalOpForVector(LHSValue.getInt(), Opcode,
+                                    RHSValue.getInt(), Result);
+  assert(LHSValue.getKind() == APValue::Float && "Should be no other options");
+  return handleLogicalOpForVector(LHSValue.getFloat(), Opcode,
+                                  RHSValue.getFloat(), Result);
+}
+
+template <typename APTy>
+static bool
+handleCompareOpForVectorHelper(const APTy &LHSValue, BinaryOperatorKind Opcode,
+                               const APTy &RHSValue, APInt &Result) {
+  switch (Opcode) {
+  default:
+    llvm_unreachable("unsupported binary operator");
+  case BO_EQ:
+    Result = (LHSValue == RHSValue);
+    break;
+  case BO_NE:
+    Result = (LHSValue != RHSValue);
+    break;
+  case BO_LT:
+    Result = (LHSValue < RHSValue);
+    break;
+  case BO_GT:
+    Result = (LHSValue > RHSValue);
+    break;
+  case BO_LE:
+    Result = (LHSValue <= RHSValue);
+    break;
+  case BO_GE:
+    Result = (LHSValue >= RHSValue);
+    break;
+  }
+
+  return true;
+}
+
+static bool handleCompareOpForVector(const APValue &LHSValue,
+                                     BinaryOperatorKind Opcode,
+                                     const APValue &RHSValue, APInt &Result) {
+  // The result is always an int type, however operands match the first.
+  if (LHSValue.getKind() == APValue::Int)
+    return handleCompareOpForVectorHelper(LHSValue.getInt(), Opcode,
+                                          RHSValue.getInt(), Result);
+  assert(LHSValue.getKind() == APValue::Float && "Should be no other options");
+  return handleCompareOpForVectorHelper(LHSValue.getFloat(), Opcode,
+                                        RHSValue.getFloat(), Result);
+}
+
+// Perform binary operations for vector types, in place on the LHS.
+static bool handleVectorVectorBinOp(EvalInfo &Info, const Expr *E,
+                                    BinaryOperatorKind Opcode,
+                                    APValue &LHSValue,
+                                    const APValue &RHSValue) {
+  assert(Opcode != BO_PtrMemD && Opcode != BO_PtrMemI &&
+         "Operation not supported on vector types");
+
+  const auto *VT = E->getType()->castAs<VectorType>();
+  unsigned NumElements = VT->getNumElements();
+  QualType EltTy = VT->getElementType();
+
+  // In the cases (typically C as I've observed) where we aren't evaluating
+  // constexpr but are checking for cases where the LHS isn't yet evaluatable,
+  // just give up.
+  if (!LHSValue.isVector()) {
+    assert(LHSValue.isLValue() &&
+           "A vector result that isn't a vector OR uncalculated LValue");
+    Info.FFDiag(E);
+    return false;
+  }
+
+  assert(LHSValue.getVectorLength() == NumElements &&
+         RHSValue.getVectorLength() == NumElements && "Different vector sizes");
+
+  SmallVector<APValue, 4> ResultElements;
+
+  for (unsigned EltNum = 0; EltNum < NumElements; ++EltNum) {
+    APValue LHSElt = LHSValue.getVectorElt(EltNum);
+    APValue RHSElt = RHSValue.getVectorElt(EltNum);
+
+    if (EltTy->isIntegerType()) {
+      APSInt EltResult{Info.Ctx.getIntWidth(EltTy),
+                       EltTy->isUnsignedIntegerType()};
+      bool Success = true;
+
+      if (BinaryOperator::isLogicalOp(Opcode))
+        Success = handleLogicalOpForVector(LHSElt, Opcode, RHSElt, EltResult);
+      else if (BinaryOperator::isComparisonOp(Opcode))
+        Success = handleCompareOpForVector(LHSElt, Opcode, RHSElt, EltResult);
+      else
+        Success = handleIntIntBinOp(Info, E, LHSElt.getInt(), Opcode,
+                                    RHSElt.getInt(), EltResult);
+
+      if (!Success) {
+        Info.FFDiag(E);
+        return false;
+      }
+      ResultElements.emplace_back(EltResult);
+
+    } else if (EltTy->isFloatingType()) {
+      assert(LHSElt.getKind() == APValue::Float &&
+             RHSElt.getKind() == APValue::Float &&
+             "Mismatched LHS/RHS/Result Type");
+      APFloat LHSFloat = LHSElt.getFloat();
+
+      if (!handleFloatFloatBinOp(Info, E, LHSFloat, Opcode,
+                                 RHSElt.getFloat())) {
+        Info.FFDiag(E);
+        return false;
+      }
+
+      ResultElements.emplace_back(LHSFloat);
+    }
+  }
+
+  LHSValue = APValue(ResultElements.data(), ResultElements.size());
+  return true;
+}
+
 /// Cast an lvalue referring to a base subobject to a derived class, by
 /// truncating the lvalue's path to the given length.
 static bool CastToDerivedClass(EvalInfo &Info, const Expr *E, LValue &Result,
@@ -3910,12 +4059,26 @@ struct CompoundAssignSubobjectHandler {
       return false;
     case APValue::LValue:
       return foundPointer(Subobj, SubobjType);
+    case APValue::Vector:
+      return foundVector(Subobj, SubobjType);
     default:
       // FIXME: can this happen?
       Info.FFDiag(E);
       return false;
     }
   }
+
+  bool foundVector(APValue &Value, QualType SubobjType) {
+    if (!checkConst(SubobjType))
+      return false;
+
+    if (!SubobjType->isVectorType()) {
+      Info.FFDiag(E);
+      return false;
+    }
+    return handleVectorVectorBinOp(Info, E, Opcode, Value, RHS);
+  }
+
   bool found(APSInt &Value, QualType SubobjType) {
     if (!checkConst(SubobjType))
       return false;
@@ -9516,10 +9679,9 @@ namespace {
     bool VisitCastExpr(const CastExpr* E);
     bool VisitInitListExpr(const InitListExpr *E);
     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
+    bool VisitBinaryOperator(const BinaryOperator *E);
+    // FIXME: Missing: unary -, unary ~, conditional operator (for GNU
+    //                 conditional select), shufflevector, ExtVectorElementExpr
   };
 } // end anonymous namespace
 
@@ -9667,6 +9829,41 @@ bool VectorExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {
   return ZeroInitialization(E);
 }
 
+bool VectorExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
+  BinaryOperatorKind Op = E->getOpcode();
+  assert(Op != BO_PtrMemD && Op != BO_PtrMemI && Op != BO_Cmp &&
+         "Operation not supported on vector types");
+
+  if (Op == BO_Comma)
+    return ExprEvaluatorBaseTy::VisitBinaryOperator(E);
+
+  Expr *LHS = E->getLHS();
+  Expr *RHS = E->getRHS();
+
+  assert(LHS->getType()->isVectorType() && RHS->getType()->isVectorType() &&
+         "Must both be vector types");
+  // Checking JUST the types are the same would be fine, except shifts don't
+  // need to have their types be the same (since you always shift by an int).
+  assert(LHS->getType()->getAs<VectorType>()->getNumElements() ==
+             E->getType()->getAs<VectorType>()->getNumElements() &&
+         RHS->getType()->getAs<VectorType>()->getNumElements() ==
+             E->getType()->getAs<VectorType>()->getNumElements() &&
+         "All operands must be the same size.");
+
+  APValue LHSValue;
+  APValue RHSValue;
+  bool LHSOK = Evaluate(LHSValue, Info, LHS);
+  if (!LHSOK && !Info.noteFailure())
+    return false;
+  if (!Evaluate(RHSValue, Info, RHS) || !LHSOK)
+    return false;
+
+  if (!handleVectorVectorBinOp(Info, E, Op, LHSValue, RHSValue))
+    return false;
+
+  return Success(LHSValue, E);
+}
+
 //===----------------------------------------------------------------------===//
 // Array Evaluation
 //===----------------------------------------------------------------------===//

diff  --git a/clang/test/SemaCXX/constexpr-vectors.cpp b/clang/test/SemaCXX/constexpr-vectors.cpp
new file mode 100644
index 000000000000..1ba0e3325332
--- /dev/null
+++ b/clang/test/SemaCXX/constexpr-vectors.cpp
@@ -0,0 +1,616 @@
+// RUN: %clang_cc1 -std=c++14 -Wno-unused-value %s -disable-llvm-passes -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s
+
+// FIXME: Unfortunately there is no good way to validate that our values are
+// correct since Vector types don't have operator [] implemented for constexpr.
+// Instead, we need to use filecheck to ensure the emitted IR is correct. Once
+// someone implements array subscript operator for these types as constexpr,
+// this test should modified to jsut use static asserts.
+
+using FourCharsVecSize __attribute__((vector_size(4))) = char;
+using FourIntsVecSize __attribute__((vector_size(16))) = int;
+using FourLongLongsVecSize __attribute__((vector_size(32))) = long long;
+using FourFloatsVecSize __attribute__((vector_size(16))) = float;
+using FourDoublesVecSize __attribute__((vector_size(32))) = double;
+
+using FourCharsExtVec __attribute__((ext_vector_type(4))) = char;
+using FourIntsExtVec __attribute__((ext_vector_type(4))) = int;
+using FourLongLongsExtVec __attribute__((ext_vector_type(4))) = long long;
+using FourFloatsExtVec __attribute__((ext_vector_type(4))) = float;
+using FourDoublesExtVec __attribute__((ext_vector_type(4))) = double;
+
+// Next a series of tests to make sure these operations are usable in
+// constexpr functions. Template instantiations don't emit Winvalid-constexpr,
+// so we have to do these as macros.
+#define MathShiftOps(Type)                            \
+  constexpr auto MathShiftOps##Type(Type a, Type b) { \
+    a = a + b;                                        \
+    a = a - b;                                        \
+    a = a * b;                                        \
+    a = a / b;                                        \
+    b = a + 1;                                        \
+    b = a - 1;                                        \
+    b = a * 1;                                        \
+    b = a / 1;                                        \
+    a += a;                                           \
+    a -= a;                                           \
+    a *= a;                                           \
+    a /= a;                                           \
+    b += a;                                           \
+    b -= a;                                           \
+    b *= a;                                           \
+    b /= a;                                           \
+    a < b;                                            \
+    a > b;                                            \
+    a <= b;                                           \
+    a >= b;                                           \
+    a == b;                                           \
+    a != b;                                           \
+    a &&b;                                            \
+    a || b;                                           \
+    auto c = (a, b);                                  \
+    return c;                                         \
+  }
+
+// Ops specific to Integers.
+#define MathShiftOpsInts(Type)                            \
+  constexpr auto MathShiftopsInts##Type(Type a, Type b) { \
+    a = a << b;                                           \
+    a = a >> b;                                           \
+    a = a << 3;                                           \
+    a = a >> 3;                                           \
+    a = 3 << b;                                           \
+    a = 3 >> b;                                           \
+    a <<= b;                                              \
+    a >>= b;                                              \
+    a <<= 3;                                              \
+    a >>= 3;                                              \
+    a = a % b;                                            \
+    a &b;                                                 \
+    a | b;                                                \
+    a ^ b;                                                \
+    return a;                                             \
+  }
+
+MathShiftOps(FourCharsVecSize);
+MathShiftOps(FourIntsVecSize);
+MathShiftOps(FourLongLongsVecSize);
+MathShiftOps(FourFloatsVecSize);
+MathShiftOps(FourDoublesVecSize);
+MathShiftOps(FourCharsExtVec);
+MathShiftOps(FourIntsExtVec);
+MathShiftOps(FourLongLongsExtVec);
+MathShiftOps(FourFloatsExtVec);
+MathShiftOps(FourDoublesExtVec);
+
+MathShiftOpsInts(FourCharsVecSize);
+MathShiftOpsInts(FourIntsVecSize);
+MathShiftOpsInts(FourLongLongsVecSize);
+MathShiftOpsInts(FourCharsExtVec);
+MathShiftOpsInts(FourIntsExtVec);
+MathShiftOpsInts(FourLongLongsExtVec);
+
+template <typename T, typename U>
+constexpr auto CmpMul(T t, U u) {
+  t *= u;
+  return t;
+}
+template <typename T, typename U>
+constexpr auto CmpDiv(T t, U u) {
+  t /= u;
+  return t;
+}
+template <typename T, typename U>
+constexpr auto CmpRem(T t, U u) {
+  t %= u;
+  return t;
+}
+
+template <typename T, typename U>
+constexpr auto CmpAdd(T t, U u) {
+  t += u;
+  return t;
+}
+
+template <typename T, typename U>
+constexpr auto CmpSub(T t, U u) {
+  t -= u;
+  return t;
+}
+
+template <typename T, typename U>
+constexpr auto CmpLSH(T t, U u) {
+  t <<= u;
+  return t;
+}
+
+template <typename T, typename U>
+constexpr auto CmpRSH(T t, U u) {
+  t >>= u;
+  return t;
+}
+
+template <typename T, typename U>
+constexpr auto CmpBinAnd(T t, U u) {
+  t &= u;
+  return t;
+}
+
+template <typename T, typename U>
+constexpr auto CmpBinXOr(T t, U u) {
+  t ^= u;
+  return t;
+}
+
+template <typename T, typename U>
+constexpr auto CmpBinOr(T t, U u) {
+  t |= u;
+  return t;
+}
+
+// Only int vs float makes a 
diff erence here, so we only need to test 1 of each.
+// Test Char to make sure the mixed-nature of shifts around char is evident.
+void CharUsage() {
+  constexpr auto a = FourCharsVecSize{6, 3, 2, 1} +
+                     FourCharsVecSize{12, 15, 5, 7};
+  // CHECK: store <4 x i8> <i8 18, i8 18, i8 7, i8 8>
+  constexpr auto b = FourCharsVecSize{19, 15, 13, 12} -
+                     FourCharsVecSize{13, 14, 5, 3};
+  // CHECK: store <4 x i8> <i8 6, i8 1, i8 8, i8 9>
+  constexpr auto c = FourCharsVecSize{8, 4, 2, 1} *
+                     FourCharsVecSize{3, 4, 5, 6};
+  // CHECK: store <4 x i8> <i8 24, i8 16, i8 10, i8 6>
+  constexpr auto d = FourCharsVecSize{12, 12, 10, 10} /
+                     FourCharsVecSize{6, 4, 5, 2};
+  // CHECK: store <4 x i8> <i8 2, i8 3, i8 2, i8 5>
+  constexpr auto e = FourCharsVecSize{12, 12, 10, 10} %
+                     FourCharsVecSize{6, 4, 4, 3};
+  // CHECK: store <4 x i8> <i8 0, i8 0, i8 2, i8 1>
+
+  constexpr auto f = FourCharsVecSize{6, 3, 2, 1} + 3;
+  // CHECK: store <4 x i8> <i8 9, i8 6, i8 5, i8 4>
+  constexpr auto g = FourCharsVecSize{19, 15, 12, 10} - 3;
+  // CHECK: store <4 x i8> <i8 16, i8 12, i8 9, i8 7>
+  constexpr auto h = FourCharsVecSize{8, 4, 2, 1} * 3;
+  // CHECK: store <4 x i8> <i8 24, i8 12, i8 6, i8 3>
+  constexpr auto j = FourCharsVecSize{12, 15, 18, 21} / 3;
+  // CHECK: store <4 x i8> <i8 4, i8 5, i8 6, i8 7>
+  constexpr auto k = FourCharsVecSize{12, 17, 19, 22} % 3;
+  // CHECK: store <4 x i8> <i8 0, i8 2, i8 1, i8 1>
+
+  constexpr auto l = 3 + FourCharsVecSize{6, 3, 2, 1};
+  // CHECK: store <4 x i8> <i8 9, i8 6, i8 5, i8 4>
+  constexpr auto m = 20 - FourCharsVecSize{19, 15, 12, 10};
+  // CHECK: store <4 x i8> <i8 1, i8 5, i8 8, i8 10>
+  constexpr auto n = 3 * FourCharsVecSize{8, 4, 2, 1};
+  // CHECK: store <4 x i8> <i8 24, i8 12, i8 6, i8 3>
+  constexpr auto o = 100 / FourCharsVecSize{12, 15, 18, 21};
+  // CHECK: store <4 x i8> <i8 8, i8 6, i8 5, i8 4>
+  constexpr auto p = 100 % FourCharsVecSize{12, 15, 18, 21};
+  // CHECK: store <4 x i8> <i8 4, i8 10, i8 10, i8 16>
+
+  constexpr auto q = FourCharsVecSize{6, 3, 2, 1} << FourCharsVecSize{1, 1, 2, 2};
+  // CHECK: store <4 x i8> <i8 12, i8 6, i8 8, i8 4>
+  constexpr auto r = FourCharsVecSize{19, 15, 12, 10} >>
+                     FourCharsVecSize{1, 1, 2, 2};
+  // CHECK: store <4 x i8> <i8 9, i8 7, i8 3, i8 2>
+  constexpr auto s = FourCharsVecSize{6, 3, 5, 10} << 1;
+  // CHECK: store <4 x i8> <i8 12, i8 6, i8 10, i8 20>
+  constexpr auto t = FourCharsVecSize{19, 15, 10, 20} >> 1;
+  // CHECK: store <4 x i8> <i8 9, i8 7, i8 5, i8 10>
+  constexpr auto u = 12 << FourCharsVecSize{1, 2, 3, 3};
+  // CHECK: store <4 x i8> <i8 24, i8 48, i8 96, i8 96>
+  constexpr auto v = 12 >> FourCharsVecSize{1, 2, 2, 1};
+  // CHECK: store <4 x i8> <i8 6, i8 3, i8 3, i8 6>
+
+  constexpr auto w = FourCharsVecSize{1, 2, 3, 4} <
+                     FourCharsVecSize{4, 3, 2, 1};
+  // CHECK: store <4 x i8> <i8 1, i8 1, i8 0, i8 0>
+  constexpr auto x = FourCharsVecSize{1, 2, 3, 4} >
+                     FourCharsVecSize{4, 3, 2, 1};
+  // CHECK: store <4 x i8> <i8 0, i8 0, i8 1, i8 1>
+  constexpr auto y = FourCharsVecSize{1, 2, 3, 4} <=
+                     FourCharsVecSize{4, 3, 3, 1};
+  // CHECK: store <4 x i8> <i8 1, i8 1, i8 1, i8 0>
+  constexpr auto z = FourCharsVecSize{1, 2, 3, 4} >=
+                     FourCharsVecSize{4, 3, 3, 1};
+  // CHECK: store <4 x i8> <i8 0, i8 0, i8 1, i8 1>
+  constexpr auto A = FourCharsVecSize{1, 2, 3, 4} ==
+                     FourCharsVecSize{4, 3, 3, 1};
+  // CHECK: store <4 x i8> <i8 0, i8 0, i8 1, i8 0>
+  constexpr auto B = FourCharsVecSize{1, 2, 3, 4} !=
+                     FourCharsVecSize{4, 3, 3, 1};
+  // CHECK: store <4 x i8> <i8 1, i8 1, i8 0, i8 1>
+
+  constexpr auto C = FourCharsVecSize{1, 2, 3, 4} < 3;
+  // CHECK: store <4 x i8> <i8 1, i8 1, i8 0, i8 0>
+  constexpr auto D = FourCharsVecSize{1, 2, 3, 4} > 3;
+  // CHECK: store <4 x i8> <i8 0, i8 0, i8 0, i8 1>
+  constexpr auto E = FourCharsVecSize{1, 2, 3, 4} <= 3;
+  // CHECK: store <4 x i8> <i8 1, i8 1, i8 1, i8 0>
+  constexpr auto F = FourCharsVecSize{1, 2, 3, 4} >= 3;
+  // CHECK: store <4 x i8> <i8 0, i8 0, i8 1, i8 1>
+  constexpr auto G = FourCharsVecSize{1, 2, 3, 4} == 3;
+  // CHECK: store <4 x i8> <i8 0, i8 0, i8 1, i8 0>
+  constexpr auto H = FourCharsVecSize{1, 2, 3, 4} != 3;
+  // CHECK: store <4 x i8> <i8 1, i8 1, i8 0, i8 1>
+
+  constexpr auto I = FourCharsVecSize{1, 2, 3, 4} &
+                     FourCharsVecSize{4, 3, 2, 1};
+  // CHECK: store <4 x i8> <i8 0, i8 2, i8 2, i8 0>
+  constexpr auto J = FourCharsVecSize{1, 2, 3, 4} ^
+                     FourCharsVecSize { 4, 3, 2, 1 };
+  // CHECK: store <4 x i8> <i8 5, i8 1, i8 1, i8 5>
+  constexpr auto K = FourCharsVecSize{1, 2, 3, 4} |
+                     FourCharsVecSize{4, 3, 2, 1};
+  // CHECK: store <4 x i8> <i8 5, i8 3, i8 3, i8 5>
+  constexpr auto L = FourCharsVecSize{1, 2, 3, 4} & 3;
+  // CHECK: store <4 x i8> <i8 1, i8 2, i8 3, i8 0>
+  constexpr auto M = FourCharsVecSize{1, 2, 3, 4} ^ 3;
+  // CHECK: store <4 x i8> <i8 2, i8 1, i8 0, i8 7>
+  constexpr auto N = FourCharsVecSize{1, 2, 3, 4} | 3;
+  // CHECK: store <4 x i8> <i8 3, i8 3, i8 3, i8 7>
+
+  constexpr auto O = FourCharsVecSize{5, 0, 6, 0} &&
+                     FourCharsVecSize{5, 5, 0, 0};
+  // CHECK: store <4 x i8> <i8 1, i8 0, i8 0, i8 0>
+  constexpr auto P = FourCharsVecSize{5, 0, 6, 0} ||
+                     FourCharsVecSize{5, 5, 0, 0};
+  // CHECK: store <4 x i8> <i8 1, i8 1, i8 1, i8 0>
+
+  constexpr auto Q = FourCharsVecSize{5, 0, 6, 0} && 3;
+  // CHECK: store <4 x i8> <i8 1, i8 0, i8 1, i8 0>
+  constexpr auto R = FourCharsVecSize{5, 0, 6, 0} || 3;
+  // CHECK: store <4 x i8> <i8 1, i8 1, i8 1, i8 1>
+
+  constexpr auto T = CmpMul(a, b);
+  // CHECK: store <4 x i8> <i8 108, i8 18, i8 56, i8 72>
+
+  constexpr auto U = CmpDiv(a, b);
+  // CHECK: store <4 x i8> <i8 3, i8 18, i8 0, i8 0>
+
+  constexpr auto V = CmpRem(a, b);
+  // CHECK: store <4 x i8> <i8 0, i8 0, i8 7, i8 8>
+
+  constexpr auto X = CmpAdd(a, b);
+  // CHECK: store <4 x i8> <i8 24, i8 19, i8 15, i8 17>
+
+  constexpr auto Y = CmpSub(a, b);
+  // CHECK: store <4 x i8> <i8 12, i8 17, i8 -1, i8 -1>
+
+  constexpr auto Z = CmpLSH(a, H);
+  // CHECK: store <4 x i8> <i8 36, i8 36, i8 7, i8 16>
+
+  constexpr auto aa = CmpRSH(a, H);
+  // CHECK: store <4 x i8> <i8 9, i8 9, i8 7, i8 4>
+
+  constexpr auto ab = CmpBinAnd(a, b);
+  // CHECK: store <4 x i8> <i8 2, i8 0, i8 0, i8 8>
+
+  constexpr auto ac = CmpBinXOr(a, b);
+  // CHECK: store <4 x i8> <i8 20, i8 19, i8 15, i8 1>
+
+  constexpr auto ad = CmpBinOr(a, b);
+  // CHECK: store <4 x i8> <i8 22, i8 19, i8 15, i8 9>
+}
+
+void CharExtVecUsage() {
+  constexpr auto a = FourCharsExtVec{6, 3, 2, 1} +
+                     FourCharsExtVec{12, 15, 5, 7};
+  // CHECK: store <4 x i8> <i8 18, i8 18, i8 7, i8 8>
+  constexpr auto b = FourCharsExtVec{19, 15, 13, 12} -
+                     FourCharsExtVec{13, 14, 5, 3};
+  // CHECK: store <4 x i8> <i8 6, i8 1, i8 8, i8 9>
+  constexpr auto c = FourCharsExtVec{8, 4, 2, 1} *
+                     FourCharsExtVec{3, 4, 5, 6};
+  // CHECK: store <4 x i8> <i8 24, i8 16, i8 10, i8 6>
+  constexpr auto d = FourCharsExtVec{12, 12, 10, 10} /
+                     FourCharsExtVec{6, 4, 5, 2};
+  // CHECK: store <4 x i8> <i8 2, i8 3, i8 2, i8 5>
+  constexpr auto e = FourCharsExtVec{12, 12, 10, 10} %
+                     FourCharsExtVec{6, 4, 4, 3};
+  // CHECK: store <4 x i8> <i8 0, i8 0, i8 2, i8 1>
+
+  constexpr auto f = FourCharsExtVec{6, 3, 2, 1} + 3;
+  // CHECK: store <4 x i8> <i8 9, i8 6, i8 5, i8 4>
+  constexpr auto g = FourCharsExtVec{19, 15, 12, 10} - 3;
+  // CHECK: store <4 x i8> <i8 16, i8 12, i8 9, i8 7>
+  constexpr auto h = FourCharsExtVec{8, 4, 2, 1} * 3;
+  // CHECK: store <4 x i8> <i8 24, i8 12, i8 6, i8 3>
+  constexpr auto j = FourCharsExtVec{12, 15, 18, 21} / 3;
+  // CHECK: store <4 x i8> <i8 4, i8 5, i8 6, i8 7>
+  constexpr auto k = FourCharsExtVec{12, 17, 19, 22} % 3;
+  // CHECK: store <4 x i8> <i8 0, i8 2, i8 1, i8 1>
+
+  constexpr auto l = 3 + FourCharsExtVec{6, 3, 2, 1};
+  // CHECK: store <4 x i8> <i8 9, i8 6, i8 5, i8 4>
+  constexpr auto m = 20 - FourCharsExtVec{19, 15, 12, 10};
+  // CHECK: store <4 x i8> <i8 1, i8 5, i8 8, i8 10>
+  constexpr auto n = 3 * FourCharsExtVec{8, 4, 2, 1};
+  // CHECK: store <4 x i8> <i8 24, i8 12, i8 6, i8 3>
+  constexpr auto o = 100 / FourCharsExtVec{12, 15, 18, 21};
+  // CHECK: store <4 x i8> <i8 8, i8 6, i8 5, i8 4>
+  constexpr auto p = 100 % FourCharsExtVec{12, 15, 18, 21};
+  // CHECK: store <4 x i8> <i8 4, i8 10, i8 10, i8 16>
+
+  constexpr auto q = FourCharsExtVec{6, 3, 2, 1} << FourCharsVecSize{1, 1, 2, 2};
+  // CHECK: store <4 x i8> <i8 12, i8 6, i8 8, i8 4>
+  constexpr auto r = FourCharsExtVec{19, 15, 12, 10} >>
+                     FourCharsExtVec{1, 1, 2, 2};
+  // CHECK: store <4 x i8> <i8 9, i8 7, i8 3, i8 2>
+  constexpr auto s = FourCharsExtVec{6, 3, 5, 10} << 1;
+  // CHECK: store <4 x i8> <i8 12, i8 6, i8 10, i8 20>
+  constexpr auto t = FourCharsExtVec{19, 15, 10, 20} >> 1;
+  // CHECK: store <4 x i8> <i8 9, i8 7, i8 5, i8 10>
+  constexpr auto u = 12 << FourCharsExtVec{1, 2, 3, 3};
+  // CHECK: store <4 x i8> <i8 24, i8 48, i8 96, i8 96>
+  constexpr auto v = 12 >> FourCharsExtVec{1, 2, 2, 1};
+  // CHECK: store <4 x i8> <i8 6, i8 3, i8 3, i8 6>
+
+  constexpr auto w = FourCharsExtVec{1, 2, 3, 4} <
+                     FourCharsExtVec{4, 3, 2, 1};
+  // CHECK: store <4 x i8> <i8 1, i8 1, i8 0, i8 0>
+  constexpr auto x = FourCharsExtVec{1, 2, 3, 4} >
+                     FourCharsExtVec{4, 3, 2, 1};
+  // CHECK: store <4 x i8> <i8 0, i8 0, i8 1, i8 1>
+  constexpr auto y = FourCharsExtVec{1, 2, 3, 4} <=
+                     FourCharsExtVec{4, 3, 3, 1};
+  // CHECK: store <4 x i8> <i8 1, i8 1, i8 1, i8 0>
+  constexpr auto z = FourCharsExtVec{1, 2, 3, 4} >=
+                     FourCharsExtVec{4, 3, 3, 1};
+  // CHECK: store <4 x i8> <i8 0, i8 0, i8 1, i8 1>
+  constexpr auto A = FourCharsExtVec{1, 2, 3, 4} ==
+                     FourCharsExtVec{4, 3, 3, 1};
+  // CHECK: store <4 x i8> <i8 0, i8 0, i8 1, i8 0>
+  constexpr auto B = FourCharsExtVec{1, 2, 3, 4} !=
+                     FourCharsExtVec{4, 3, 3, 1};
+  // CHECK: store <4 x i8> <i8 1, i8 1, i8 0, i8 1>
+
+  constexpr auto C = FourCharsExtVec{1, 2, 3, 4} < 3;
+  // CHECK: store <4 x i8> <i8 1, i8 1, i8 0, i8 0>
+  constexpr auto D = FourCharsExtVec{1, 2, 3, 4} > 3;
+  // CHECK: store <4 x i8> <i8 0, i8 0, i8 0, i8 1>
+  constexpr auto E = FourCharsExtVec{1, 2, 3, 4} <= 3;
+  // CHECK: store <4 x i8> <i8 1, i8 1, i8 1, i8 0>
+  constexpr auto F = FourCharsExtVec{1, 2, 3, 4} >= 3;
+  // CHECK: store <4 x i8> <i8 0, i8 0, i8 1, i8 1>
+  constexpr auto G = FourCharsExtVec{1, 2, 3, 4} == 3;
+  // CHECK: store <4 x i8> <i8 0, i8 0, i8 1, i8 0>
+  constexpr auto H = FourCharsExtVec{1, 2, 3, 4} != 3;
+  // CHECK: store <4 x i8> <i8 1, i8 1, i8 0, i8 1>
+
+  constexpr auto I = FourCharsExtVec{1, 2, 3, 4} &
+                     FourCharsExtVec{4, 3, 2, 1};
+  // CHECK: store <4 x i8> <i8 0, i8 2, i8 2, i8 0>
+  constexpr auto J = FourCharsExtVec{1, 2, 3, 4} ^
+                     FourCharsExtVec { 4, 3, 2, 1 };
+  // CHECK: store <4 x i8> <i8 5, i8 1, i8 1, i8 5>
+  constexpr auto K = FourCharsExtVec{1, 2, 3, 4} |
+                     FourCharsExtVec{4, 3, 2, 1};
+  // CHECK: store <4 x i8> <i8 5, i8 3, i8 3, i8 5>
+  constexpr auto L = FourCharsExtVec{1, 2, 3, 4} & 3;
+  // CHECK: store <4 x i8> <i8 1, i8 2, i8 3, i8 0>
+  constexpr auto M = FourCharsExtVec{1, 2, 3, 4} ^ 3;
+  // CHECK: store <4 x i8> <i8 2, i8 1, i8 0, i8 7>
+  constexpr auto N = FourCharsExtVec{1, 2, 3, 4} | 3;
+  // CHECK: store <4 x i8> <i8 3, i8 3, i8 3, i8 7>
+
+  constexpr auto O = FourCharsExtVec{5, 0, 6, 0} &&
+                     FourCharsExtVec{5, 5, 0, 0};
+  // CHECK: store <4 x i8> <i8 1, i8 0, i8 0, i8 0>
+  constexpr auto P = FourCharsExtVec{5, 0, 6, 0} ||
+                     FourCharsExtVec{5, 5, 0, 0};
+  // CHECK: store <4 x i8> <i8 1, i8 1, i8 1, i8 0>
+
+  constexpr auto Q = FourCharsExtVec{5, 0, 6, 0} && 3;
+  // CHECK: store <4 x i8> <i8 1, i8 0, i8 1, i8 0>
+  constexpr auto R = FourCharsExtVec{5, 0, 6, 0} || 3;
+  // CHECK: store <4 x i8> <i8 1, i8 1, i8 1, i8 1>
+
+  constexpr auto T = CmpMul(a, b);
+  // CHECK: store <4 x i8> <i8 108, i8 18, i8 56, i8 72>
+
+  constexpr auto U = CmpDiv(a, b);
+  // CHECK: store <4 x i8> <i8 3, i8 18, i8 0, i8 0>
+
+  constexpr auto V = CmpRem(a, b);
+  // CHECK: store <4 x i8> <i8 0, i8 0, i8 7, i8 8>
+
+  constexpr auto X = CmpAdd(a, b);
+  // CHECK: store <4 x i8> <i8 24, i8 19, i8 15, i8 17>
+
+  constexpr auto Y = CmpSub(a, b);
+  // CHECK: store <4 x i8> <i8 12, i8 17, i8 -1, i8 -1>
+
+  constexpr auto Z = CmpLSH(a, H);
+  // CHECK: store <4 x i8> <i8 36, i8 36, i8 7, i8 16>
+
+  constexpr auto aa = CmpRSH(a, H);
+  // CHECK: store <4 x i8> <i8 9, i8 9, i8 7, i8 4>
+
+  constexpr auto ab = CmpBinAnd(a, b);
+  // CHECK: store <4 x i8> <i8 2, i8 0, i8 0, i8 8>
+
+  constexpr auto ac = CmpBinXOr(a, b);
+  // CHECK: store <4 x i8> <i8 20, i8 19, i8 15, i8 1>
+
+  constexpr auto ad = CmpBinOr(a, b);
+  // CHECK: store <4 x i8> <i8 22, i8 19, i8 15, i8 9>
+}
+
+void FloatUsage() {
+  constexpr auto a = FourFloatsVecSize{6, 3, 2, 1} +
+                     FourFloatsVecSize{12, 15, 5, 7};
+  // CHECK: <4 x float> <float 1.800000e+01, float 1.800000e+01, float 7.000000e+00, float 8.000000e+00>
+  constexpr auto b = FourFloatsVecSize{19, 15, 13, 12} -
+                     FourFloatsVecSize{13, 14, 5, 3};
+  // CHECK: store <4 x float> <float 6.000000e+00, float 1.000000e+00, float 8.000000e+00, float 9.000000e+00>
+  constexpr auto c = FourFloatsVecSize{8, 4, 2, 1} *
+                     FourFloatsVecSize{3, 4, 5, 6};
+  // CHECK: store <4 x float> <float 2.400000e+01, float 1.600000e+01, float 1.000000e+01, float 6.000000e+00>
+  constexpr auto d = FourFloatsVecSize{12, 12, 10, 10} /
+                     FourFloatsVecSize{6, 4, 5, 2};
+  // CHECK: store <4 x float> <float 2.000000e+00, float 3.000000e+00, float 2.000000e+00, float 5.000000e+00>
+
+  constexpr auto f = FourFloatsVecSize{6, 3, 2, 1} + 3;
+  // CHECK: store <4 x float> <float 9.000000e+00, float 6.000000e+00, float 5.000000e+00, float 4.000000e+00>
+  constexpr auto g = FourFloatsVecSize{19, 15, 12, 10} - 3;
+  // CHECK: store <4 x float> <float 1.600000e+01, float 1.200000e+01, float 9.000000e+00, float 7.000000e+00>
+  constexpr auto h = FourFloatsVecSize{8, 4, 2, 1} * 3;
+  // CHECK: store <4 x float> <float 2.400000e+01, float 1.200000e+01, float 6.000000e+00, float 3.000000e+00>
+  constexpr auto j = FourFloatsVecSize{12, 15, 18, 21} / 3;
+  // CHECK: store <4 x float> <float 4.000000e+00, float 5.000000e+00, float 6.000000e+00, float 7.000000e+00>
+
+  constexpr auto l = 3 + FourFloatsVecSize{6, 3, 2, 1};
+  // CHECK: store <4 x float> <float 9.000000e+00, float 6.000000e+00, float 5.000000e+00, float 4.000000e+00>
+  constexpr auto m = 20 - FourFloatsVecSize{19, 15, 12, 10};
+  // CHECK: store <4 x float> <float 1.000000e+00, float 5.000000e+00, float 8.000000e+00, float 1.000000e+01>
+  constexpr auto n = 3 * FourFloatsVecSize{8, 4, 2, 1};
+  // CHECK: store <4 x float> <float 2.400000e+01, float 1.200000e+01, float 6.000000e+00, float 3.000000e+00>
+  constexpr auto o = 100 / FourFloatsVecSize{12, 15, 18, 21};
+  // CHECK: store <4 x float> <float 0x4020AAAAA0000000, float 0x401AAAAAA0000000, float 0x401638E380000000, float 0x40130C30C0000000>
+
+  constexpr auto w = FourFloatsVecSize{1, 2, 3, 4} <
+                     FourFloatsVecSize{4, 3, 2, 1};
+  // CHECK: store <4 x i32> <i32 1, i32 1, i32 0, i32 0>
+  constexpr auto x = FourFloatsVecSize{1, 2, 3, 4} >
+                     FourFloatsVecSize{4, 3, 2, 1};
+  // CHECK: store <4 x i32> <i32 0, i32 0, i32 1, i32 1>
+  constexpr auto y = FourFloatsVecSize{1, 2, 3, 4} <=
+                     FourFloatsVecSize{4, 3, 3, 1};
+  // CHECK: store <4 x i32> <i32 1, i32 1, i32 1, i32 0>
+  constexpr auto z = FourFloatsVecSize{1, 2, 3, 4} >=
+                     FourFloatsVecSize{4, 3, 3, 1};
+  // CHECK: store <4 x i32> <i32 0, i32 0, i32 1, i32 1>
+  constexpr auto A = FourFloatsVecSize{1, 2, 3, 4} ==
+                     FourFloatsVecSize{4, 3, 3, 1};
+  // CHECK: store <4 x i32> <i32 0, i32 0, i32 1, i32 0>
+  constexpr auto B = FourFloatsVecSize{1, 2, 3, 4} !=
+                     FourFloatsVecSize{4, 3, 3, 1};
+  // CHECK: store <4 x i32> <i32 1, i32 1, i32 0, i32 1>
+
+  constexpr auto C = FourFloatsVecSize{1, 2, 3, 4} < 3;
+  // CHECK: store <4 x i32> <i32 1, i32 1, i32 0, i32 0>
+  constexpr auto D = FourFloatsVecSize{1, 2, 3, 4} > 3;
+  // CHECK: store <4 x i32> <i32 0, i32 0, i32 0, i32 1>
+  constexpr auto E = FourFloatsVecSize{1, 2, 3, 4} <= 3;
+  // CHECK: store <4 x i32> <i32 1, i32 1, i32 1, i32 0>
+  constexpr auto F = FourFloatsVecSize{1, 2, 3, 4} >= 3;
+  // CHECK: store <4 x i32> <i32 0, i32 0, i32 1, i32 1>
+  constexpr auto G = FourFloatsVecSize{1, 2, 3, 4} == 3;
+  // CHECK: store <4 x i32> <i32 0, i32 0, i32 1, i32 0>
+  constexpr auto H = FourFloatsVecSize{1, 2, 3, 4} != 3;
+  // CHECK: store <4 x i32> <i32 1, i32 1, i32 0, i32 1>
+
+  constexpr auto O = FourFloatsVecSize{5, 0, 6, 0} &&
+                     FourFloatsVecSize{5, 5, 0, 0};
+  // CHECK: store <4 x i32> <i32 1, i32 0, i32 0, i32 0>
+  constexpr auto P = FourFloatsVecSize{5, 0, 6, 0} ||
+                     FourFloatsVecSize{5, 5, 0, 0};
+  // CHECK: store <4 x i32> <i32 1, i32 1, i32 1, i32 0>
+
+  constexpr auto Q = FourFloatsVecSize{5, 0, 6, 0} && 3;
+  // CHECK: store <4 x i32> <i32 1, i32 0, i32 1, i32 0>
+  constexpr auto R = FourFloatsVecSize{5, 0, 6, 0} || 3;
+  // CHECK: store <4 x i32> <i32 1, i32 1, i32 1, i32 1>
+
+  constexpr auto T = CmpMul(a, b);
+  // CHECK: store <4 x float> <float 1.080000e+02, float 1.800000e+01, float 5.600000e+01, float 7.200000e+01>
+
+  constexpr auto U = CmpDiv(a, b);
+  // CHECK: store <4 x float> <float 3.000000e+00, float 1.800000e+01, float 8.750000e-01, float 0x3FEC71C720000000>
+
+  constexpr auto X = CmpAdd(a, b);
+  // CHECK: store <4 x float> <float 2.400000e+01, float 1.900000e+01, float 1.500000e+01, float 1.700000e+01>
+
+  constexpr auto Y = CmpSub(a, b);
+  // CHECK: store <4 x float> <float 1.200000e+01, float 1.700000e+01, float -1.000000e+00, float -1.000000e+00>
+}
+
+void FloatVecUsage() {
+  constexpr auto a = FourFloatsVecSize{6, 3, 2, 1} +
+                     FourFloatsVecSize{12, 15, 5, 7};
+  // CHECK: <4 x float> <float 1.800000e+01, float 1.800000e+01, float 7.000000e+00, float 8.000000e+00>
+  constexpr auto b = FourFloatsVecSize{19, 15, 13, 12} -
+                     FourFloatsVecSize{13, 14, 5, 3};
+  // CHECK: store <4 x float> <float 6.000000e+00, float 1.000000e+00, float 8.000000e+00, float 9.000000e+00>
+  constexpr auto c = FourFloatsVecSize{8, 4, 2, 1} *
+                     FourFloatsVecSize{3, 4, 5, 6};
+  // CHECK: store <4 x float> <float 2.400000e+01, float 1.600000e+01, float 1.000000e+01, float 6.000000e+00>
+  constexpr auto d = FourFloatsVecSize{12, 12, 10, 10} /
+                     FourFloatsVecSize{6, 4, 5, 2};
+  // CHECK: store <4 x float> <float 2.000000e+00, float 3.000000e+00, float 2.000000e+00, float 5.000000e+00>
+
+  constexpr auto f = FourFloatsVecSize{6, 3, 2, 1} + 3;
+  // CHECK: store <4 x float> <float 9.000000e+00, float 6.000000e+00, float 5.000000e+00, float 4.000000e+00>
+  constexpr auto g = FourFloatsVecSize{19, 15, 12, 10} - 3;
+  // CHECK: store <4 x float> <float 1.600000e+01, float 1.200000e+01, float 9.000000e+00, float 7.000000e+00>
+  constexpr auto h = FourFloatsVecSize{8, 4, 2, 1} * 3;
+  // CHECK: store <4 x float> <float 2.400000e+01, float 1.200000e+01, float 6.000000e+00, float 3.000000e+00>
+  constexpr auto j = FourFloatsVecSize{12, 15, 18, 21} / 3;
+  // CHECK: store <4 x float> <float 4.000000e+00, float 5.000000e+00, float 6.000000e+00, float 7.000000e+00>
+
+  constexpr auto l = 3 + FourFloatsVecSize{6, 3, 2, 1};
+  // CHECK: store <4 x float> <float 9.000000e+00, float 6.000000e+00, float 5.000000e+00, float 4.000000e+00>
+  constexpr auto m = 20 - FourFloatsVecSize{19, 15, 12, 10};
+  // CHECK: store <4 x float> <float 1.000000e+00, float 5.000000e+00, float 8.000000e+00, float 1.000000e+01>
+  constexpr auto n = 3 * FourFloatsVecSize{8, 4, 2, 1};
+  // CHECK: store <4 x float> <float 2.400000e+01, float 1.200000e+01, float 6.000000e+00, float 3.000000e+00>
+  constexpr auto o = 100 / FourFloatsVecSize{12, 15, 18, 21};
+  // CHECK: store <4 x float> <float 0x4020AAAAA0000000, float 0x401AAAAAA0000000, float 0x401638E380000000, float 0x40130C30C0000000>
+
+  constexpr auto w = FourFloatsVecSize{1, 2, 3, 4} <
+                     FourFloatsVecSize{4, 3, 2, 1};
+  // CHECK: store <4 x i32> <i32 1, i32 1, i32 0, i32 0>
+  constexpr auto x = FourFloatsVecSize{1, 2, 3, 4} >
+                     FourFloatsVecSize{4, 3, 2, 1};
+  // CHECK: store <4 x i32> <i32 0, i32 0, i32 1, i32 1>
+  constexpr auto y = FourFloatsVecSize{1, 2, 3, 4} <=
+                     FourFloatsVecSize{4, 3, 3, 1};
+  // CHECK: store <4 x i32> <i32 1, i32 1, i32 1, i32 0>
+  constexpr auto z = FourFloatsVecSize{1, 2, 3, 4} >=
+                     FourFloatsVecSize{4, 3, 3, 1};
+  // CHECK: store <4 x i32> <i32 0, i32 0, i32 1, i32 1>
+  constexpr auto A = FourFloatsVecSize{1, 2, 3, 4} ==
+                     FourFloatsVecSize{4, 3, 3, 1};
+  // CHECK: store <4 x i32> <i32 0, i32 0, i32 1, i32 0>
+  constexpr auto B = FourFloatsVecSize{1, 2, 3, 4} !=
+                     FourFloatsVecSize{4, 3, 3, 1};
+  // CHECK: store <4 x i32> <i32 1, i32 1, i32 0, i32 1>
+
+  constexpr auto C = FourFloatsVecSize{1, 2, 3, 4} < 3;
+  // CHECK: store <4 x i32> <i32 1, i32 1, i32 0, i32 0>
+  constexpr auto D = FourFloatsVecSize{1, 2, 3, 4} > 3;
+  // CHECK: store <4 x i32> <i32 0, i32 0, i32 0, i32 1>
+  constexpr auto E = FourFloatsVecSize{1, 2, 3, 4} <= 3;
+  // CHECK: store <4 x i32> <i32 1, i32 1, i32 1, i32 0>
+  constexpr auto F = FourFloatsVecSize{1, 2, 3, 4} >= 3;
+  // CHECK: store <4 x i32> <i32 0, i32 0, i32 1, i32 1>
+  constexpr auto G = FourFloatsVecSize{1, 2, 3, 4} == 3;
+  // CHECK: store <4 x i32> <i32 0, i32 0, i32 1, i32 0>
+  constexpr auto H = FourFloatsVecSize{1, 2, 3, 4} != 3;
+  // CHECK: store <4 x i32> <i32 1, i32 1, i32 0, i32 1>
+
+  constexpr auto O = FourFloatsVecSize{5, 0, 6, 0} &&
+                     FourFloatsVecSize{5, 5, 0, 0};
+  // CHECK: store <4 x i32> <i32 1, i32 0, i32 0, i32 0>
+  constexpr auto P = FourFloatsVecSize{5, 0, 6, 0} ||
+                     FourFloatsVecSize{5, 5, 0, 0};
+  // CHECK: store <4 x i32> <i32 1, i32 1, i32 1, i32 0>
+
+  constexpr auto Q = FourFloatsVecSize{5, 0, 6, 0} && 3;
+  // CHECK: store <4 x i32> <i32 1, i32 0, i32 1, i32 0>
+  constexpr auto R = FourFloatsVecSize{5, 0, 6, 0} || 3;
+  // CHECK: store <4 x i32> <i32 1, i32 1, i32 1, i32 1>
+
+  constexpr auto T = CmpMul(a, b);
+  // CHECK: store <4 x float> <float 1.080000e+02, float 1.800000e+01, float 5.600000e+01, float 7.200000e+01>
+
+  constexpr auto U = CmpDiv(a, b);
+  // CHECK: store <4 x float> <float 3.000000e+00, float 1.800000e+01, float 8.750000e-01, float 0x3FEC71C720000000>
+
+  constexpr auto X = CmpAdd(a, b);
+  // CHECK: store <4 x float> <float 2.400000e+01, float 1.900000e+01, float 1.500000e+01, float 1.700000e+01>
+
+  constexpr auto Y = CmpSub(a, b);
+  // CHECK: store <4 x float> <float 1.200000e+01, float 1.700000e+01, float -1.000000e+00, float -1.000000e+00>
+}


        


More information about the cfe-commits mailing list