Author: yronglin Date: 2024-08-29T06:10:30+08:00 New Revision: ee0d70633872a30175cf29f81de7b2dbf771d708
URL: https://github.com/llvm/llvm-project/commit/ee0d70633872a30175cf29f81de7b2dbf771d708 DIFF: https://github.com/llvm/llvm-project/commit/ee0d70633872a30175cf29f81de7b2dbf771d708.diff LOG: [clang][bytecode] Implement constexpr vector unary operators +, -, ~, ! (#105996) Implement constexpr vector unary operators +, -, ~ and ! . - Follow the current constant interpreter. All of our boolean operations on vector types should be '-1' for the 'truth' type. - Move the following functions from `Sema` to `ASTContext`, because we used it in new interpreter. ```C++ QualType GetSignedVectorType(QualType V); QualType GetSignedSizelessVectorType(QualType V); ``` --------- Signed-off-by: yronglin <yronglin...@gmail.com> Added: clang/test/AST/ByteCode/constexpr-vectors.cpp Modified: clang/lib/AST/ByteCode/Compiler.cpp clang/lib/AST/ByteCode/Compiler.h Removed: ################################################################################ diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 0fc942a4f1bc4f..6a77323d939791 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -4991,6 +4991,8 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) { const Expr *SubExpr = E->getSubExpr(); if (SubExpr->getType()->isAnyComplexType()) return this->VisitComplexUnaryOperator(E); + if (SubExpr->getType()->isVectorType()) + return this->VisitVectorUnaryOperator(E); std::optional<PrimType> T = classify(SubExpr->getType()); switch (E->getOpcode()) { @@ -5312,6 +5314,110 @@ bool Compiler<Emitter>::VisitComplexUnaryOperator(const UnaryOperator *E) { return true; } +template <class Emitter> +bool Compiler<Emitter>::VisitVectorUnaryOperator(const UnaryOperator *E) { + const Expr *SubExpr = E->getSubExpr(); + assert(SubExpr->getType()->isVectorType()); + + if (DiscardResult) + return this->discard(SubExpr); + + auto UnaryOp = E->getOpcode(); + if (UnaryOp != UO_Plus && UnaryOp != UO_Minus && UnaryOp != UO_LNot && + UnaryOp != UO_Not) + return this->emitInvalid(E); + + // Nothing to do here. + if (UnaryOp == UO_Plus) + return this->delegate(SubExpr); + + if (!Initializing) { + std::optional<unsigned> LocalIndex = allocateLocal(SubExpr); + if (!LocalIndex) + return false; + if (!this->emitGetPtrLocal(*LocalIndex, E)) + return false; + } + + // The offset of the temporary, if we created one. + unsigned SubExprOffset = + this->allocateLocalPrimitive(SubExpr, PT_Ptr, true, false); + if (!this->visit(SubExpr)) + return false; + if (!this->emitSetLocal(PT_Ptr, SubExprOffset, E)) + return false; + + const auto *VecTy = SubExpr->getType()->getAs<VectorType>(); + PrimType ElemT = classifyVectorElementType(SubExpr->getType()); + auto getElem = [=](unsigned Offset, unsigned Index) -> bool { + if (!this->emitGetLocal(PT_Ptr, Offset, E)) + return false; + return this->emitArrayElemPop(ElemT, Index, E); + }; + + switch (UnaryOp) { + case UO_Minus: + for (unsigned I = 0; I != VecTy->getNumElements(); ++I) { + if (!getElem(SubExprOffset, I)) + return false; + if (!this->emitNeg(ElemT, E)) + return false; + if (!this->emitInitElem(ElemT, I, E)) + return false; + } + break; + case UO_LNot: { // !x + // In C++, the logic operators !, &&, || are available for vectors. !v is + // equivalent to v == 0. + // + // The result of the comparison is a vector of the same width and number of + // elements as the comparison operands with a signed integral element type. + // + // https://gcc.gnu.org/onlinedocs/gcc/Vector-Extensions.html + QualType ResultVecTy = E->getType(); + PrimType ResultVecElemT = + classifyPrim(ResultVecTy->getAs<VectorType>()->getElementType()); + for (unsigned I = 0; I != VecTy->getNumElements(); ++I) { + if (!getElem(SubExprOffset, I)) + return false; + // operator ! on vectors returns -1 for 'truth', so negate it. + if (!this->emitPrimCast(ElemT, PT_Bool, Ctx.getASTContext().BoolTy, E)) + return false; + if (!this->emitInv(E)) + return false; + if (!this->emitPrimCast(PT_Bool, ElemT, VecTy->getElementType(), E)) + return false; + if (!this->emitNeg(ElemT, E)) + return false; + if (ElemT != ResultVecElemT && + !this->emitPrimCast(ElemT, ResultVecElemT, ResultVecTy, E)) + return false; + if (!this->emitInitElem(ResultVecElemT, I, E)) + return false; + } + break; + } + case UO_Not: // ~x + for (unsigned I = 0; I != VecTy->getNumElements(); ++I) { + if (!getElem(SubExprOffset, I)) + return false; + if (ElemT == PT_Bool) { + if (!this->emitInv(E)) + return false; + } else { + if (!this->emitComp(ElemT, E)) + return false; + } + if (!this->emitInitElem(ElemT, I, E)) + return false; + } + break; + default: + llvm_unreachable("Unsupported unary operators should be handled up front"); + } + return true; +} + template <class Emitter> bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) { if (DiscardResult) diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h index 5acfe3c41796c4..939cc0dae3546f 100644 --- a/clang/lib/AST/ByteCode/Compiler.h +++ b/clang/lib/AST/ByteCode/Compiler.h @@ -139,6 +139,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>, bool VisitGNUNullExpr(const GNUNullExpr *E); bool VisitCXXThisExpr(const CXXThisExpr *E); bool VisitUnaryOperator(const UnaryOperator *E); + bool VisitVectorUnaryOperator(const UnaryOperator *E); bool VisitComplexUnaryOperator(const UnaryOperator *E); bool VisitDeclRefExpr(const DeclRefExpr *E); bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E); @@ -349,6 +350,11 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>, return *this->classify(ElemType); } + PrimType classifyVectorElementType(QualType T) const { + assert(T->isVectorType()); + return *this->classify(T->getAs<VectorType>()->getElementType()); + } + bool emitComplexReal(const Expr *SubExpr); bool emitComplexBoolCast(const Expr *E); bool emitComplexComparison(const Expr *LHS, const Expr *RHS, diff --git a/clang/test/AST/ByteCode/constexpr-vectors.cpp b/clang/test/AST/ByteCode/constexpr-vectors.cpp new file mode 100644 index 00000000000000..a738cfe617a0e0 --- /dev/null +++ b/clang/test/AST/ByteCode/constexpr-vectors.cpp @@ -0,0 +1,90 @@ +// RUN: %clang_cc1 %s -triple x86_64-linux-gnu -std=c++14 -fsyntax-only -verify +// RUN: %clang_cc1 %s -triple x86_64-linux-gnu -fexperimental-new-constant-interpreter -std=c++14 -fsyntax-only -verify + +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 FourI128VecSize __attribute__((vector_size(64))) = __int128; + +using FourCharsExtVec __attribute__((ext_vector_type(4))) = char; +using FourIntsExtVec __attribute__((ext_vector_type(4))) = int; +using FourI128ExtVec __attribute__((ext_vector_type(4))) = __int128; + +// 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 H = FourCharsVecSize{-1, -1, 0, -1}; + constexpr auto InvH = -H; + static_assert(InvH[0] == 1 && InvH[1] == 1 && InvH[2] == 0 && InvH[3] == 1, ""); + + constexpr auto ae = ~FourCharsVecSize{1, 2, 10, 20}; + static_assert(ae[0] == -2 && ae[1] == -3 && ae[2] == -11 && ae[3] == -21, ""); + + constexpr auto af = !FourCharsVecSize{0, 1, 8, -1}; + static_assert(af[0] == -1 && af[1] == 0 && af[2] == 0 && af[3] == 0, ""); +} + +void CharExtVecUsage() { + constexpr auto H = FourCharsExtVec{-1, -1, 0, -1}; + constexpr auto InvH = -H; + static_assert(InvH[0] == 1 && InvH[1] == 1 && InvH[2] == 0 && InvH[3] == 1, ""); + + constexpr auto ae = ~FourCharsExtVec{1, 2, 10, 20}; + static_assert(ae[0] == -2 && ae[1] == -3 && ae[2] == -11 && ae[3] == -21, ""); + + constexpr auto af = !FourCharsExtVec{0, 1, 8, -1}; + static_assert(af[0] == -1 && af[1] == 0 && af[2] == 0 && af[3] == 0, ""); +} + +void FloatUsage() { + constexpr auto Y = FourFloatsVecSize{1.200000e+01, 1.700000e+01, -1.000000e+00, -1.000000e+00}; + constexpr auto Z = -Y; + static_assert(Z[0] == -1.200000e+01 && Z[1] == -1.700000e+01 && Z[2] == 1.000000e+00 && Z[3] == 1.000000e+00, ""); + + // Operator ~ is illegal on floats. + constexpr auto ae = ~FourFloatsVecSize{0, 1, 8, -1}; // expected-error {{invalid argument type}} + + constexpr auto af = !FourFloatsVecSize{0, 1, 8, -1}; + static_assert(af[0] == -1 && af[1] == 0 && af[2] == 0 && af[3] == 0, ""); +} + +void FloatVecUsage() { + constexpr auto Y = FourFloatsVecSize{1.200000e+01, 1.700000e+01, -1.000000e+00, -1.000000e+00}; + constexpr auto Z = -Y; + static_assert(Z[0] == -1.200000e+01 && Z[1] == -1.700000e+01 && Z[2] == 1.000000e+00 && Z[3] == 1.000000e+00, ""); + + // Operator ~ is illegal on floats. + constexpr auto ae = ~FourFloatsVecSize{0, 1, 8, -1}; // expected-error {{invalid argument type}} + + constexpr auto af = !FourFloatsVecSize{0, 1, 8, -1}; + static_assert(af[0] == -1 && af[1] == 0 && af[2] == 0 && af[3] == 0, ""); +} + +void I128Usage() { + // Operator ~ is illegal on floats, so no test for that. + constexpr auto c = ~FourI128VecSize{1, 2, 10, 20}; + static_assert(c[0] == -2 && c[1] == -3 && c[2] == -11 && c[3] == -21, ""); + + constexpr auto d = !FourI128VecSize{0, 1, 8, -1}; + static_assert(d[0] == -1 && d[1] == 0 && d[2] == 0 && d[3] == 0, ""); +} + +void I128VecUsage() { + // Operator ~ is illegal on floats, so no test for that. + constexpr auto c = ~FourI128ExtVec{1, 2, 10, 20}; + static_assert(c[0] == -2 && c[1] == -3 && c[2] == -11 && c[3] == -21, ""); + + constexpr auto d = !FourI128ExtVec{0, 1, 8, -1}; + static_assert(d[0] == -1 && d[1] == 0 && d[2] == 0 && d[3] == 0, ""); +} + +using FourBoolsExtVec __attribute__((ext_vector_type(4))) = bool; +void BoolVecUsage() { + constexpr auto j = !FourBoolsExtVec{true, false, true, false}; + static_assert(j[0] == false && j[1] == true && j[2] == false && j[3] == true, ""); + + constexpr auto k = ~FourBoolsExtVec{true, false, true, false}; + static_assert(k[0] == false && k[1] == true && k[2] == false && k[3] == true, ""); +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits