Pol Marcet =?utf-8?q?Sardà?= <polmarcetsa...@gmail.com>, Pol Marcet =?utf-8?q?Sardà?= <polmarcetsa...@gmail.com>,Pol M <polmarcetsa...@gmail.com>, Pol Marcet =?utf-8?q?Sardà?= <polmarcetsa...@gmail.com> Message-ID: In-Reply-To: <llvm.org/llvm/llvm-project/pull/76...@github.com>
https://github.com/Destroyerrrocket updated https://github.com/llvm/llvm-project/pull/76615 >From cba67a73ea1e59eb8eeb4e702d77f329028f4c22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pol=20Marcet=20Sard=C3=A0?= <polmarcetsa...@gmail.com> Date: Sat, 30 Dec 2023 13:59:00 +0100 Subject: [PATCH 1/5] [clang] Constexpr for __builtin_shufflevector and __builtin_convertvector 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. --- clang/docs/LanguageExtensions.rst | 5 +- clang/docs/ReleaseNotes.rst | 2 + clang/lib/AST/ExprConstant.cpp | 138 +++++++++++++++++++++++++- clang/test/Sema/constant-builtins-2.c | 61 ++++++++++++ 4 files changed, 203 insertions(+), 3 deletions(-) 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); >From 28177a86c8bdfc1c0f0077419fd2def4a1854c3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pol=20Marcet=20Sard=C3=A0?= <polmarcetsa...@gmail.com> Date: Thu, 4 Jan 2024 11:26:08 +0100 Subject: [PATCH 2/5] Address suggestions from RKSimon --- clang/lib/AST/ExprConstant.cpp | 28 +++--- clang/test/Sema/constant-builtins-2.c | 61 ------------- clang/test/Sema/constat_builtins_vector.cpp | 99 +++++++++++++++++++++ 3 files changed, 110 insertions(+), 78 deletions(-) create mode 100644 clang/test/Sema/constat_builtins_vector.cpp diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index e8afa10fe7aaac..711d306ceb8e58 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -10909,15 +10909,11 @@ static bool EvaluateVectorOrLValue(APValue &Result, EvalInfo &Info, // it was an rvalue to get the current APValue. LValue LValueFound; LValueFound.setFrom(Info.Ctx, Result); - if (!handleLValueToRValueConversion(Info, E, Type, LValueFound, Result)) { + if (!handleLValueToRValueConversion(Info, E, Type, LValueFound, Result)) return false; - } } - if (!Result.isVector()) { - return false; - } - return true; + return Result.isVector(); } static bool handleVectorConversion(EvalInfo &Info, const FPOptions FPO, @@ -10961,9 +10957,10 @@ bool VectorExprEvaluator::VisitConvertVectorExpr(const ConvertVectorExpr *E) { const FPOptions FPO = E->getFPFeaturesInEffect(Info.Ctx.getLangOpts()); + auto SourceLen = Source.getVectorLength(); SmallVector<APValue, 4> ResultElements; - ResultElements.reserve(Source.getVectorLength()); - for (unsigned EltNum = 0; EltNum < Source.getVectorLength(); ++EltNum) { + ResultElements.reserve(SourceLen); + for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) { APValue Elt; if (!handleVectorConversion(Info, FPO, E, SourceTy, DestTy, Source.getVectorElt(EltNum), Elt)) @@ -10982,22 +10979,19 @@ static bool handleVectorShuffle(EvalInfo &Info, const ShuffleVectorExpr *E, Expr const *IndexExpr = E->getExpr(2 + EltNum); APSInt IndexVal; - if (!EvaluateInteger(IndexExpr, IndexVal, Info)) { + 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) { + if (index >= TotalElementsInAVector * 2) index = 0; - } - if (index >= TotalElementsInAVector) { + if (index >= TotalElementsInAVector) Result = VecVal2.getVectorElt(index - TotalElementsInAVector); - } else { + else Result = VecVal1.getVectorElt(index); - } return true; } @@ -11012,9 +11006,9 @@ bool VectorExprEvaluator::VisitShuffleVectorExpr(const ShuffleVectorExpr *E) { return false; VectorType const *DestVecTy = E->getType()->castAs<VectorType>(); - if (!DestVecTy) { + if (!DestVecTy) return false; - } + QualType DestElTy = DestVecTy->getElementType(); auto TotalElementsInOutputVector = DestVecTy->getNumElements(); diff --git a/clang/test/Sema/constant-builtins-2.c b/clang/test/Sema/constant-builtins-2.c index c6bb602149e193..2bdd7b06daabfe 100644 --- a/clang/test/Sema/constant-builtins-2.c +++ b/clang/test/Sema/constant-builtins-2.c @@ -302,64 +302,3 @@ 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); diff --git a/clang/test/Sema/constat_builtins_vector.cpp b/clang/test/Sema/constat_builtins_vector.cpp new file mode 100644 index 00000000000000..afd5904e7afeab --- /dev/null +++ b/clang/test/Sema/constat_builtins_vector.cpp @@ -0,0 +1,99 @@ +// RUN: %clang_cc1 -verify -std=c++2a -fsyntax-only %s +// expected-no-diagnostics + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define LITTLE_END 1 +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define LITTLE_END 0 +#else +#error "huh?" +#endif + +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))); + +#define CHECK_NUM(__size, __typeFrom, __typeTo, ...) \ + constexpr 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__) \ + static_assert( \ + __builtin_bit_cast( \ + unsigned, \ + __builtin_shufflevector( \ + from_vector##__size##__typeFrom##_to_vector##__size##char_var, \ + from_vector##__size##__typeFrom##_to_vector##__size##char_var, \ + 0, 1, 2, 3)) == (LITTLE_END ? 0x03020100 : 0x00010203)); \ + static_assert( \ + __builtin_bit_cast( \ + unsigned long long, \ + __builtin_shufflevector( \ + from_vector##__size##__typeFrom##_to_vector##__size##short_var, \ + from_vector##__size##__typeFrom##_to_vector##__size##short_var, \ + 0, 1, 2, 3)) == \ + (LITTLE_END ? 0x0003000200010000 : 0x0000000100020003)); + +#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 +constexpr vector4char vector4charConst1 = {0, 1, 2, 3}; +constexpr vector4char vector4charConst2 = {4, 5, 6, 7}; +constexpr vector8char vector8intConst = {8, 9, 10, 11, 12, 13, 14, 15}; + +constexpr vector4char vectorShuffle1 = + __builtin_shufflevector(vector4charConst1, vector4charConst2, 0, 1, 2, 3); +static_assert(__builtin_bit_cast(unsigned, vectorShuffle1) == + (LITTLE_END ? 0x03020100 : 0x00010203)); +constexpr vector4char vectorShuffle2 = + __builtin_shufflevector(vector4charConst1, vector4charConst2, 4, 5, 6, 7); +static_assert(__builtin_bit_cast(unsigned, vectorShuffle2) == + (LITTLE_END ? 0x07060504 : 0x04050607)); +constexpr vector4char vectorShuffle3 = __builtin_shufflevector( + vector4charConst1, vector4charConst2, -1, -1, -1, -1); +static_assert(__builtin_bit_cast(unsigned, vectorShuffle3) == + (LITTLE_END ? 0x00000000 : 0x00000000)); +constexpr vector4char vectorShuffle4 = + __builtin_shufflevector(vector4charConst1, vector4charConst2, 0, 2, 4, 6); +static_assert(__builtin_bit_cast(unsigned, vectorShuffle4) == + (LITTLE_END ? 0x06040200 : 0x00020406)); +constexpr vector8char vectorShuffle5 = __builtin_shufflevector( + vector8intConst, vector8intConst, 0, 2, 4, 6, 8, 10, 12, 14); +static_assert(__builtin_bit_cast(unsigned long long, vectorShuffle5) == + (LITTLE_END ? 0x0E0C0A080E0C0A08 : 0x080A0C0E080A0C0E)); +constexpr vector4char vectorShuffle6 = + __builtin_shufflevector(vector8intConst, vector8intConst, 0, 2, 4, 6); +static_assert(__builtin_bit_cast(unsigned, vectorShuffle6) == + (LITTLE_END ? 0x0E0C0A08 : 0x080A0C0E)); +constexpr vector8char vectorShuffle7 = __builtin_shufflevector( + vector4charConst1, vector4charConst2, 0, 2, 4, 6, 1, 3, 5, 7); +static_assert(__builtin_bit_cast(unsigned long long, vectorShuffle7) == + (LITTLE_END ? 0x0705030106040200 : 0x0002040601030507)); >From bb908ba2eb02d60a3f481e0547a26587d0fca340 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pol=20Marcet=20Sard=C3=A0?= <polmarcetsa...@gmail.com> Date: Thu, 4 Jan 2024 12:31:08 +0100 Subject: [PATCH 3/5] Fix typo in file name --- .../{constat_builtins_vector.cpp => constant_builtins_vector.cpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename clang/test/Sema/{constat_builtins_vector.cpp => constant_builtins_vector.cpp} (100%) diff --git a/clang/test/Sema/constat_builtins_vector.cpp b/clang/test/Sema/constant_builtins_vector.cpp similarity index 100% rename from clang/test/Sema/constat_builtins_vector.cpp rename to clang/test/Sema/constant_builtins_vector.cpp >From 3b7ec630c020182ddc251b9bec3bcc07c752fb0f Mon Sep 17 00:00:00 2001 From: Pol M <polmarcetsa...@gmail.com> Date: Fri, 5 Jan 2024 15:34:02 +0100 Subject: [PATCH 4/5] Update ReleaseNotes.rst --- clang/docs/ReleaseNotes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index b6f1407436ed4f..d8716673fbdcba 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -238,7 +238,7 @@ Non-comprehensive list of changes in this release * Added ``#pragma clang fp reciprocal``. * Builtins ``__builtin_shufflevector()`` and ``__builtin_convertvector()`` may now be used within constant - expressions. + expressions. New Compiler Flags ------------------ >From a97fd838760389bc96dc5e3764f09b088bc8e207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pol=20Marcet=20Sard=C3=A0?= <polmarcetsa...@gmail.com> Date: Sun, 31 Mar 2024 18:18:45 +0200 Subject: [PATCH 5/5] Following the review of sethp, I have made the following changes: -- Added diagnostic for the undefined shuffle of -1 -- Validated support for _BitInt -- A bunch of other minnor tweaks here and there --- .../clang/Basic/DiagnosticSemaKinds.td | 2 + clang/lib/AST/ExprConstant.cpp | 69 ++++++++----------- clang/test/Sema/constant_builtins_vector.cpp | 51 ++++++++++---- clang/test/Sema/convertvector.c | 3 + 4 files changed, 70 insertions(+), 55 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index aebb7d9b945c33..76ab1fbd0a6cd0 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10217,6 +10217,8 @@ def err_shufflevector_nonconstant_argument : Error< def err_shufflevector_argument_too_large : Error< "index for __builtin_shufflevector must be less than the total number " "of vector elements">; +def err_shufflevector_minus_one_is_undefined_behavior_constexpr : Error< + "index for __builtin_shufflevector must be within the bounds of the input vectors in a constexpr context. An index of -1 at position %0 was found. -1 is only allowed at runtime.">; def err_convertvector_non_vector : Error< "first argument to __builtin_convertvector must be a vector">; diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 711d306ceb8e58..dedd1b115c75de 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -2702,8 +2702,11 @@ 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) || - isa<ConvertVectorExpr>(E)); + assert((isa<CastExpr>(E) || isa<CompoundAssignOperator>(E) || + isa<ConvertVectorExpr>(E)) && + "HandleFloatToFloatCast has been checked with only CastExpr, " + "CompoundAssignOperator and ConvertVectorExpr. Please either validate " + "the new expression or address the root cause of this usage."); llvm::RoundingMode RM = getActiveRoundingMode(Info, E); APFloat::opStatus St; APFloat Value = Result; @@ -10648,7 +10651,7 @@ namespace { bool VisitShuffleVectorExpr(const ShuffleVectorExpr *E); // FIXME: Missing: conditional operator (for GNU - // conditional select), shufflevector, ExtVectorElementExpr + // conditional select), ExtVectorElementExpr }; } // end anonymous namespace @@ -10899,27 +10902,10 @@ 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; - } - - return Result.isVector(); -} - -static bool handleVectorConversion(EvalInfo &Info, const FPOptions FPO, - const Expr *E, QualType SourceTy, - QualType DestTy, APValue const &Original, - APValue &Result) { +static bool handleVectorElementCast(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)); @@ -10949,7 +10935,7 @@ static bool handleVectorConversion(EvalInfo &Info, const FPOptions FPO, bool VectorExprEvaluator::VisitConvertVectorExpr(const ConvertVectorExpr *E) { APValue Source; QualType SourceVecType = E->getSrcExpr()->getType(); - if (!EvaluateVectorOrLValue(Source, Info, E->getSrcExpr(), SourceVecType)) + if (!EvaluateAsRValue(Info, E->getSrcExpr(), Source)) return false; QualType DestTy = E->getType()->castAs<VectorType>()->getElementType(); @@ -10962,8 +10948,8 @@ bool VectorExprEvaluator::VisitConvertVectorExpr(const ConvertVectorExpr *E) { ResultElements.reserve(SourceLen); for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) { APValue Elt; - if (!handleVectorConversion(Info, FPO, E, SourceTy, DestTy, - Source.getVectorElt(EltNum), Elt)) + if (!handleVectorElementCast(Info, FPO, E, SourceTy, DestTy, + Source.getVectorElt(EltNum), Elt)) return false; ResultElements.push_back(std::move(Elt)); } @@ -10975,21 +10961,24 @@ 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; + unsigned const TotalElementsInInputVector = VecVal1.getVectorLength(); - uint32_t index = IndexVal.getZExtValue(); + APSInt IndexVal = E->getShuffleMaskIdx(Info.Ctx, EltNum); + int64_t index = IndexVal.getExtValue(); // 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 == -1) { + Info.FFDiag( + E, diag::err_shufflevector_minus_one_is_undefined_behavior_constexpr) + << EltNum; + return false; + } + + if (index < 0 || index >= TotalElementsInInputVector * 2) + llvm_unreachable("Out of bounds shuffle index"); - if (index >= TotalElementsInAVector) - Result = VecVal2.getVectorElt(index - TotalElementsInAVector); + if (index >= TotalElementsInInputVector) + Result = VecVal2.getVectorElt(index - TotalElementsInInputVector); else Result = VecVal1.getVectorElt(index); return true; @@ -10998,11 +10987,11 @@ static bool handleVectorShuffle(EvalInfo &Info, const ShuffleVectorExpr *E, bool VectorExprEvaluator::VisitShuffleVectorExpr(const ShuffleVectorExpr *E) { APValue VecVal1; const Expr *Vec1 = E->getExpr(0); - if (!EvaluateVectorOrLValue(VecVal1, Info, Vec1, Vec1->getType())) + if (!EvaluateAsRValue(Info, Vec1, VecVal1)) return false; APValue VecVal2; const Expr *Vec2 = E->getExpr(1); - if (!EvaluateVectorOrLValue(VecVal2, Info, Vec2, Vec2->getType())) + if (!EvaluateAsRValue(Info, Vec2, VecVal2)) return false; VectorType const *DestVecTy = E->getType()->castAs<VectorType>(); diff --git a/clang/test/Sema/constant_builtins_vector.cpp b/clang/test/Sema/constant_builtins_vector.cpp index afd5904e7afeab..73f8eed22abcbd 100644 --- a/clang/test/Sema/constant_builtins_vector.cpp +++ b/clang/test/Sema/constant_builtins_vector.cpp @@ -1,5 +1,4 @@ -// RUN: %clang_cc1 -verify -std=c++2a -fsyntax-only %s -// expected-no-diagnostics +// RUN: %clang_cc1 -verify -std=c++2a -fsyntax-only -Wno-bit-int-extension %s #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #define LITTLE_END 1 @@ -9,18 +8,29 @@ #error "huh?" #endif +// We also support _BitInt as long as it is >=8 and a power of 2. +typedef _BitInt(8) BitInt8; +typedef _BitInt(32) BitInt32; +typedef _BitInt(128) BitInt128; + 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 BitInt8 vector4BitInt8 __attribute__((__vector_size__(4))); +typedef BitInt32 vector4BitInt32 __attribute__((__vector_size__(16))); +typedef BitInt128 vector4BitInt128 __attribute__((__vector_size__(64))); 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))); +typedef BitInt8 vector8BitInt8 __attribute__((__vector_size__(8))); +typedef BitInt32 vector8BitInt32 __attribute__((__vector_size__(32))); +typedef BitInt128 vector8BitInt128 __attribute__((__vector_size__(128))); #define CHECK_NUM(__size, __typeFrom, __typeTo, ...) \ constexpr vector##__size##__typeTo \ @@ -34,6 +44,9 @@ typedef char vector8char __attribute__((__vector_size__(8))); CHECK_NUM(__size, __typeFrom, int, __VA_ARGS__) \ CHECK_NUM(__size, __typeFrom, short, __VA_ARGS__) \ CHECK_NUM(__size, __typeFrom, char, __VA_ARGS__) \ + CHECK_NUM(__size, __typeFrom, BitInt8, __VA_ARGS__) \ + CHECK_NUM(__size, __typeFrom, BitInt32, __VA_ARGS__) \ + CHECK_NUM(__size, __typeFrom, BitInt128, __VA_ARGS__) \ static_assert( \ __builtin_bit_cast( \ unsigned, \ @@ -56,7 +69,10 @@ typedef char vector8char __attribute__((__vector_size__(8))); 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_TO_ALL_TYPES(__size, char, __VA_ARGS__) \ + CHECK_TO_ALL_TYPES(__size, BitInt8, __VA_ARGS__) \ + CHECK_TO_ALL_TYPES(__size, BitInt32, __VA_ARGS__) \ + CHECK_TO_ALL_TYPES(__size, BitInt128, __VA_ARGS__) CHECK_ALL_COMBINATIONS(4, 0, 1, 2, 3); CHECK_ALL_COMBINATIONS(8, 0, 1, 2, 3, 4, 5, 6, 7); @@ -77,23 +93,28 @@ constexpr vector4char vectorShuffle2 = __builtin_shufflevector(vector4charConst1, vector4charConst2, 4, 5, 6, 7); static_assert(__builtin_bit_cast(unsigned, vectorShuffle2) == (LITTLE_END ? 0x07060504 : 0x04050607)); -constexpr vector4char vectorShuffle3 = __builtin_shufflevector( - vector4charConst1, vector4charConst2, -1, -1, -1, -1); -static_assert(__builtin_bit_cast(unsigned, vectorShuffle3) == - (LITTLE_END ? 0x00000000 : 0x00000000)); -constexpr vector4char vectorShuffle4 = +constexpr vector4char vectorShuffle3 = __builtin_shufflevector(vector4charConst1, vector4charConst2, 0, 2, 4, 6); -static_assert(__builtin_bit_cast(unsigned, vectorShuffle4) == +static_assert(__builtin_bit_cast(unsigned, vectorShuffle3) == (LITTLE_END ? 0x06040200 : 0x00020406)); -constexpr vector8char vectorShuffle5 = __builtin_shufflevector( +constexpr vector8char vectorShuffle4 = __builtin_shufflevector( vector8intConst, vector8intConst, 0, 2, 4, 6, 8, 10, 12, 14); -static_assert(__builtin_bit_cast(unsigned long long, vectorShuffle5) == +static_assert(__builtin_bit_cast(unsigned long long, vectorShuffle4) == (LITTLE_END ? 0x0E0C0A080E0C0A08 : 0x080A0C0E080A0C0E)); -constexpr vector4char vectorShuffle6 = +constexpr vector4char vectorShuffle5 = __builtin_shufflevector(vector8intConst, vector8intConst, 0, 2, 4, 6); -static_assert(__builtin_bit_cast(unsigned, vectorShuffle6) == +static_assert(__builtin_bit_cast(unsigned, vectorShuffle5) == (LITTLE_END ? 0x0E0C0A08 : 0x080A0C0E)); -constexpr vector8char vectorShuffle7 = __builtin_shufflevector( +constexpr vector8char vectorShuffle6 = __builtin_shufflevector( vector4charConst1, vector4charConst2, 0, 2, 4, 6, 1, 3, 5, 7); -static_assert(__builtin_bit_cast(unsigned long long, vectorShuffle7) == +static_assert(__builtin_bit_cast(unsigned long long, vectorShuffle6) == (LITTLE_END ? 0x0705030106040200 : 0x0002040601030507)); + +constexpr vector4char + vectorShuffleFail1 = // expected-error {{constexpr variable 'vectorShuffleFail1'\ + must be initialized by a constant expression}} + __builtin_shufflevector( // expected-error {{index for __builtin_shufflevector must be within\ + the bounds of the input vectors in a constexpr context. An index of\ + -1 at position 0 was found. -1 is only allowed at runtime.}} + vector4charConst1, + vector4charConst2, -1, -1, -1, -1); diff --git a/clang/test/Sema/convertvector.c b/clang/test/Sema/convertvector.c index 8ae43c3ba3d493..1ff04af9098185 100644 --- a/clang/test/Sema/convertvector.c +++ b/clang/test/Sema/convertvector.c @@ -15,3 +15,6 @@ vector8float foo3(double x) { return __builtin_convertvector(x, vector8float); // expected-error {{must be a vector}} } +float foo4(float x) { + return __builtin_convertvector(x, float); // expected-error {{first argument to __builtin_convertvector must be a vector}} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits