[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