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

via cfe-commits cfe-commits at lists.llvm.org
Wed Oct 11 04:37:26 PDT 2023


================
@@ -7098,6 +7052,69 @@ class APValueToBufferConverter {
     return true;
   }
 
+  bool visitVector(const APValue &Val, QualType Ty, CharUnits Offset) {
+    const VectorType *VTy = Ty->castAs<VectorType>();
+    QualType EltTy = VTy->getElementType();
+    unsigned NElts = VTy->getNumElements();
+    unsigned EltSize =
+        VTy->isExtVectorBoolType() ? 1 : Info.Ctx.getTypeSize(EltTy);
+
+    if ((NElts * EltSize) % Info.Ctx.getCharWidth() != 0) {
+      // The vector's size in bits is not a multiple of the target's byte size,
+      // so its layout is unspecified. For now, we'll simply treat these cases
+      // as unsupported (this should only be possible with OpenCL bool vectors
+      // whose element count isn't a multiple of the byte size).
+      Info.FFDiag(BCE->getBeginLoc(),
+                  diag::note_constexpr_bit_cast_invalid_vector)
+          << Ty.getCanonicalType() << EltSize << NElts
+          << Info.Ctx.getCharWidth();
+      return false;
+    }
+
+    if (VTy->isExtVectorBoolType()) {
+      // Special handling for OpenCL bool vectors:
+      // Since these vectors are stored as packed bits, but we can't write
+      // individual bits to the BitCastBuffer, we'll buffer all of the elements
+      // together into an appropriately sized APInt and write them all out at
+      // once. Because we don't accept vectors where NElts * EltSize isn't a
+      // multiple of the char size, there will be no padding space, so we don't
+      // have to worry about writing data which should have been left
+      // uninitialized.
+      bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian();
+
+      llvm::APInt Res = llvm::APInt::getZero(NElts);
+      for (unsigned I = 0; I < NElts; ++I) {
+        const llvm::APSInt &EltAsInt = Val.getVectorElt(I).getInt();
+        assert(EltAsInt.isUnsigned() && EltAsInt.getBitWidth() == 1 &&
+               "bool vector element must be 1-bit unsigned integer!");
+
+        Res.insertBits(EltAsInt, BigEndian ? (NElts - I - 1) : I);
+      }
+
+      SmallVector<uint8_t, 8> Bytes(NElts / 8);
+      llvm::StoreIntToMemory(Res, &*Bytes.begin(), NElts / 8);
+      Buffer.writeObject(Offset, Bytes);
+    } else {
+      // Iterate over each of the elements and write them out to the buffer at
+      // the appropriate offset.
+      CharUnits EltSizeChars = Info.Ctx.getTypeSizeInChars(EltTy);
+
+      // Special handling for vectors of x86_fp80: use a size of exactly 80 bits
+      // because LLVM stores vector elements without padding
+      if (EltTy->isRealFloatingType() &&
+          &Info.Ctx.getFloatTypeSemantics(EltTy) ==
+              &APFloat::x87DoubleExtended())
+        EltSizeChars = Info.Ctx.toCharUnitsFromBits(80);
----------------
DaMatrix wrote:

@nikic gave [an example](https://godbolt.org/z/rcev7Ps1a) in #68566 which shows that sometimes it doesn't, and pointed out that LLVM itself documents that vector types are represented without padding. Actually, [this example I just came up with](https://godbolt.org/z/hsdxhPrE8) shows how inconsistent it is, with LLVM storing vector elements at different offsets depending on how many elements are being written to and the current optimization level. Honestly, at this point I have no idea what's supposed to be correct, it seems like every time I think I've figured out which the "correct" format is something else pops up, and I don't really see much point in spending any more time trying to fix this code which only breaks on a vector format which nobody will ever actually use in practice. Can I just make it fail constant evaluation when the element type is `x86_fp80` and leave it at that?

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


More information about the cfe-commits mailing list