[clang] 1b3da36 - [clang][bytecode] Fix bitcasting packed bool vectors (#114937)

via cfe-commits cfe-commits at lists.llvm.org
Tue Nov 5 02:43:13 PST 2024


Author: Timm Baeder
Date: 2024-11-05T11:43:09+01:00
New Revision: 1b3da362c5e32e7a2b23fe5febd9e1a09b484150

URL: https://github.com/llvm/llvm-project/commit/1b3da362c5e32e7a2b23fe5febd9e1a09b484150
DIFF: https://github.com/llvm/llvm-project/commit/1b3da362c5e32e7a2b23fe5febd9e1a09b484150.diff

LOG: [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.

Added: 
    

Modified: 
    clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
    clang/test/AST/ByteCode/builtin-bit-cast.cpp

Removed: 
    


################################################################################
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 1834bb5dc89b2f..7d1fcbda10965f 100644
--- a/clang/test/AST/ByteCode/builtin-bit-cast.cpp
+++ b/clang/test/AST/ByteCode/builtin-bit-cast.cpp
@@ -475,8 +475,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