llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Pol M (Destroyerrrocket) <details> <summary>Changes</summary> Summary: This patch adds constexpr support for __builtin_shufflevector and __builtin_convertvector. A small oddity encountered was that the arg to the intrinsics may be an lvalue without any sort of implicit cast of any kind. I solved this through the EvaluateVectorOrLValue function, which treats the lvalue as if it was in an rvalue cast, which gets me the desired vector. --- Full diff: https://github.com/llvm/llvm-project/pull/76615.diff 4 Files Affected: - (modified) clang/docs/LanguageExtensions.rst (+3-2) - (modified) clang/docs/ReleaseNotes.rst (+2) - (modified) clang/lib/AST/ExprConstant.cpp (+137-1) - (modified) clang/test/Sema/constant-builtins-2.c (+61) ``````````diff diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index 23a7f4f5d5b926..5f06c3d4b86f94 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -2853,7 +2853,7 @@ Query for this feature with ``__has_builtin(__builtin_dump_struct)`` ``__builtin_shufflevector`` is used to express generic vector permutation/shuffle/swizzle operations. This builtin is also very important for the implementation of various target-specific header files like -``<xmmintrin.h>``. +``<xmmintrin.h>``. This builtin can be used within constant expressions. **Syntax**: @@ -2907,7 +2907,8 @@ Query for this feature with ``__has_builtin(__builtin_shufflevector)``. ``__builtin_convertvector`` is used to express generic vector type-conversion operations. The input vector and the output vector -type must have the same number of elements. +type must have the same number of elements. This builtin can be used within +constant expressions. **Syntax**: diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 0c8fec691bf3c9..b6f1407436ed4f 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -237,6 +237,8 @@ Non-comprehensive list of changes in this release * Since MSVC 19.33 added undocumented attribute ``[[msvc::constexpr]]``, this release adds the attribute as well. * Added ``#pragma clang fp reciprocal``. +* Builtins ``__builtin_shufflevector()`` and ``__builtin_convertvector()`` may now be used within constant + expressions. New Compiler Flags ------------------ diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index f6aeee1a4e935d..e8afa10fe7aaac 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -2702,7 +2702,8 @@ static bool checkFloatingPointResult(EvalInfo &Info, const Expr *E, static bool HandleFloatToFloatCast(EvalInfo &Info, const Expr *E, QualType SrcType, QualType DestType, APFloat &Result) { - assert(isa<CastExpr>(E) || isa<CompoundAssignOperator>(E)); + assert(isa<CastExpr>(E) || isa<CompoundAssignOperator>(E) || + isa<ConvertVectorExpr>(E)); llvm::RoundingMode RM = getActiveRoundingMode(Info, E); APFloat::opStatus St; APFloat Value = Result; @@ -10643,6 +10644,9 @@ namespace { bool VisitUnaryImag(const UnaryOperator *E); bool VisitBinaryOperator(const BinaryOperator *E); bool VisitUnaryOperator(const UnaryOperator *E); + bool VisitConvertVectorExpr(const ConvertVectorExpr *E); + bool VisitShuffleVectorExpr(const ShuffleVectorExpr *E); + // FIXME: Missing: conditional operator (for GNU // conditional select), shufflevector, ExtVectorElementExpr }; @@ -10895,6 +10899,138 @@ bool VectorExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { return Success(APValue(ResultElements.data(), ResultElements.size()), E); } +static bool EvaluateVectorOrLValue(APValue &Result, EvalInfo &Info, + const Expr *E, const QualType &Type) { + if (!Evaluate(Result, Info, E)) + return false; + + if (Result.isLValue()) { + // Source of the data is an lvalue; Manually handle the lvalue as if + // it was an rvalue to get the current APValue. + LValue LValueFound; + LValueFound.setFrom(Info.Ctx, Result); + if (!handleLValueToRValueConversion(Info, E, Type, LValueFound, Result)) { + return false; + } + } + + if (!Result.isVector()) { + return false; + } + return true; +} + +static bool handleVectorConversion(EvalInfo &Info, const FPOptions FPO, + const Expr *E, QualType SourceTy, + QualType DestTy, APValue const &Original, + APValue &Result) { + if (SourceTy->isIntegerType()) { + if (DestTy->isRealFloatingType()) { + Result = APValue(APFloat(0.0)); + return HandleIntToFloatCast(Info, E, FPO, SourceTy, Original.getInt(), + DestTy, Result.getFloat()); + } + if (DestTy->isIntegerType()) { + Result = APValue( + HandleIntToIntCast(Info, E, DestTy, SourceTy, Original.getInt())); + return true; + } + } else if (SourceTy->isRealFloatingType()) { + if (DestTy->isRealFloatingType()) { + Result = Original; + return HandleFloatToFloatCast(Info, E, SourceTy, DestTy, + Result.getFloat()); + } + if (DestTy->isIntegerType()) { + Result = APValue(APSInt()); + return HandleFloatToIntCast(Info, E, SourceTy, Original.getFloat(), + DestTy, Result.getInt()); + } + } + return false; +} + +bool VectorExprEvaluator::VisitConvertVectorExpr(const ConvertVectorExpr *E) { + APValue Source; + QualType SourceVecType = E->getSrcExpr()->getType(); + if (!EvaluateVectorOrLValue(Source, Info, E->getSrcExpr(), SourceVecType)) + return false; + + QualType DestTy = E->getType()->castAs<VectorType>()->getElementType(); + QualType SourceTy = SourceVecType->castAs<VectorType>()->getElementType(); + + const FPOptions FPO = E->getFPFeaturesInEffect(Info.Ctx.getLangOpts()); + + SmallVector<APValue, 4> ResultElements; + ResultElements.reserve(Source.getVectorLength()); + for (unsigned EltNum = 0; EltNum < Source.getVectorLength(); ++EltNum) { + APValue Elt; + if (!handleVectorConversion(Info, FPO, E, SourceTy, DestTy, + Source.getVectorElt(EltNum), Elt)) + return false; + ResultElements.push_back(std::move(Elt)); + } + + return Success(APValue(ResultElements.data(), ResultElements.size()), E); +} + +static bool handleVectorShuffle(EvalInfo &Info, const ShuffleVectorExpr *E, + QualType ElemType, APValue const &VecVal1, + APValue const &VecVal2, unsigned EltNum, + APValue &Result) { + unsigned const TotalElementsInAVector = VecVal1.getVectorLength(); + + Expr const *IndexExpr = E->getExpr(2 + EltNum); + APSInt IndexVal; + if (!EvaluateInteger(IndexExpr, IndexVal, Info)) { + return false; + } + + uint32_t index = IndexVal.getZExtValue(); + // The spec says that -1 should be treated as undef for optimizations, + // but in constexpr we need to choose a value. We'll choose 0. + if (index >= TotalElementsInAVector * 2) { + index = 0; + } + + if (index >= TotalElementsInAVector) { + Result = VecVal2.getVectorElt(index - TotalElementsInAVector); + } else { + Result = VecVal1.getVectorElt(index); + } + return true; +} + +bool VectorExprEvaluator::VisitShuffleVectorExpr(const ShuffleVectorExpr *E) { + APValue VecVal1; + const Expr *Vec1 = E->getExpr(0); + if (!EvaluateVectorOrLValue(VecVal1, Info, Vec1, Vec1->getType())) + return false; + APValue VecVal2; + const Expr *Vec2 = E->getExpr(1); + if (!EvaluateVectorOrLValue(VecVal2, Info, Vec2, Vec2->getType())) + return false; + + VectorType const *DestVecTy = E->getType()->castAs<VectorType>(); + if (!DestVecTy) { + return false; + } + QualType DestElTy = DestVecTy->getElementType(); + + auto TotalElementsInOutputVector = DestVecTy->getNumElements(); + + SmallVector<APValue, 4> ResultElements; + ResultElements.reserve(TotalElementsInOutputVector); + for (unsigned EltNum = 0; EltNum < TotalElementsInOutputVector; ++EltNum) { + APValue Elt; + if (!handleVectorShuffle(Info, E, DestElTy, VecVal1, VecVal2, EltNum, Elt)) + return false; + ResultElements.push_back(std::move(Elt)); + } + + return Success(APValue(ResultElements.data(), ResultElements.size()), E); +} + //===----------------------------------------------------------------------===// // Array Evaluation //===----------------------------------------------------------------------===// diff --git a/clang/test/Sema/constant-builtins-2.c b/clang/test/Sema/constant-builtins-2.c index 2bdd7b06daabfe..c6bb602149e193 100644 --- a/clang/test/Sema/constant-builtins-2.c +++ b/clang/test/Sema/constant-builtins-2.c @@ -302,3 +302,64 @@ extern __typeof__(__builtin_expect(0, 0)) bi0; // Strings int array1[__builtin_strlen("ab\0cd")]; int array2[(sizeof(array1)/sizeof(int)) == 2? 1 : -1]; + +typedef double vector4double __attribute__((__vector_size__(32))); +typedef float vector4float __attribute__((__vector_size__(16))); +typedef long long vector4long __attribute__((__vector_size__(32))); +typedef int vector4int __attribute__((__vector_size__(16))); +typedef short vector4short __attribute__((__vector_size__(8))); +typedef char vector4char __attribute__((__vector_size__(4))); +typedef double vector8double __attribute__((__vector_size__(64))); +typedef float vector8float __attribute__((__vector_size__(32))); +typedef long long vector8long __attribute__((__vector_size__(64))); +typedef int vector8int __attribute__((__vector_size__(32))); +typedef short vector8short __attribute__((__vector_size__(16))); +typedef char vector8char __attribute__((__vector_size__(8))); + +// Convert vector +#define CHECK_NUM(__size, __typeFrom, __typeTo, ...) \ + vector##__size##__typeTo \ + from_##vector##__size##__typeFrom##_to_##vector##__size##__typeTo##_var = \ + __builtin_convertvector((vector##__size##__typeFrom){__VA_ARGS__}, \ + vector##__size##__typeTo); +#define CHECK_TO_ALL_TYPES(__size, __typeFrom, ...) \ + CHECK_NUM(__size, __typeFrom, double, __VA_ARGS__) \ + CHECK_NUM(__size, __typeFrom, float, __VA_ARGS__) \ + CHECK_NUM(__size, __typeFrom, long, __VA_ARGS__) \ + CHECK_NUM(__size, __typeFrom, int, __VA_ARGS__) \ + CHECK_NUM(__size, __typeFrom, short, __VA_ARGS__) \ + CHECK_NUM(__size, __typeFrom, char, __VA_ARGS__) + +#define CHECK_ALL_COMBINATIONS(__size, ...) \ + CHECK_TO_ALL_TYPES(__size, double, __VA_ARGS__) \ + CHECK_TO_ALL_TYPES(__size, float, __VA_ARGS__) \ + CHECK_TO_ALL_TYPES(__size, long, __VA_ARGS__) \ + CHECK_TO_ALL_TYPES(__size, int, __VA_ARGS__) \ + CHECK_TO_ALL_TYPES(__size, short, __VA_ARGS__) \ + CHECK_TO_ALL_TYPES(__size, char, __VA_ARGS__) + +CHECK_ALL_COMBINATIONS(4, 0, 1, 2, 3); +CHECK_ALL_COMBINATIONS(8, 0, 1, 2, 3, 4, 5, 6, 7); +#undef CHECK_ALL_COMBINATIONS +#undef CHECK_TO_ALL_TYPES +#undef CHECK_NUM + +// Shuffle vector +vector4int const vector4intConst1 = {0, 1, 2, 3}; +vector4int const vector4intConst2 = {4, 5, 6, 7}; +vector8int const vector8intConst = {}; + +vector4int vectorShuffle1 = + __builtin_shufflevector(vector4intConst1, vector4intConst2, 0, 1, 2, 3); +vector4int vectorShuffle2 = + __builtin_shufflevector(vector4intConst1, vector4intConst2, 4, 5, 6, 7); +vector4int vectorShuffle3 = + __builtin_shufflevector(vector4intConst1, vector4intConst2, -1, -1, -1, -1); +vector4int vectorShuffle4 = + __builtin_shufflevector(vector4intConst1, vector4intConst2, 0, 2, 4, 6); +vector8int vectorShuffle5 = __builtin_shufflevector( + vector8intConst, vector8intConst, 0, 2, 4, 6, 8, 10, 12, 14); +vector4int vectorShuffle6 = __builtin_shufflevector( + vector8intConst, vector8intConst, 0, 2, 4, 6); +vector8int vectorShuffle7 = + __builtin_shufflevector(vector4intConst1, vector4intConst2, 0, 2, 4, 6, 1, 3, 5, 7); `````````` </details> https://github.com/llvm/llvm-project/pull/76615 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits