https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/114937
This is a special case we need to handle. We don't do bitcasting _into_ such vectors yet though. >From 762974afcfe2ba3e667f5362eddef0902ca23e97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbae...@redhat.com> Date: Tue, 5 Nov 2024 06:47:00 +0100 Subject: [PATCH] [clang][bytecode] Fix bitcasting packed bool vectors This is a special case we need to handle. We don't do bitcasting _into_ such vectors yet though. --- .../lib/AST/ByteCode/InterpBuiltinBitCast.cpp | 18 +++++--- clang/test/AST/ByteCode/builtin-bit-cast.cpp | 44 +++++++++++++++++++ 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp index e1de151af3e021..17a175a48b5df4 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp @@ -26,8 +26,8 @@ using namespace clang; using namespace clang::interp; /// Used to iterate over pointer fields. -using DataFunc = - llvm::function_ref<bool(const Pointer &P, PrimType Ty, size_t BitOffset)>; +using DataFunc = llvm::function_ref<bool(const Pointer &P, PrimType Ty, + size_t BitOffset, bool PackedBools)>; #define BITCAST_TYPE_SWITCH(Expr, B) \ do { \ @@ -89,6 +89,7 @@ struct BitcastBuffer { std::byte *getBytes(unsigned BitOffset) const { assert(BitOffset % 8 == 0); + assert(BitOffset < SizeInBits); return const_cast<std::byte *>(data() + (BitOffset / 8)); } @@ -147,7 +148,7 @@ static bool enumerateData(const Pointer &P, const Context &Ctx, size_t Offset, // Primitives. if (FieldDesc->isPrimitive()) - return F(P, FieldDesc->getPrimType(), Offset); + return F(P, FieldDesc->getPrimType(), Offset, false); // Primitive arrays. if (FieldDesc->isPrimitiveArray()) { @@ -155,10 +156,12 @@ static bool enumerateData(const Pointer &P, const Context &Ctx, size_t Offset, QualType ElemType = FieldDesc->getElemQualType(); size_t ElemSizeInBits = Ctx.getASTContext().getTypeSize(ElemType); PrimType ElemT = *Ctx.classify(ElemType); + // Special case, since the bools here are packed. + bool PackedBools = FieldDesc->getType()->isExtVectorBoolType(); bool Ok = true; for (unsigned I = 0; I != FieldDesc->getNumElems(); ++I) { unsigned Index = BigEndianTarget ? (FieldDesc->getNumElems() - 1 - I) : I; - Ok = Ok && F(P.atIndex(Index), ElemT, Offset); + Ok = Ok && F(P.atIndex(Index), ElemT, Offset, PackedBools); Offset += ElemSizeInBits; } return Ok; @@ -302,7 +305,8 @@ static bool readPointerToBuffer(const Context &Ctx, const Pointer &FromPtr, return enumeratePointerFields( FromPtr, Ctx, - [&](const Pointer &P, PrimType T, size_t BitOffset) -> bool { + [&](const Pointer &P, PrimType T, size_t BitOffset, + bool PackedBools) -> bool { if (!P.isInitialized()) { assert(false && "Implement uninitialized value tracking"); return ReturnOnUninit; @@ -334,6 +338,8 @@ static bool readPointerToBuffer(const Context &Ctx, const Pointer &FromPtr, } else { if (const FieldDecl *FD = P.getField(); FD && FD->isBitField()) BitWidth = FD->getBitWidthValue(ASTCtx); + else if (T == PT_Bool && PackedBools) + BitWidth = 1; BITCAST_TYPE_SWITCH(T, { T Val = P.deref<T>(); @@ -401,7 +407,7 @@ bool clang::interp::DoBitCastPtr(InterpState &S, CodePtr OpPC, size_t BitOffset = 0; bool Success = enumeratePointerFields( ToPtr, S.getContext(), - [&](const Pointer &P, PrimType T, size_t _) -> bool { + [&](const Pointer &P, PrimType T, size_t _, bool PackedBools) -> bool { if (T == PT_Float) { CharUnits ObjectReprChars = ASTCtx.getTypeSizeInChars(P.getType()); const auto &Semantics = ASTCtx.getFloatTypeSemantics(P.getType()); diff --git a/clang/test/AST/ByteCode/builtin-bit-cast.cpp b/clang/test/AST/ByteCode/builtin-bit-cast.cpp index 0c55155ec64a24..b5c6bc14af3544 100644 --- a/clang/test/AST/ByteCode/builtin-bit-cast.cpp +++ b/clang/test/AST/ByteCode/builtin-bit-cast.cpp @@ -468,8 +468,52 @@ struct ref_mem { // both-note@+1 {{bit_cast from a type with a reference member is not allowed in a constant expression}} constexpr intptr_t run_ref_mem = __builtin_bit_cast(intptr_t, ref_mem{global_int}); +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(check_round_trip<uint2>(0xCAFEBABE0C05FEFEULL), ""); +static_assert(check_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), ""); +constexpr bool8 b8 = __builtin_bit_cast(bool8, 0x55); // both-error {{__builtin_bit_cast source size does not equal destination size (4 vs 1)}} +#if 0 +static_assert(check_round_trip<bool8>(static_cast<unsigned char>(0)), ""); +static_assert(check_round_trip<bool8>(static_cast<unsigned char>(1)), ""); +static_assert(check_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(check_round_trip<bool16>(static_cast<short>(0xCAFE)), ""); +static_assert(check_round_trip<bool32>(static_cast<int>(0xCAFEBABE)), ""); +static_assert(check_round_trip<bool128>(static_cast<__int128_t>(0xCAFEBABE0C05FEFEULL)), ""); +#endif + +#if 0 +// expected-error@+2 {{constexpr variable 'bad_bool9_to_short' must be initialized by a constant expression}} +// expected-note@+1 {{bit_cast involving type 'bool __attribute__((ext_vector_type(9)))' (vector of 9 'bool' values) is not allowed in a constant expression; element size 1 * element count 9 is not a multiple of the byte size 8}} +constexpr unsigned short bad_bool9_to_short = __builtin_bit_cast(unsigned short, bool9{1,1,0,1,0,1,0,1,0}); +// expected-error@+2 {{constexpr variable 'bad_short_to_bool9' must be initialized by a constant expression}} +// expected-note@+1 {{bit_cast involving type 'bool __attribute__((ext_vector_type(9)))' (vector of 9 'bool' values) is not allowed in a constant expression; element size 1 * element count 9 is not a multiple of the byte size 8}} +constexpr bool9 bad_short_to_bool9 = __builtin_bit_cast(bool9, static_cast<unsigned short>(0)); +// expected-error@+2 {{constexpr variable 'bad_int_to_bool17' must be initialized by a constant expression}} +// expected-note@+1 {{bit_cast involving type 'bool __attribute__((ext_vector_type(17)))' (vector of 17 'bool' values) is not allowed in a constant expression; element size 1 * element count 17 is not a multiple of the byte size 8}} +constexpr bool17 bad_int_to_bool17 = __builtin_bit_cast(bool17, 0x0001CAFEU); +#endif +} namespace test_complex { constexpr _Complex unsigned test_int_complex = { 0x0C05FEFE, 0xCAFEBABE }; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits