diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index bb59e72ed51b6d..9fcba4e25cef60 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -2931,6 +2931,11 @@ handleCompareOpForVectorHelper(const APTy &LHSValue, BinaryOperatorKind Opcode, break; } + // The boolean operations on these vector types use an instruction that + // results in a mask of '-1' for the 'truth' value. Ensure that we negate 1 + // to -1 to make sure that we produce the correct value. + Result.negate(); + return true; } @@ -10179,7 +10184,8 @@ namespace { bool VisitInitListExpr(const InitListExpr *E); bool VisitUnaryImag(const UnaryOperator *E); bool VisitBinaryOperator(const BinaryOperator *E); - // FIXME: Missing: unary -, unary ~, conditional operator (for GNU + bool VisitUnaryOperator(const UnaryOperator *E); + // FIXME: Missing: conditional operator (for GNU // conditional select), shufflevector, ExtVectorElementExpr }; } // end anonymous namespace @@ -10364,6 +10370,83 @@ bool VectorExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { return Success(LHSValue, E); } +static llvm::Optional handleVectorUnaryOperator(ASTContext &Ctx, + QualType ResultTy, + UnaryOperatorKind Op, + APValue Elt) { + switch (Op) { + case UO_Plus: + // Nothing to do here. + return Elt; + case UO_Minus: + if (Elt.getKind() == APValue::Int) { + Elt.getInt().negate(); + } else { + assert(Elt.getKind() == APValue::Float && + "Vector can only be int or float type"); + Elt.getFloat().changeSign(); + } + return Elt; + case UO_Not: + // This is only valid for integral types anyway, so we don't have to handle + // float here. + assert(Elt.getKind() == APValue::Int && + "Vector operator ~ can only be int"); + Elt.getInt().flipAllBits(); + return Elt; + case UO_LNot: { + if (Elt.getKind() == APValue::Int) { + Elt.getInt() = !Elt.getInt(); + // operator ! on vectors returns -1 for 'truth', so negate it. + Elt.getInt().negate(); + return Elt; + } + assert(Elt.getKind() == APValue::Float && + "Vector can only be int or float type"); + // Float types result in an int of the same size, but -1 for true, or 0 for + // false. + APSInt EltResult{Ctx.getIntWidth(ResultTy), + ResultTy->isUnsignedIntegerType()}; + if (Elt.getFloat().isZero()) + EltResult.setAllBits(); + else + EltResult.clearAllBits(); + + return APValue{EltResult}; + } + default: + // FIXME: Implement the rest of the unary operators. + return llvm::None; + } +} + +bool VectorExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { + Expr *SubExpr = E->getSubExpr(); + const auto *VD = SubExpr->getType()->castAs(); + // This result element type differs in the case of negating a floating point + // vector, since the result type is the a vector of the equivilant sized + // integer. + const QualType ResultEltTy = VD->getElementType(); + UnaryOperatorKind Op = E->getOpcode(); + + APValue SubExprValue; + if (!Evaluate(SubExprValue, Info, SubExpr)) + return false; + + assert(SubExprValue.getVectorLength() == VD->getNumElements() && + "Vector length doesn't match type?"); + + SmallVector ResultElements; + for (unsigned EltNum = 0; EltNum < VD->getNumElements(); ++EltNum) { + llvm::Optional Elt = handleVectorUnaryOperator( + Info.Ctx, ResultEltTy, Op, SubExprValue.getVectorElt(EltNum)); + if (!Elt) + return false; + ResultElements.push_back(*Elt); + } + return Success(APValue(ResultElements.data(), ResultElements.size()), E); +} + //===----------------------------------------------------------------------===// // Array Evaluation //===----------------------------------------------------------------------===// diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 2b69c372785264..82e881476d35c9 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -12261,27 +12261,32 @@ QualType Sema::GetSignedVectorType(QualType V) { if (isa(VTy)) { if (TypeSize == Context.getTypeSize(Context.CharTy)) return Context.getExtVectorType(Context.CharTy, VTy->getNumElements()); - else if (TypeSize == Context.getTypeSize(Context.ShortTy)) + if (TypeSize == Context.getTypeSize(Context.ShortTy)) return Context.getExtVectorType(Context.ShortTy, VTy->getNumElements()); - else if (TypeSize == Context.getTypeSize(Context.IntTy)) + if (TypeSize == Context.getTypeSize(Context.IntTy)) return Context.getExtVectorType(Context.IntTy, VTy->getNumElements()); - else if (TypeSize == Context.getTypeSize(Context.LongTy)) + if (TypeSize == Context.getTypeSize(Context.Int128Ty)) + return Context.getExtVectorType(Context.Int128Ty, VTy->getNumElements()); + if (TypeSize == Context.getTypeSize(Context.LongTy)) return Context.getExtVectorType(Context.LongTy, VTy->getNumElements()); assert(TypeSize == Context.getTypeSize(Context.LongLongTy) && "Unhandled vector element size in vector compare"); return Context.getExtVectorType(Context.LongLongTy, VTy->getNumElements()); } + if (TypeSize == Context.getTypeSize(Context.Int128Ty)) + return Context.getVectorType(Context.Int128Ty, VTy->getNumElements(), + VectorType::GenericVector); if (TypeSize == Context.getTypeSize(Context.LongLongTy)) return Context.getVectorType(Context.LongLongTy, VTy->getNumElements(), VectorType::GenericVector); - else if (TypeSize == Context.getTypeSize(Context.LongTy)) + if (TypeSize == Context.getTypeSize(Context.LongTy)) return Context.getVectorType(Context.LongTy, VTy->getNumElements(), VectorType::GenericVector); - else if (TypeSize == Context.getTypeSize(Context.IntTy)) + if (TypeSize == Context.getTypeSize(Context.IntTy)) return Context.getVectorType(Context.IntTy, VTy->getNumElements(), VectorType::GenericVector); - else if (TypeSize == Context.getTypeSize(Context.ShortTy)) + if (TypeSize == Context.getTypeSize(Context.ShortTy)) return Context.getVectorType(Context.ShortTy, VTy->getNumElements(), VectorType::GenericVector); assert(TypeSize == Context.getTypeSize(Context.CharTy) && diff --git a/clang/test/SemaCXX/constexpr-vectors.cpp b/clang/test/SemaCXX/constexpr-vectors.cpp index 1ba0e33253321e..609d1970dde871 100644 --- a/clang/test/SemaCXX/constexpr-vectors.cpp +++ b/clang/test/SemaCXX/constexpr-vectors.cpp @@ -11,12 +11,15 @@ 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 FourI128VecSize __attribute__((vector_size(64))) = __int128; 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; +using FourI128ExtVec __attribute__((ext_vector_type(4))) = __int128; + // Next a series of tests to make sure these operations are usable in // constexpr functions. Template instantiations don't emit Winvalid-constexpr, @@ -204,35 +207,35 @@ void CharUsage() { constexpr auto w = FourCharsVecSize{1, 2, 3, 4} < FourCharsVecSize{4, 3, 2, 1}; - // CHECK: store <4 x i8> + // CHECK: store <4 x i8> constexpr auto x = FourCharsVecSize{1, 2, 3, 4} > FourCharsVecSize{4, 3, 2, 1}; - // CHECK: store <4 x i8> + // CHECK: store <4 x i8> constexpr auto y = FourCharsVecSize{1, 2, 3, 4} <= FourCharsVecSize{4, 3, 3, 1}; - // CHECK: store <4 x i8> + // CHECK: store <4 x i8> constexpr auto z = FourCharsVecSize{1, 2, 3, 4} >= FourCharsVecSize{4, 3, 3, 1}; - // CHECK: store <4 x i8> + // CHECK: store <4 x i8> constexpr auto A = FourCharsVecSize{1, 2, 3, 4} == FourCharsVecSize{4, 3, 3, 1}; - // CHECK: store <4 x i8> + // CHECK: store <4 x i8> constexpr auto B = FourCharsVecSize{1, 2, 3, 4} != FourCharsVecSize{4, 3, 3, 1}; - // CHECK: store <4 x i8> + // CHECK: store <4 x i8> constexpr auto C = FourCharsVecSize{1, 2, 3, 4} < 3; - // CHECK: store <4 x i8> + // CHECK: store <4 x i8> constexpr auto D = FourCharsVecSize{1, 2, 3, 4} > 3; - // CHECK: store <4 x i8> + // CHECK: store <4 x i8> constexpr auto E = FourCharsVecSize{1, 2, 3, 4} <= 3; - // CHECK: store <4 x i8> + // CHECK: store <4 x i8> constexpr auto F = FourCharsVecSize{1, 2, 3, 4} >= 3; - // CHECK: store <4 x i8> + // CHECK: store <4 x i8> constexpr auto G = FourCharsVecSize{1, 2, 3, 4} == 3; - // CHECK: store <4 x i8> + // CHECK: store <4 x i8> constexpr auto H = FourCharsVecSize{1, 2, 3, 4} != 3; - // CHECK: store <4 x i8> + // CHECK: store <4 x i8> constexpr auto I = FourCharsVecSize{1, 2, 3, 4} & FourCharsVecSize{4, 3, 2, 1}; @@ -277,10 +280,12 @@ void CharUsage() { constexpr auto Y = CmpSub(a, b); // CHECK: store <4 x i8> - constexpr auto Z = CmpLSH(a, H); + constexpr auto InvH = -H; + // CHECK: store <4 x i8> + constexpr auto Z = CmpLSH(a, InvH); // CHECK: store <4 x i8> - constexpr auto aa = CmpRSH(a, H); + constexpr auto aa = CmpRSH(a, InvH); // CHECK: store <4 x i8> constexpr auto ab = CmpBinAnd(a, b); @@ -291,6 +296,12 @@ void CharUsage() { constexpr auto ad = CmpBinOr(a, b); // CHECK: store <4 x i8> + + constexpr auto ae = ~FourCharsVecSize{1, 2, 10, 20}; + // CHECK: store <4 x i8> + + constexpr auto af = !FourCharsVecSize{0, 1, 8, -1}; + // CHECK: store <4 x i8> } void CharExtVecUsage() { @@ -348,35 +359,35 @@ void CharExtVecUsage() { constexpr auto w = FourCharsExtVec{1, 2, 3, 4} < FourCharsExtVec{4, 3, 2, 1}; - // CHECK: store <4 x i8> + // CHECK: store <4 x i8> constexpr auto x = FourCharsExtVec{1, 2, 3, 4} > FourCharsExtVec{4, 3, 2, 1}; - // CHECK: store <4 x i8> + // CHECK: store <4 x i8> constexpr auto y = FourCharsExtVec{1, 2, 3, 4} <= FourCharsExtVec{4, 3, 3, 1}; - // CHECK: store <4 x i8> + // CHECK: store <4 x i8> constexpr auto z = FourCharsExtVec{1, 2, 3, 4} >= FourCharsExtVec{4, 3, 3, 1}; - // CHECK: store <4 x i8> + // CHECK: store <4 x i8> constexpr auto A = FourCharsExtVec{1, 2, 3, 4} == FourCharsExtVec{4, 3, 3, 1}; - // CHECK: store <4 x i8> + // CHECK: store <4 x i8> constexpr auto B = FourCharsExtVec{1, 2, 3, 4} != FourCharsExtVec{4, 3, 3, 1}; - // CHECK: store <4 x i8> + // CHECK: store <4 x i8> constexpr auto C = FourCharsExtVec{1, 2, 3, 4} < 3; - // CHECK: store <4 x i8> + // CHECK: store <4 x i8> constexpr auto D = FourCharsExtVec{1, 2, 3, 4} > 3; - // CHECK: store <4 x i8> + // CHECK: store <4 x i8> constexpr auto E = FourCharsExtVec{1, 2, 3, 4} <= 3; - // CHECK: store <4 x i8> + // CHECK: store <4 x i8> constexpr auto F = FourCharsExtVec{1, 2, 3, 4} >= 3; - // CHECK: store <4 x i8> + // CHECK: store <4 x i8> constexpr auto G = FourCharsExtVec{1, 2, 3, 4} == 3; - // CHECK: store <4 x i8> + // CHECK: store <4 x i8> constexpr auto H = FourCharsExtVec{1, 2, 3, 4} != 3; - // CHECK: store <4 x i8> + // CHECK: store <4 x i8> constexpr auto I = FourCharsExtVec{1, 2, 3, 4} & FourCharsExtVec{4, 3, 2, 1}; @@ -421,10 +432,13 @@ void CharExtVecUsage() { constexpr auto Y = CmpSub(a, b); // CHECK: store <4 x i8> - constexpr auto Z = CmpLSH(a, H); + constexpr auto InvH = -H; + // CHECK: store <4 x i8> + + constexpr auto Z = CmpLSH(a, InvH); // CHECK: store <4 x i8> - constexpr auto aa = CmpRSH(a, H); + constexpr auto aa = CmpRSH(a, InvH); // CHECK: store <4 x i8> constexpr auto ab = CmpBinAnd(a, b); @@ -435,6 +449,12 @@ void CharExtVecUsage() { constexpr auto ad = CmpBinOr(a, b); // CHECK: store <4 x i8> + + constexpr auto ae = ~FourCharsExtVec{1, 2, 10, 20}; + // CHECK: store <4 x i8> + + constexpr auto af = !FourCharsExtVec{0, 1, 8, -1}; + // CHECK: store <4 x i8> } void FloatUsage() { @@ -471,35 +491,35 @@ void FloatUsage() { constexpr auto w = FourFloatsVecSize{1, 2, 3, 4} < FourFloatsVecSize{4, 3, 2, 1}; - // CHECK: store <4 x i32> + // CHECK: store <4 x i32> constexpr auto x = FourFloatsVecSize{1, 2, 3, 4} > FourFloatsVecSize{4, 3, 2, 1}; - // CHECK: store <4 x i32> + // CHECK: store <4 x i32> constexpr auto y = FourFloatsVecSize{1, 2, 3, 4} <= FourFloatsVecSize{4, 3, 3, 1}; - // CHECK: store <4 x i32> + // CHECK: store <4 x i32> constexpr auto z = FourFloatsVecSize{1, 2, 3, 4} >= FourFloatsVecSize{4, 3, 3, 1}; - // CHECK: store <4 x i32> + // CHECK: store <4 x i32> constexpr auto A = FourFloatsVecSize{1, 2, 3, 4} == FourFloatsVecSize{4, 3, 3, 1}; - // CHECK: store <4 x i32> + // CHECK: store <4 x i32> constexpr auto B = FourFloatsVecSize{1, 2, 3, 4} != FourFloatsVecSize{4, 3, 3, 1}; - // CHECK: store <4 x i32> + // CHECK: store <4 x i32> constexpr auto C = FourFloatsVecSize{1, 2, 3, 4} < 3; - // CHECK: store <4 x i32> + // CHECK: store <4 x i32> constexpr auto D = FourFloatsVecSize{1, 2, 3, 4} > 3; - // CHECK: store <4 x i32> + // CHECK: store <4 x i32> constexpr auto E = FourFloatsVecSize{1, 2, 3, 4} <= 3; - // CHECK: store <4 x i32> + // CHECK: store <4 x i32> constexpr auto F = FourFloatsVecSize{1, 2, 3, 4} >= 3; - // CHECK: store <4 x i32> + // CHECK: store <4 x i32> constexpr auto G = FourFloatsVecSize{1, 2, 3, 4} == 3; - // CHECK: store <4 x i32> + // CHECK: store <4 x i32> constexpr auto H = FourFloatsVecSize{1, 2, 3, 4} != 3; - // CHECK: store <4 x i32> + // CHECK: store <4 x i32> constexpr auto O = FourFloatsVecSize{5, 0, 6, 0} && FourFloatsVecSize{5, 5, 0, 0}; @@ -524,6 +544,13 @@ void FloatUsage() { constexpr auto Y = CmpSub(a, b); // CHECK: store <4 x float> + + constexpr auto Z = -Y; + // CHECK: store <4 x float> + + // Operator ~ is illegal on floats, so no test for that. + constexpr auto af = !FourFloatsVecSize{0, 1, 8, -1}; + // CHECK: store <4 x i32> } void FloatVecUsage() { @@ -560,35 +587,35 @@ void FloatVecUsage() { constexpr auto w = FourFloatsVecSize{1, 2, 3, 4} < FourFloatsVecSize{4, 3, 2, 1}; - // CHECK: store <4 x i32> + // CHECK: store <4 x i32> constexpr auto x = FourFloatsVecSize{1, 2, 3, 4} > FourFloatsVecSize{4, 3, 2, 1}; - // CHECK: store <4 x i32> + // CHECK: store <4 x i32> constexpr auto y = FourFloatsVecSize{1, 2, 3, 4} <= FourFloatsVecSize{4, 3, 3, 1}; - // CHECK: store <4 x i32> + // CHECK: store <4 x i32> constexpr auto z = FourFloatsVecSize{1, 2, 3, 4} >= FourFloatsVecSize{4, 3, 3, 1}; - // CHECK: store <4 x i32> + // CHECK: store <4 x i32> constexpr auto A = FourFloatsVecSize{1, 2, 3, 4} == FourFloatsVecSize{4, 3, 3, 1}; - // CHECK: store <4 x i32> + // CHECK: store <4 x i32> constexpr auto B = FourFloatsVecSize{1, 2, 3, 4} != FourFloatsVecSize{4, 3, 3, 1}; - // CHECK: store <4 x i32> + // CHECK: store <4 x i32> constexpr auto C = FourFloatsVecSize{1, 2, 3, 4} < 3; - // CHECK: store <4 x i32> + // CHECK: store <4 x i32> constexpr auto D = FourFloatsVecSize{1, 2, 3, 4} > 3; - // CHECK: store <4 x i32> + // CHECK: store <4 x i32> constexpr auto E = FourFloatsVecSize{1, 2, 3, 4} <= 3; - // CHECK: store <4 x i32> + // CHECK: store <4 x i32> constexpr auto F = FourFloatsVecSize{1, 2, 3, 4} >= 3; - // CHECK: store <4 x i32> + // CHECK: store <4 x i32> constexpr auto G = FourFloatsVecSize{1, 2, 3, 4} == 3; - // CHECK: store <4 x i32> + // CHECK: store <4 x i32> constexpr auto H = FourFloatsVecSize{1, 2, 3, 4} != 3; - // CHECK: store <4 x i32> + // CHECK: store <4 x i32> constexpr auto O = FourFloatsVecSize{5, 0, 6, 0} && FourFloatsVecSize{5, 5, 0, 0}; @@ -613,4 +640,40 @@ void FloatVecUsage() { constexpr auto Y = CmpSub(a, b); // CHECK: store <4 x float> + + constexpr auto Z = -Y; + // CHECK: store <4 x float> + + // Operator ~ is illegal on floats, so no test for that. + constexpr auto af = !FourFloatsVecSize{0, 1, 8, -1}; + // CHECK: store <4 x i32> +} + +void I128Usage() { + constexpr auto a = FourI128VecSize{1, 2, 3, 4}; + // CHECK: store <4 x i128> + constexpr auto b = a < 3; + // CHECK: store <4 x i128> + + // Operator ~ is illegal on floats, so no test for that. + constexpr auto c = ~FourI128VecSize{1, 2, 10, 20}; + // CHECK: store <4 x i128> + + constexpr auto d = !FourI128VecSize{0, 1, 8, -1}; + // CHECK: store <4 x i128> +} + +void I128VecUsage() { + constexpr auto a = FourI128ExtVec{1, 2, 3, 4}; + // CHECK: store <4 x i128> + constexpr auto b = a < 3; + // CHECK: store <4 x i128> + + // Operator ~ is illegal on floats, so no test for that. + constexpr auto c = ~FourI128ExtVec{1, 2, 10, 20}; + // CHECK: store <4 x i128> + + constexpr auto d = !FourI128ExtVec{0, 1, 8, -1}; + // CHECK: store <4 x i128> } +