[clang] [clang][bytecode] Fix bitcasting packed bool vectors (PR #114937)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Mon Nov 4 21:49:23 PST 2024
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?= <tbaeder at 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 at +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 at +2 {{constexpr variable 'bad_bool9_to_short' must be initialized by a constant expression}}
+// expected-note at +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 at +2 {{constexpr variable 'bad_short_to_bool9' must be initialized by a constant expression}}
+// expected-note at +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 at +2 {{constexpr variable 'bad_int_to_bool17' must be initialized by a constant expression}}
+// expected-note at +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 };
More information about the cfe-commits
mailing list