Skip to content

Commit 1b3da36

Browse files
authored
[clang][bytecode] Fix bitcasting packed bool vectors (#114937)
This is a special case we need to handle. We don't do bitcasting _into_ such vectors yet though.
1 parent 23f3bff commit 1b3da36

File tree

2 files changed

+56
-6
lines changed

2 files changed

+56
-6
lines changed

clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ using namespace clang;
2626
using namespace clang::interp;
2727

2828
/// Used to iterate over pointer fields.
29-
using DataFunc =
30-
llvm::function_ref<bool(const Pointer &P, PrimType Ty, size_t BitOffset)>;
29+
using DataFunc = llvm::function_ref<bool(const Pointer &P, PrimType Ty,
30+
size_t BitOffset, bool PackedBools)>;
3131

3232
#define BITCAST_TYPE_SWITCH(Expr, B) \
3333
do { \
@@ -89,6 +89,7 @@ struct BitcastBuffer {
8989

9090
std::byte *getBytes(unsigned BitOffset) const {
9191
assert(BitOffset % 8 == 0);
92+
assert(BitOffset < SizeInBits);
9293
return const_cast<std::byte *>(data() + (BitOffset / 8));
9394
}
9495

@@ -147,18 +148,20 @@ static bool enumerateData(const Pointer &P, const Context &Ctx, size_t Offset,
147148

148149
// Primitives.
149150
if (FieldDesc->isPrimitive())
150-
return F(P, FieldDesc->getPrimType(), Offset);
151+
return F(P, FieldDesc->getPrimType(), Offset, false);
151152

152153
// Primitive arrays.
153154
if (FieldDesc->isPrimitiveArray()) {
154155
bool BigEndianTarget = Ctx.getASTContext().getTargetInfo().isBigEndian();
155156
QualType ElemType = FieldDesc->getElemQualType();
156157
size_t ElemSizeInBits = Ctx.getASTContext().getTypeSize(ElemType);
157158
PrimType ElemT = *Ctx.classify(ElemType);
159+
// Special case, since the bools here are packed.
160+
bool PackedBools = FieldDesc->getType()->isExtVectorBoolType();
158161
bool Ok = true;
159162
for (unsigned I = 0; I != FieldDesc->getNumElems(); ++I) {
160163
unsigned Index = BigEndianTarget ? (FieldDesc->getNumElems() - 1 - I) : I;
161-
Ok = Ok && F(P.atIndex(Index), ElemT, Offset);
164+
Ok = Ok && F(P.atIndex(Index), ElemT, Offset, PackedBools);
162165
Offset += ElemSizeInBits;
163166
}
164167
return Ok;
@@ -302,7 +305,8 @@ static bool readPointerToBuffer(const Context &Ctx, const Pointer &FromPtr,
302305

303306
return enumeratePointerFields(
304307
FromPtr, Ctx,
305-
[&](const Pointer &P, PrimType T, size_t BitOffset) -> bool {
308+
[&](const Pointer &P, PrimType T, size_t BitOffset,
309+
bool PackedBools) -> bool {
306310
if (!P.isInitialized()) {
307311
assert(false && "Implement uninitialized value tracking");
308312
return ReturnOnUninit;
@@ -334,6 +338,8 @@ static bool readPointerToBuffer(const Context &Ctx, const Pointer &FromPtr,
334338
} else {
335339
if (const FieldDecl *FD = P.getField(); FD && FD->isBitField())
336340
BitWidth = FD->getBitWidthValue(ASTCtx);
341+
else if (T == PT_Bool && PackedBools)
342+
BitWidth = 1;
337343

338344
BITCAST_TYPE_SWITCH(T, {
339345
T Val = P.deref<T>();
@@ -401,7 +407,7 @@ bool clang::interp::DoBitCastPtr(InterpState &S, CodePtr OpPC,
401407
size_t BitOffset = 0;
402408
bool Success = enumeratePointerFields(
403409
ToPtr, S.getContext(),
404-
[&](const Pointer &P, PrimType T, size_t _) -> bool {
410+
[&](const Pointer &P, PrimType T, size_t _, bool PackedBools) -> bool {
405411
if (T == PT_Float) {
406412
CharUnits ObjectReprChars = ASTCtx.getTypeSizeInChars(P.getType());
407413
const auto &Semantics = ASTCtx.getFloatTypeSemantics(P.getType());

clang/test/AST/ByteCode/builtin-bit-cast.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,8 +475,52 @@ struct ref_mem {
475475
// both-note@+1 {{bit_cast from a type with a reference member is not allowed in a constant expression}}
476476
constexpr intptr_t run_ref_mem = __builtin_bit_cast(intptr_t, ref_mem{global_int});
477477

478+
namespace test_vector {
478479

480+
typedef unsigned uint2 __attribute__((vector_size(2 * sizeof(unsigned))));
481+
typedef char byte8 __attribute__((vector_size(sizeof(unsigned long long))));
479482

483+
constexpr uint2 test_vector = { 0x0C05FEFE, 0xCAFEBABE };
484+
485+
static_assert(bit_cast<unsigned long long>(test_vector) == (LITTLE_END
486+
? 0xCAFEBABE0C05FEFE
487+
: 0x0C05FEFECAFEBABE), "");
488+
static_assert(check_round_trip<uint2>(0xCAFEBABE0C05FEFEULL), "");
489+
static_assert(check_round_trip<byte8>(0xCAFEBABE0C05FEFEULL), "");
490+
491+
typedef bool bool8 __attribute__((ext_vector_type(8)));
492+
typedef bool bool9 __attribute__((ext_vector_type(9)));
493+
typedef bool bool16 __attribute__((ext_vector_type(16)));
494+
typedef bool bool17 __attribute__((ext_vector_type(17)));
495+
typedef bool bool32 __attribute__((ext_vector_type(32)));
496+
typedef bool bool128 __attribute__((ext_vector_type(128)));
497+
498+
static_assert(bit_cast<unsigned char>(bool8{1,0,1,0,1,0,1,0}) == (LITTLE_END ? 0x55 : 0xAA), "");
499+
constexpr bool8 b8 = __builtin_bit_cast(bool8, 0x55); // both-error {{__builtin_bit_cast source size does not equal destination size (4 vs 1)}}
500+
#if 0
501+
static_assert(check_round_trip<bool8>(static_cast<unsigned char>(0)), "");
502+
static_assert(check_round_trip<bool8>(static_cast<unsigned char>(1)), "");
503+
static_assert(check_round_trip<bool8>(static_cast<unsigned char>(0x55)), "");
504+
505+
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), "");
506+
507+
static_assert(check_round_trip<bool16>(static_cast<short>(0xCAFE)), "");
508+
static_assert(check_round_trip<bool32>(static_cast<int>(0xCAFEBABE)), "");
509+
static_assert(check_round_trip<bool128>(static_cast<__int128_t>(0xCAFEBABE0C05FEFEULL)), "");
510+
#endif
511+
512+
#if 0
513+
// expected-error@+2 {{constexpr variable 'bad_bool9_to_short' must be initialized by a constant expression}}
514+
// 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}}
515+
constexpr unsigned short bad_bool9_to_short = __builtin_bit_cast(unsigned short, bool9{1,1,0,1,0,1,0,1,0});
516+
// expected-error@+2 {{constexpr variable 'bad_short_to_bool9' must be initialized by a constant expression}}
517+
// 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}}
518+
constexpr bool9 bad_short_to_bool9 = __builtin_bit_cast(bool9, static_cast<unsigned short>(0));
519+
// expected-error@+2 {{constexpr variable 'bad_int_to_bool17' must be initialized by a constant expression}}
520+
// 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}}
521+
constexpr bool17 bad_int_to_bool17 = __builtin_bit_cast(bool17, 0x0001CAFEU);
522+
#endif
523+
}
480524

481525
namespace test_complex {
482526
constexpr _Complex unsigned test_int_complex = { 0x0C05FEFE, 0xCAFEBABE };

0 commit comments

Comments
 (0)