[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)

via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 21 13:16:08 PDT 2023


https://github.com/DaMatrix updated https://github.com/llvm/llvm-project/pull/66894

>From cb7e616dacc1afcdf3357a4a95278479a234be6d Mon Sep 17 00:00:00 2001
From: DaPorkchop_ <daporkchop at 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                | 86 ++++++++++++++++++-
 .../SemaCXX/constexpr-builtin-bit-cast.cpp    | 35 ++++++++
 2 files changed, 120 insertions(+), 1 deletion(-)

diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index fea06b97259fe31..9612ca5d15c686e 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -7005,10 +7005,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 +7096,45 @@ class APValueToBufferConverter {
     return true;
   }
 
+  bool visitVector(const APValue &Val, QualType Ty, CharUnits Offset) {
+    const auto *VT = Ty->castAs<VectorType>();
+    unsigned VectorLength = Val.getVectorLength();
+
+    if (VT->isExtVectorBoolType()) {
+      // Special handling for OpenCL bool vectors: we need to pack the vector
+      // of 1-bit unsigned integers into a single integer with the corresponding
+      // bits set, then write out the resulting integer.
+
+      CharUnits VecWidthBytes = Info.Ctx.getTypeSizeInChars(VT);
+      assert(VecWidthBytes.getQuantity() * Info.Ctx.getCharWidth() >=
+                 VectorLength &&
+             "Vector type is smaller than the number of bool elements?");
+
+      APSInt Bits(VecWidthBytes.getQuantity() * Info.Ctx.getCharWidth());
+      for (unsigned I = 0; I != VectorLength; ++I) {
+        const APValue &SubObj = Val.getVectorElt(I);
+        assert(SubObj.isInt() && "Bool vector element isn't an int?");
+        Bits.setBitVal(I, !SubObj.getInt().isZero());
+      }
+
+      SmallVector<unsigned char, 8> Bytes(VecWidthBytes.getQuantity());
+      llvm::StoreIntToMemory(Bits, &*Bytes.begin(),
+                             VecWidthBytes.getQuantity());
+      Buffer.writeObject(Offset, Bytes);
+      return true;
+    }
+
+    CharUnits ElemWidth = Info.Ctx.getTypeSizeInChars(VT->getElementType());
+    // Visit each of the vector elements
+    for (unsigned I = 0; I != VectorLength; ++I) {
+      const APValue &SubObj = Val.getVectorElt(I);
+      if (!visit(SubObj, VT->getElementType(), Offset + I * ElemWidth))
+        return false;
+    }
+
+    return true;
+  }
+
   bool visitInt(const APSInt &Val, QualType Ty, CharUnits Offset) {
     APSInt AdjustedVal = Val;
     unsigned Width = AdjustedVal.getBitWidth();
@@ -7304,6 +7344,50 @@ class BufferToAPValueConverter {
     return ArrayValue;
   }
 
+  std::optional<APValue> visit(const VectorType *Ty, CharUnits Offset) {
+    unsigned NumElements = Ty->getNumElements();
+
+    SmallVector<APValue, 4> Elts;
+    Elts.reserve(NumElements);
+
+    if (Ty->isExtVectorBoolType()) {
+      // Special handling for OpenCL bool vectors: we need to read
+      // the individual bits and then unpack them into a vector of 1-bit
+      // unsigned integers.
+
+      CharUnits VecWidthBytes = Info.Ctx.getTypeSizeInChars(Ty);
+      assert(VecWidthBytes.getQuantity() * Info.Ctx.getCharWidth() >=
+                 NumElements &&
+             "Vector type is smaller than the number of bool elements?");
+
+      SmallVector<uint8_t, 8> Bytes;
+      if (!Buffer.readObject(Offset, VecWidthBytes, Bytes))
+        return std::nullopt;
+
+      APSInt Bits(VecWidthBytes.getQuantity() * Info.Ctx.getCharWidth(), true);
+      llvm::LoadIntFromMemory(Bits, &*Bytes.begin(), Bytes.size());
+
+      for (unsigned I = 0; I != NumElements; ++I) {
+        APSInt Bit(1);
+        Bit = Bits.intersects(APInt::getOneBitSet(Bits.getBitWidth(), I));
+        Elts.emplace_back(std::move(Bit));
+      }
+    } else {
+      CharUnits ElementWidth =
+          Info.Ctx.getTypeSizeInChars(Ty->getElementType());
+
+      for (unsigned I = 0; I != NumElements; ++I) {
+        std::optional<APValue> ElementValue =
+            visitType(Ty->getElementType(), Offset + I * ElementWidth);
+        if (!ElementValue)
+          return std::nullopt;
+        Elts.push_back(std::move(*ElementValue));
+      }
+    }
+
+    return APValue(Elts.data(), Elts.size());
+  }
+
   std::optional<APValue> visit(const Type *Ty, CharUnits Offset) {
     return unsupportedType(QualType(Ty, 0));
   }
diff --git a/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp b/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp
index a6ebe0572d063bb..fe7aa51c167fa67 100644
--- a/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp
+++ b/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp
@@ -463,3 +463,38 @@ 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 bool17 __attribute__((ext_vector_type(17)));
+typedef bool bool32 __attribute__((ext_vector_type(32)));
+
+static_assert(bit_cast<unsigned char>(bool8{1,0,1,0,1,0,1,0}) == 0x55, "");
+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>(bool9{1,1,0,1,0,1,0,1,0}) == 0xAB, "");
+static_assert(round_trip<bool9>(static_cast<unsigned short>(0)), "");
+static_assert(round_trip<bool9>(static_cast<unsigned short>(1)), "");
+static_assert(round_trip<bool9>(static_cast<unsigned short>(0x00AB)), "");
+static_assert(round_trip<bool9>(static_cast<unsigned short>(0x01AB)), "");
+
+static_assert(round_trip<bool17>(static_cast<unsigned int>(0x0001CAFE)), "");
+static_assert(round_trip<bool32>(static_cast<unsigned int>(0xCAFEBABE)), "");
+
+}



More information about the cfe-commits mailing list