Index: clang/lib/AST/ExprConstant.cpp =================================================================== --- clang/lib/AST/ExprConstant.cpp +++ clang/lib/AST/ExprConstant.cpp @@ -2664,6 +2664,155 @@ 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 +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(); + 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 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 @@ 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 @@ 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 @@ 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()->getNumElements() == + E->getType()->getAs()->getNumElements() && + RHS->getType()->getAs()->getNumElements() == + E->getType()->getAs()->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 //===----------------------------------------------------------------------===// Index: clang/test/SemaCXX/constexpr-vectors.cpp =================================================================== --- /dev/null +++ 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 +constexpr auto CmpMul(T t, U u) { + t *= u; + return t; +} +template +constexpr auto CmpDiv(T t, U u) { + t /= u; + return t; +} +template +constexpr auto CmpRem(T t, U u) { + t %= u; + return t; +} + +template +constexpr auto CmpAdd(T t, U u) { + t += u; + return t; +} + +template +constexpr auto CmpSub(T t, U u) { + t -= u; + return t; +} + +template +constexpr auto CmpLSH(T t, U u) { + t <<= u; + return t; +} + +template +constexpr auto CmpRSH(T t, U u) { + t >>= u; + return t; +} + +template +constexpr auto CmpBinAnd(T t, U u) { + t &= u; + return t; +} + +template +constexpr auto CmpBinXOr(T t, U u) { + t ^= u; + return t; +} + +template +constexpr auto CmpBinOr(T t, U u) { + t |= u; + return t; +} + +// Only int vs float makes a difference 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> + constexpr auto b = FourCharsVecSize{19, 15, 13, 12} - + FourCharsVecSize{13, 14, 5, 3}; + // CHECK: store <4 x i8> + constexpr auto c = FourCharsVecSize{8, 4, 2, 1} * + FourCharsVecSize{3, 4, 5, 6}; + // CHECK: store <4 x i8> + constexpr auto d = FourCharsVecSize{12, 12, 10, 10} / + FourCharsVecSize{6, 4, 5, 2}; + // CHECK: store <4 x i8> + constexpr auto e = FourCharsVecSize{12, 12, 10, 10} % + FourCharsVecSize{6, 4, 4, 3}; + // CHECK: store <4 x i8> + + constexpr auto f = FourCharsVecSize{6, 3, 2, 1} + 3; + // CHECK: store <4 x i8> + constexpr auto g = FourCharsVecSize{19, 15, 12, 10} - 3; + // CHECK: store <4 x i8> + constexpr auto h = FourCharsVecSize{8, 4, 2, 1} * 3; + // CHECK: store <4 x i8> + constexpr auto j = FourCharsVecSize{12, 15, 18, 21} / 3; + // CHECK: store <4 x i8> + constexpr auto k = FourCharsVecSize{12, 17, 19, 22} % 3; + // CHECK: store <4 x i8> + + constexpr auto l = 3 + FourCharsVecSize{6, 3, 2, 1}; + // CHECK: store <4 x i8> + constexpr auto m = 20 - FourCharsVecSize{19, 15, 12, 10}; + // CHECK: store <4 x i8> + constexpr auto n = 3 * FourCharsVecSize{8, 4, 2, 1}; + // CHECK: store <4 x i8> + constexpr auto o = 100 / FourCharsVecSize{12, 15, 18, 21}; + // CHECK: store <4 x i8> + constexpr auto p = 100 % FourCharsVecSize{12, 15, 18, 21}; + // CHECK: store <4 x i8> + + constexpr auto q = FourCharsVecSize{6, 3, 2, 1} << FourCharsVecSize{1, 1, 2, 2}; + // CHECK: store <4 x i8> + constexpr auto r = FourCharsVecSize{19, 15, 12, 10} >> + FourCharsVecSize{1, 1, 2, 2}; + // CHECK: store <4 x i8> + constexpr auto s = FourCharsVecSize{6, 3, 5, 10} << 1; + // CHECK: store <4 x i8> + constexpr auto t = FourCharsVecSize{19, 15, 10, 20} >> 1; + // CHECK: store <4 x i8> + constexpr auto u = 12 << FourCharsVecSize{1, 2, 3, 3}; + // CHECK: store <4 x i8> + constexpr auto v = 12 >> FourCharsVecSize{1, 2, 2, 1}; + // CHECK: store <4 x i8> + + constexpr auto w = FourCharsVecSize{1, 2, 3, 4} < + FourCharsVecSize{4, 3, 2, 1}; + // CHECK: store <4 x i8> + constexpr auto x = FourCharsVecSize{1, 2, 3, 4} > + FourCharsVecSize{4, 3, 2, 1}; + // CHECK: store <4 x i8> + constexpr auto y = FourCharsVecSize{1, 2, 3, 4} <= + FourCharsVecSize{4, 3, 3, 1}; + // CHECK: store <4 x i8> + constexpr auto z = FourCharsVecSize{1, 2, 3, 4} >= + FourCharsVecSize{4, 3, 3, 1}; + // CHECK: store <4 x i8> + constexpr auto A = FourCharsVecSize{1, 2, 3, 4} == + FourCharsVecSize{4, 3, 3, 1}; + // CHECK: store <4 x i8> + constexpr auto B = FourCharsVecSize{1, 2, 3, 4} != + FourCharsVecSize{4, 3, 3, 1}; + // CHECK: store <4 x i8> + + constexpr auto C = FourCharsVecSize{1, 2, 3, 4} < 3; + // CHECK: store <4 x i8> + constexpr auto D = FourCharsVecSize{1, 2, 3, 4} > 3; + // CHECK: store <4 x i8> + constexpr auto E = FourCharsVecSize{1, 2, 3, 4} <= 3; + // CHECK: store <4 x i8> + constexpr auto F = FourCharsVecSize{1, 2, 3, 4} >= 3; + // CHECK: store <4 x i8> + constexpr auto G = FourCharsVecSize{1, 2, 3, 4} == 3; + // CHECK: store <4 x i8> + constexpr auto H = FourCharsVecSize{1, 2, 3, 4} != 3; + // CHECK: store <4 x i8> + + constexpr auto I = FourCharsVecSize{1, 2, 3, 4} & + FourCharsVecSize{4, 3, 2, 1}; + // CHECK: store <4 x i8> + constexpr auto J = FourCharsVecSize{1, 2, 3, 4} ^ + FourCharsVecSize { 4, 3, 2, 1 }; + // CHECK: store <4 x i8> + constexpr auto K = FourCharsVecSize{1, 2, 3, 4} | + FourCharsVecSize{4, 3, 2, 1}; + // CHECK: store <4 x i8> + constexpr auto L = FourCharsVecSize{1, 2, 3, 4} & 3; + // CHECK: store <4 x i8> + constexpr auto M = FourCharsVecSize{1, 2, 3, 4} ^ 3; + // CHECK: store <4 x i8> + constexpr auto N = FourCharsVecSize{1, 2, 3, 4} | 3; + // CHECK: store <4 x i8> + + constexpr auto O = FourCharsVecSize{5, 0, 6, 0} && + FourCharsVecSize{5, 5, 0, 0}; + // CHECK: store <4 x i8> + constexpr auto P = FourCharsVecSize{5, 0, 6, 0} || + FourCharsVecSize{5, 5, 0, 0}; + // CHECK: store <4 x i8> + + constexpr auto Q = FourCharsVecSize{5, 0, 6, 0} && 3; + // CHECK: store <4 x i8> + constexpr auto R = FourCharsVecSize{5, 0, 6, 0} || 3; + // CHECK: store <4 x i8> + + constexpr auto T = CmpMul(a, b); + // CHECK: store <4 x i8> + + constexpr auto U = CmpDiv(a, b); + // CHECK: store <4 x i8> + + constexpr auto V = CmpRem(a, b); + // CHECK: store <4 x i8> + + constexpr auto X = CmpAdd(a, b); + // CHECK: store <4 x i8> + + constexpr auto Y = CmpSub(a, b); + // CHECK: store <4 x i8> + + constexpr auto Z = CmpLSH(a, H); + // CHECK: store <4 x i8> + + constexpr auto aa = CmpRSH(a, H); + // CHECK: store <4 x i8> + + constexpr auto ab = CmpBinAnd(a, b); + // CHECK: store <4 x i8> + + constexpr auto ac = CmpBinXOr(a, b); + // CHECK: store <4 x i8> + + constexpr auto ad = CmpBinOr(a, b); + // CHECK: store <4 x i8> +} + +void CharExtVecUsage() { + constexpr auto a = FourCharsExtVec{6, 3, 2, 1} + + FourCharsExtVec{12, 15, 5, 7}; + // CHECK: store <4 x i8> + constexpr auto b = FourCharsExtVec{19, 15, 13, 12} - + FourCharsExtVec{13, 14, 5, 3}; + // CHECK: store <4 x i8> + constexpr auto c = FourCharsExtVec{8, 4, 2, 1} * + FourCharsExtVec{3, 4, 5, 6}; + // CHECK: store <4 x i8> + constexpr auto d = FourCharsExtVec{12, 12, 10, 10} / + FourCharsExtVec{6, 4, 5, 2}; + // CHECK: store <4 x i8> + constexpr auto e = FourCharsExtVec{12, 12, 10, 10} % + FourCharsExtVec{6, 4, 4, 3}; + // CHECK: store <4 x i8> + + constexpr auto f = FourCharsExtVec{6, 3, 2, 1} + 3; + // CHECK: store <4 x i8> + constexpr auto g = FourCharsExtVec{19, 15, 12, 10} - 3; + // CHECK: store <4 x i8> + constexpr auto h = FourCharsExtVec{8, 4, 2, 1} * 3; + // CHECK: store <4 x i8> + constexpr auto j = FourCharsExtVec{12, 15, 18, 21} / 3; + // CHECK: store <4 x i8> + constexpr auto k = FourCharsExtVec{12, 17, 19, 22} % 3; + // CHECK: store <4 x i8> + + constexpr auto l = 3 + FourCharsExtVec{6, 3, 2, 1}; + // CHECK: store <4 x i8> + constexpr auto m = 20 - FourCharsExtVec{19, 15, 12, 10}; + // CHECK: store <4 x i8> + constexpr auto n = 3 * FourCharsExtVec{8, 4, 2, 1}; + // CHECK: store <4 x i8> + constexpr auto o = 100 / FourCharsExtVec{12, 15, 18, 21}; + // CHECK: store <4 x i8> + constexpr auto p = 100 % FourCharsExtVec{12, 15, 18, 21}; + // CHECK: store <4 x i8> + + constexpr auto q = FourCharsExtVec{6, 3, 2, 1} << FourCharsVecSize{1, 1, 2, 2}; + // CHECK: store <4 x i8> + constexpr auto r = FourCharsExtVec{19, 15, 12, 10} >> + FourCharsExtVec{1, 1, 2, 2}; + // CHECK: store <4 x i8> + constexpr auto s = FourCharsExtVec{6, 3, 5, 10} << 1; + // CHECK: store <4 x i8> + constexpr auto t = FourCharsExtVec{19, 15, 10, 20} >> 1; + // CHECK: store <4 x i8> + constexpr auto u = 12 << FourCharsExtVec{1, 2, 3, 3}; + // CHECK: store <4 x i8> + constexpr auto v = 12 >> FourCharsExtVec{1, 2, 2, 1}; + // CHECK: store <4 x i8> + + constexpr auto w = FourCharsExtVec{1, 2, 3, 4} < + FourCharsExtVec{4, 3, 2, 1}; + // CHECK: store <4 x i8> + constexpr auto x = FourCharsExtVec{1, 2, 3, 4} > + FourCharsExtVec{4, 3, 2, 1}; + // CHECK: store <4 x i8> + constexpr auto y = FourCharsExtVec{1, 2, 3, 4} <= + FourCharsExtVec{4, 3, 3, 1}; + // CHECK: store <4 x i8> + constexpr auto z = FourCharsExtVec{1, 2, 3, 4} >= + FourCharsExtVec{4, 3, 3, 1}; + // CHECK: store <4 x i8> + constexpr auto A = FourCharsExtVec{1, 2, 3, 4} == + FourCharsExtVec{4, 3, 3, 1}; + // CHECK: store <4 x i8> + constexpr auto B = FourCharsExtVec{1, 2, 3, 4} != + FourCharsExtVec{4, 3, 3, 1}; + // CHECK: store <4 x i8> + + constexpr auto C = FourCharsExtVec{1, 2, 3, 4} < 3; + // CHECK: store <4 x i8> + constexpr auto D = FourCharsExtVec{1, 2, 3, 4} > 3; + // CHECK: store <4 x i8> + constexpr auto E = FourCharsExtVec{1, 2, 3, 4} <= 3; + // CHECK: store <4 x i8> + constexpr auto F = FourCharsExtVec{1, 2, 3, 4} >= 3; + // CHECK: store <4 x i8> + constexpr auto G = FourCharsExtVec{1, 2, 3, 4} == 3; + // CHECK: store <4 x i8> + constexpr auto H = FourCharsExtVec{1, 2, 3, 4} != 3; + // CHECK: store <4 x i8> + + constexpr auto I = FourCharsExtVec{1, 2, 3, 4} & + FourCharsExtVec{4, 3, 2, 1}; + // CHECK: store <4 x i8> + constexpr auto J = FourCharsExtVec{1, 2, 3, 4} ^ + FourCharsExtVec { 4, 3, 2, 1 }; + // CHECK: store <4 x i8> + constexpr auto K = FourCharsExtVec{1, 2, 3, 4} | + FourCharsExtVec{4, 3, 2, 1}; + // CHECK: store <4 x i8> + constexpr auto L = FourCharsExtVec{1, 2, 3, 4} & 3; + // CHECK: store <4 x i8> + constexpr auto M = FourCharsExtVec{1, 2, 3, 4} ^ 3; + // CHECK: store <4 x i8> + constexpr auto N = FourCharsExtVec{1, 2, 3, 4} | 3; + // CHECK: store <4 x i8> + + constexpr auto O = FourCharsExtVec{5, 0, 6, 0} && + FourCharsExtVec{5, 5, 0, 0}; + // CHECK: store <4 x i8> + constexpr auto P = FourCharsExtVec{5, 0, 6, 0} || + FourCharsExtVec{5, 5, 0, 0}; + // CHECK: store <4 x i8> + + constexpr auto Q = FourCharsExtVec{5, 0, 6, 0} && 3; + // CHECK: store <4 x i8> + constexpr auto R = FourCharsExtVec{5, 0, 6, 0} || 3; + // CHECK: store <4 x i8> + + constexpr auto T = CmpMul(a, b); + // CHECK: store <4 x i8> + + constexpr auto U = CmpDiv(a, b); + // CHECK: store <4 x i8> + + constexpr auto V = CmpRem(a, b); + // CHECK: store <4 x i8> + + constexpr auto X = CmpAdd(a, b); + // CHECK: store <4 x i8> + + constexpr auto Y = CmpSub(a, b); + // CHECK: store <4 x i8> + + constexpr auto Z = CmpLSH(a, H); + // CHECK: store <4 x i8> + + constexpr auto aa = CmpRSH(a, H); + // CHECK: store <4 x i8> + + constexpr auto ab = CmpBinAnd(a, b); + // CHECK: store <4 x i8> + + constexpr auto ac = CmpBinXOr(a, b); + // CHECK: store <4 x i8> + + constexpr auto ad = CmpBinOr(a, b); + // CHECK: store <4 x i8> +} + +void FloatUsage() { + constexpr auto a = FourFloatsVecSize{6, 3, 2, 1} + + FourFloatsVecSize{12, 15, 5, 7}; + // CHECK: <4 x float> + constexpr auto b = FourFloatsVecSize{19, 15, 13, 12} - + FourFloatsVecSize{13, 14, 5, 3}; + // CHECK: store <4 x float> + constexpr auto c = FourFloatsVecSize{8, 4, 2, 1} * + FourFloatsVecSize{3, 4, 5, 6}; + // CHECK: store <4 x float> + constexpr auto d = FourFloatsVecSize{12, 12, 10, 10} / + FourFloatsVecSize{6, 4, 5, 2}; + // CHECK: store <4 x float> + + constexpr auto f = FourFloatsVecSize{6, 3, 2, 1} + 3; + // CHECK: store <4 x float> + constexpr auto g = FourFloatsVecSize{19, 15, 12, 10} - 3; + // CHECK: store <4 x float> + constexpr auto h = FourFloatsVecSize{8, 4, 2, 1} * 3; + // CHECK: store <4 x float> + constexpr auto j = FourFloatsVecSize{12, 15, 18, 21} / 3; + // CHECK: store <4 x float> + + constexpr auto l = 3 + FourFloatsVecSize{6, 3, 2, 1}; + // CHECK: store <4 x float> + constexpr auto m = 20 - FourFloatsVecSize{19, 15, 12, 10}; + // CHECK: store <4 x float> + constexpr auto n = 3 * FourFloatsVecSize{8, 4, 2, 1}; + // CHECK: store <4 x float> + constexpr auto o = 100 / FourFloatsVecSize{12, 15, 18, 21}; + // CHECK: store <4 x float> + + constexpr auto w = FourFloatsVecSize{1, 2, 3, 4} < + FourFloatsVecSize{4, 3, 2, 1}; + // CHECK: store <4 x i32> + constexpr auto x = FourFloatsVecSize{1, 2, 3, 4} > + FourFloatsVecSize{4, 3, 2, 1}; + // CHECK: store <4 x i32> + constexpr auto y = FourFloatsVecSize{1, 2, 3, 4} <= + FourFloatsVecSize{4, 3, 3, 1}; + // CHECK: store <4 x i32> + constexpr auto z = FourFloatsVecSize{1, 2, 3, 4} >= + FourFloatsVecSize{4, 3, 3, 1}; + // CHECK: store <4 x i32> + constexpr auto A = FourFloatsVecSize{1, 2, 3, 4} == + FourFloatsVecSize{4, 3, 3, 1}; + // CHECK: store <4 x i32> + constexpr auto B = FourFloatsVecSize{1, 2, 3, 4} != + FourFloatsVecSize{4, 3, 3, 1}; + // CHECK: store <4 x i32> + + constexpr auto C = FourFloatsVecSize{1, 2, 3, 4} < 3; + // CHECK: store <4 x i32> + constexpr auto D = FourFloatsVecSize{1, 2, 3, 4} > 3; + // CHECK: store <4 x i32> + constexpr auto E = FourFloatsVecSize{1, 2, 3, 4} <= 3; + // CHECK: store <4 x i32> + constexpr auto F = FourFloatsVecSize{1, 2, 3, 4} >= 3; + // CHECK: store <4 x i32> + constexpr auto G = FourFloatsVecSize{1, 2, 3, 4} == 3; + // CHECK: store <4 x i32> + constexpr auto H = FourFloatsVecSize{1, 2, 3, 4} != 3; + // CHECK: store <4 x i32> + + constexpr auto O = FourFloatsVecSize{5, 0, 6, 0} && + FourFloatsVecSize{5, 5, 0, 0}; + // CHECK: store <4 x i32> + constexpr auto P = FourFloatsVecSize{5, 0, 6, 0} || + FourFloatsVecSize{5, 5, 0, 0}; + // CHECK: store <4 x i32> + + constexpr auto Q = FourFloatsVecSize{5, 0, 6, 0} && 3; + // CHECK: store <4 x i32> + constexpr auto R = FourFloatsVecSize{5, 0, 6, 0} || 3; + // CHECK: store <4 x i32> + + constexpr auto T = CmpMul(a, b); + // CHECK: store <4 x float> + + constexpr auto U = CmpDiv(a, b); + // CHECK: store <4 x float> + + constexpr auto X = CmpAdd(a, b); + // CHECK: store <4 x float> + + constexpr auto Y = CmpSub(a, b); + // CHECK: store <4 x float> +} + +void FloatVecUsage() { + constexpr auto a = FourFloatsVecSize{6, 3, 2, 1} + + FourFloatsVecSize{12, 15, 5, 7}; + // CHECK: <4 x float> + constexpr auto b = FourFloatsVecSize{19, 15, 13, 12} - + FourFloatsVecSize{13, 14, 5, 3}; + // CHECK: store <4 x float> + constexpr auto c = FourFloatsVecSize{8, 4, 2, 1} * + FourFloatsVecSize{3, 4, 5, 6}; + // CHECK: store <4 x float> + constexpr auto d = FourFloatsVecSize{12, 12, 10, 10} / + FourFloatsVecSize{6, 4, 5, 2}; + // CHECK: store <4 x float> + + constexpr auto f = FourFloatsVecSize{6, 3, 2, 1} + 3; + // CHECK: store <4 x float> + constexpr auto g = FourFloatsVecSize{19, 15, 12, 10} - 3; + // CHECK: store <4 x float> + constexpr auto h = FourFloatsVecSize{8, 4, 2, 1} * 3; + // CHECK: store <4 x float> + constexpr auto j = FourFloatsVecSize{12, 15, 18, 21} / 3; + // CHECK: store <4 x float> + + constexpr auto l = 3 + FourFloatsVecSize{6, 3, 2, 1}; + // CHECK: store <4 x float> + constexpr auto m = 20 - FourFloatsVecSize{19, 15, 12, 10}; + // CHECK: store <4 x float> + constexpr auto n = 3 * FourFloatsVecSize{8, 4, 2, 1}; + // CHECK: store <4 x float> + constexpr auto o = 100 / FourFloatsVecSize{12, 15, 18, 21}; + // CHECK: store <4 x float> + + constexpr auto w = FourFloatsVecSize{1, 2, 3, 4} < + FourFloatsVecSize{4, 3, 2, 1}; + // CHECK: store <4 x i32> + constexpr auto x = FourFloatsVecSize{1, 2, 3, 4} > + FourFloatsVecSize{4, 3, 2, 1}; + // CHECK: store <4 x i32> + constexpr auto y = FourFloatsVecSize{1, 2, 3, 4} <= + FourFloatsVecSize{4, 3, 3, 1}; + // CHECK: store <4 x i32> + constexpr auto z = FourFloatsVecSize{1, 2, 3, 4} >= + FourFloatsVecSize{4, 3, 3, 1}; + // CHECK: store <4 x i32> + constexpr auto A = FourFloatsVecSize{1, 2, 3, 4} == + FourFloatsVecSize{4, 3, 3, 1}; + // CHECK: store <4 x i32> + constexpr auto B = FourFloatsVecSize{1, 2, 3, 4} != + FourFloatsVecSize{4, 3, 3, 1}; + // CHECK: store <4 x i32> + + constexpr auto C = FourFloatsVecSize{1, 2, 3, 4} < 3; + // CHECK: store <4 x i32> + constexpr auto D = FourFloatsVecSize{1, 2, 3, 4} > 3; + // CHECK: store <4 x i32> + constexpr auto E = FourFloatsVecSize{1, 2, 3, 4} <= 3; + // CHECK: store <4 x i32> + constexpr auto F = FourFloatsVecSize{1, 2, 3, 4} >= 3; + // CHECK: store <4 x i32> + constexpr auto G = FourFloatsVecSize{1, 2, 3, 4} == 3; + // CHECK: store <4 x i32> + constexpr auto H = FourFloatsVecSize{1, 2, 3, 4} != 3; + // CHECK: store <4 x i32> + + constexpr auto O = FourFloatsVecSize{5, 0, 6, 0} && + FourFloatsVecSize{5, 5, 0, 0}; + // CHECK: store <4 x i32> + constexpr auto P = FourFloatsVecSize{5, 0, 6, 0} || + FourFloatsVecSize{5, 5, 0, 0}; + // CHECK: store <4 x i32> + + constexpr auto Q = FourFloatsVecSize{5, 0, 6, 0} && 3; + // CHECK: store <4 x i32> + constexpr auto R = FourFloatsVecSize{5, 0, 6, 0} || 3; + // CHECK: store <4 x i32> + + constexpr auto T = CmpMul(a, b); + // CHECK: store <4 x float> + + constexpr auto U = CmpDiv(a, b); + // CHECK: store <4 x float> + + constexpr auto X = CmpAdd(a, b); + // CHECK: store <4 x float> + + constexpr auto Y = CmpSub(a, b); + // CHECK: store <4 x float> +}