[clang] [clang] Implement constexpr bit_cast for vectors (PR #66894)
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Tue Oct 10 23:55:37 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);
----------------
zygoloid wrote:
This doesn't seem correct: in [my investigation](https://godbolt.org/z/co8rxd5fe) it looks like LLVM stores vectors of `x86_fp80` with a stride of 12 (for x86) or 16 (for x86_64) bytes between elements -- the same layout as an array of `x86_fp80`, with 10 bytes of data followed by either 2 or 6 bytes of padding. Would it be correct to simply remove this special case and the matching one below?
https://github.com/llvm/llvm-project/pull/66894
More information about the cfe-commits
mailing list