https://github.com/DaMatrix updated https://github.com/llvm/llvm-project/pull/66894
>From 8768741800aae37a825864e2ee782484ed073ce9 Mon Sep 17 00:00:00 2001 From: DaPorkchop_ <daporkc...@daporkchop.net> Date: Sun, 13 Aug 2023 22:39:12 +0200 Subject: [PATCH] [clang] Implement constexpr bit_cast for vectors --- clang/lib/AST/ExprConstant.cpp | 181 ++++++++++++------ .../SemaCXX/constexpr-builtin-bit-cast.cpp | 38 ++++ 2 files changed, 162 insertions(+), 57 deletions(-) diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index fea06b97259fe31..8cd6a0e390ee0f8 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -2732,6 +2732,92 @@ static bool truncateBitfieldValue(EvalInfo &Info, const Expr *E, return true; } +static bool BitcastAPIntToVector(EvalInfo &Info, const VectorType *VTy, + const llvm::APInt &SValInt, + SmallVectorImpl<APValue> &Elts) { + QualType EltTy = VTy->getElementType(); + unsigned NElts = VTy->getNumElements(); + unsigned EltSize = + VTy->isExtVectorBoolType() ? 1 : Info.Ctx.getTypeSize(EltTy); + + if ((NElts * EltSize) % Info.Ctx.getCharWidth() != 0) { + // The vector's size in bits is not a multiple of the target's byte size, + // so its layout is unspecified. For now, we'll simply treat these cases as + // unsupported (this should only be possible with OpenCL bool vectors whose + // element count isn't a multiple of the byte size). + return false; + } + + Elts.reserve(NElts); + bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); + if (EltTy->isRealFloatingType()) { + const llvm::fltSemantics &Sem = Info.Ctx.getFloatTypeSemantics(EltTy); + unsigned FloatEltSize = EltSize; + if (&Sem == &APFloat::x87DoubleExtended()) + FloatEltSize = 80; + for (unsigned i = 0; i < NElts; i++) { + llvm::APInt Elt; + if (BigEndian) + Elt = SValInt.rotl(i * EltSize + FloatEltSize).trunc(FloatEltSize); + else + Elt = SValInt.rotr(i * EltSize).trunc(FloatEltSize); + Elts.push_back(APValue(APFloat(Sem, Elt))); + } + } else if (EltTy->isIntegerType()) { + for (unsigned i = 0; i < NElts; i++) { + llvm::APInt Elt; + if (BigEndian) + Elt = SValInt.rotl(i * EltSize + EltSize).zextOrTrunc(EltSize); + else + Elt = SValInt.rotr(i * EltSize).zextOrTrunc(EltSize); + Elts.push_back(APValue(APSInt(Elt, !EltTy->isSignedIntegerType()))); + } + } else { + return false; + } + return true; +} + +static bool BitcastVectorToAPInt(EvalInfo &Info, const VectorType *VTy, + const APValue &SVal, llvm::APInt &Res) { + QualType EltTy = VTy->getElementType(); + unsigned NElts = VTy->getNumElements(); + unsigned EltSize = + VTy->isExtVectorBoolType() ? 1 : Info.Ctx.getTypeSize(EltTy); + unsigned VecSize = Info.Ctx.getTypeSize(VTy); + + if ((NElts * EltSize) % Info.Ctx.getCharWidth() != 0) { + // The vector's size in bits is not a multiple of the target's byte size, + // so its layout is unspecified. For now, we'll simply treat these cases as + // unsupported (this should only be possible with OpenCL bool vectors whose + // element count isn't a multiple of the byte size). + return false; + } + + bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); + Res = llvm::APInt::getZero(VecSize); + for (unsigned i = 0; i < SVal.getVectorLength(); i++) { + const APValue &Elt = SVal.getVectorElt(i); + llvm::APInt EltAsInt; + if (Elt.isInt()) { + EltAsInt = Elt.getInt(); + } else if (Elt.isFloat()) { + EltAsInt = Elt.getFloat().bitcastToAPInt(); + } else { + // Don't try to handle vectors of anything other than int or float + // (not sure if it's possible to hit this case). + return false; + } + unsigned BaseEltSize = EltAsInt.getBitWidth(); + if (BigEndian) + Res |= EltAsInt.zextOrTrunc(VecSize).rotr(i * EltSize + BaseEltSize); + else + Res |= EltAsInt.zextOrTrunc(VecSize).rotl(i * EltSize); + } + + return true; +} + static bool EvalAndBitcastToAPInt(EvalInfo &Info, const Expr *E, llvm::APInt &Res) { APValue SVal; @@ -2745,34 +2831,9 @@ static bool EvalAndBitcastToAPInt(EvalInfo &Info, const Expr *E, Res = SVal.getFloat().bitcastToAPInt(); return true; } - if (SVal.isVector()) { - QualType VecTy = E->getType(); - unsigned VecSize = Info.Ctx.getTypeSize(VecTy); - QualType EltTy = VecTy->castAs<VectorType>()->getElementType(); - unsigned EltSize = Info.Ctx.getTypeSize(EltTy); - bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); - Res = llvm::APInt::getZero(VecSize); - for (unsigned i = 0; i < SVal.getVectorLength(); i++) { - APValue &Elt = SVal.getVectorElt(i); - llvm::APInt EltAsInt; - if (Elt.isInt()) { - EltAsInt = Elt.getInt(); - } else if (Elt.isFloat()) { - EltAsInt = Elt.getFloat().bitcastToAPInt(); - } else { - // Don't try to handle vectors of anything other than int or float - // (not sure if it's possible to hit this case). - Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); - return false; - } - unsigned BaseEltSize = EltAsInt.getBitWidth(); - if (BigEndian) - Res |= EltAsInt.zextOrTrunc(VecSize).rotr(i*EltSize+BaseEltSize); - else - Res |= EltAsInt.zextOrTrunc(VecSize).rotl(i*EltSize); - } + if (SVal.isVector() && + BitcastVectorToAPInt(Info, E->getType()->castAs<VectorType>(), SVal, Res)) return true; - } // Give up if the input isn't an int, float, or vector. For example, we // reject "(v4i16)(intptr_t)&a". Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); @@ -7005,10 +7066,11 @@ class APValueToBufferConverter { return visitArray(Val, Ty, Offset); case APValue::Struct: return visitRecord(Val, Ty, Offset); + case APValue::Vector: + return visitVector(Val, Ty, Offset); case APValue::ComplexInt: case APValue::ComplexFloat: - case APValue::Vector: case APValue::FixedPoint: // FIXME: We should support these. @@ -7095,6 +7157,22 @@ class APValueToBufferConverter { return true; } + bool visitVector(const APValue &Val, QualType Ty, CharUnits Offset) { + const VectorType *VTy = Ty->castAs<VectorType>(); + + APInt Bits; + if (!BitcastVectorToAPInt(Info, VTy, Val, Bits)) + return false; + + assert(Bits.getBitWidth() == Info.Ctx.getTypeSize(Ty)); + + unsigned Width = Bits.getBitWidth(); + SmallVector<uint8_t, 8> Bytes(Width / 8); + llvm::StoreIntToMemory(Bits, &*Bytes.begin(), Width / 8); + Buffer.writeObject(Offset, Bytes); + return true; + } + bool visitInt(const APSInt &Val, QualType Ty, CharUnits Offset) { APSInt AdjustedVal = Val; unsigned Width = AdjustedVal.getBitWidth(); @@ -7103,7 +7181,7 @@ class APValueToBufferConverter { AdjustedVal = AdjustedVal.extend(Width); } - SmallVector<unsigned char, 8> Bytes(Width / 8); + SmallVector<uint8_t, 8> Bytes(Width / 8); llvm::StoreIntToMemory(AdjustedVal, &*Bytes.begin(), Width / 8); Buffer.writeObject(Offset, Bytes); return true; @@ -7304,6 +7382,21 @@ class BufferToAPValueConverter { return ArrayValue; } + std::optional<APValue> visit(const VectorType *Ty, CharUnits Offset) { + SmallVector<uint8_t, 8> Bytes; + if (!Buffer.readObject(Offset, Info.Ctx.getTypeSizeInChars(Ty), Bytes)) + return std::nullopt; + + APInt SValInt = APInt::getZero(Info.Ctx.getTypeSize(Ty)); + llvm::LoadIntFromMemory(SValInt, &*Bytes.begin(), Bytes.size()); + + SmallVector<APValue, 4> Elts; + if (!BitcastAPIntToVector(Info, Ty, SValInt, Elts)) + return std::nullopt; + + return APValue(Elts.data(), Elts.size()); + } + std::optional<APValue> visit(const Type *Ty, CharUnits Offset) { return unsupportedType(QualType(Ty, 0)); } @@ -10515,36 +10608,10 @@ bool VectorExprEvaluator::VisitCastExpr(const CastExpr *E) { llvm::APInt SValInt; if (!EvalAndBitcastToAPInt(Info, SE, SValInt)) return false; - // Extract the elements - QualType EltTy = VTy->getElementType(); - unsigned EltSize = Info.Ctx.getTypeSize(EltTy); - bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); + SmallVector<APValue, 4> Elts; - if (EltTy->isRealFloatingType()) { - const llvm::fltSemantics &Sem = Info.Ctx.getFloatTypeSemantics(EltTy); - unsigned FloatEltSize = EltSize; - if (&Sem == &APFloat::x87DoubleExtended()) - FloatEltSize = 80; - for (unsigned i = 0; i < NElts; i++) { - llvm::APInt Elt; - if (BigEndian) - Elt = SValInt.rotl(i * EltSize + FloatEltSize).trunc(FloatEltSize); - else - Elt = SValInt.rotr(i * EltSize).trunc(FloatEltSize); - Elts.push_back(APValue(APFloat(Sem, Elt))); - } - } else if (EltTy->isIntegerType()) { - for (unsigned i = 0; i < NElts; i++) { - llvm::APInt Elt; - if (BigEndian) - Elt = SValInt.rotl(i*EltSize+EltSize).zextOrTrunc(EltSize); - else - Elt = SValInt.rotr(i*EltSize).zextOrTrunc(EltSize); - Elts.push_back(APValue(APSInt(Elt, !EltTy->isSignedIntegerType()))); - } - } else { + if (!BitcastAPIntToVector(Info, VTy, SValInt, Elts)) return Error(E); - } return Success(Elts, E); } default: diff --git a/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp b/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp index a6ebe0572d063bb..2b1c9a5d3ea8a7a 100644 --- a/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp +++ b/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp @@ -463,3 +463,41 @@ static_assert(bit_cast<long double>(ld539) == fivehundredandthirtynine, ""); static_assert(round_trip<__int128_t>(34.0L)); #endif } + +namespace test_vector { + +typedef unsigned uint2 __attribute__((vector_size(2 * sizeof(unsigned)))); +typedef char byte8 __attribute__((vector_size(sizeof(unsigned long long)))); + +constexpr uint2 test_vector = { 0x0C05FEFE, 0xCAFEBABE }; + +static_assert(bit_cast<unsigned long long>(test_vector) == (LITTLE_END + ? 0xCAFEBABE0C05FEFE + : 0x0C05FEFECAFEBABE), ""); + +static_assert(round_trip<uint2>(0xCAFEBABE0C05FEFEULL), ""); +static_assert(round_trip<byte8>(0xCAFEBABE0C05FEFEULL), ""); + +typedef bool bool8 __attribute__((ext_vector_type(8))); +typedef bool bool9 __attribute__((ext_vector_type(9))); +typedef bool bool16 __attribute__((ext_vector_type(16))); +typedef bool bool17 __attribute__((ext_vector_type(17))); +typedef bool bool32 __attribute__((ext_vector_type(32))); +typedef bool bool128 __attribute__((ext_vector_type(128))); + +static_assert(bit_cast<unsigned char>(bool8{1,0,1,0,1,0,1,0}) == (LITTLE_END ? 0x55 : 0xAA), ""); +static_assert(round_trip<bool8>(static_cast<unsigned char>(0)), ""); +static_assert(round_trip<bool8>(static_cast<unsigned char>(1)), ""); +static_assert(round_trip<bool8>(static_cast<unsigned char>(0x55)), ""); + +static_assert(bit_cast<unsigned short>(bool16{1,1,1,1,1,0,0,0, 1,1,1,1,0,1,0,0}) == (LITTLE_END ? 0x2F1F : 0xF8F4), ""); + +static_assert(round_trip<bool16>(static_cast<short>(0xCAFE)), ""); +static_assert(round_trip<bool32>(static_cast<int>(0xCAFEBABE)), ""); +static_assert(round_trip<bool128>(static_cast<__int128_t>(0xCAFEBABE0C05FEFEULL)), ""); + +static_assert(bit_cast<unsigned short>(bool9{1,1,0,1,0,1,0,1,0}) == (LITTLE_END ? 0xAB : 0x1AA), ""); // expected-error{{static assertion expression is not an integral constant expression}} +static_assert(round_trip<bool9>(static_cast<unsigned short>(0)), ""); // expected-error{{static assertion expression is not an integral constant expression}} +static_assert(round_trip<bool17>(static_cast<unsigned int>(0x0001CAFE)), ""); // expected-error{{static assertion expression is not an integral constant expression}} + +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits