https://github.com/DaMatrix updated https://github.com/llvm/llvm-project/pull/66894
>From 72f63b695c9ebd9c7032c4b754ff7965c28fad5c Mon Sep 17 00:00:00 2001 From: DaPorkchop_ <daporkc...@daporkchop.net> Date: Sun, 13 Aug 2023 22:39:12 +0200 Subject: [PATCH 1/2] [clang] Implement constexpr bit_cast for vectors --- .../include/clang/Basic/DiagnosticASTKinds.td | 3 + clang/lib/AST/ExprConstant.cpp | 269 ++++++++++++------ clang/lib/CodeGen/CGExprConstant.cpp | 3 + clang/test/CodeGen/const-init.c | 9 +- .../constexpr-builtin-bit-cast-fp80.cpp | 48 ++++ .../SemaCXX/constexpr-builtin-bit-cast.cpp | 44 +++ 6 files changed, 278 insertions(+), 98 deletions(-) create mode 100644 clang/test/SemaCXX/constexpr-builtin-bit-cast-fp80.cpp diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td index d2656310e79c9b8..3f06e18783dd558 100644 --- a/clang/include/clang/Basic/DiagnosticASTKinds.td +++ b/clang/include/clang/Basic/DiagnosticASTKinds.td @@ -326,6 +326,9 @@ def note_constexpr_bit_cast_invalid_type : Note< "%select{type|member}1 is not allowed in a constant expression">; def note_constexpr_bit_cast_invalid_subtype : Note< "invalid type %0 is a %select{member|base}1 of %2">; +def note_constexpr_bit_cast_invalid_vector : Note< + "bit_cast involving type %0 is not allowed in a constant expression; " + "element size %1 * element count %2 is not a multiple of the byte size %3">; def note_constexpr_bit_cast_indet_dest : Note< "indeterminate value can only initialize an object of type 'unsigned char'" "%select{, 'char',|}1 or 'std::byte'; %0 is invalid">; diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 5a33e918db8e8c0..bb8222caec8c7de 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -2732,53 +2732,6 @@ static bool truncateBitfieldValue(EvalInfo &Info, const Expr *E, return true; } -static bool EvalAndBitcastToAPInt(EvalInfo &Info, const Expr *E, - llvm::APInt &Res) { - APValue SVal; - if (!Evaluate(SVal, Info, E)) - return false; - if (SVal.isInt()) { - Res = SVal.getInt(); - return true; - } - if (SVal.isFloat()) { - Res = SVal.getFloat().bitcastToAPInt(); - return true; - } - if (SVal.isVector()) { - QualType VecTy = E->getType(); - unsigned VecSize = Info.Ctx.getTypeSize(VecTy); - QualType EltTy = VecTy->castAs<VectorType>()->getElementType(); - unsigned EltSize = Info.Ctx.getTypeSize(EltTy); - bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); - Res = llvm::APInt::getZero(VecSize); - for (unsigned i = 0; i < SVal.getVectorLength(); i++) { - APValue &Elt = SVal.getVectorElt(i); - llvm::APInt EltAsInt; - if (Elt.isInt()) { - EltAsInt = Elt.getInt(); - } else if (Elt.isFloat()) { - EltAsInt = Elt.getFloat().bitcastToAPInt(); - } else { - // Don't try to handle vectors of anything other than int or float - // (not sure if it's possible to hit this case). - Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); - return false; - } - unsigned BaseEltSize = EltAsInt.getBitWidth(); - if (BigEndian) - Res |= EltAsInt.zextOrTrunc(VecSize).rotr(i*EltSize+BaseEltSize); - else - Res |= EltAsInt.zextOrTrunc(VecSize).rotl(i*EltSize); - } - return true; - } - // Give up if the input isn't an int, float, or vector. For example, we - // reject "(v4i16)(intptr_t)&a". - Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); - return false; -} - /// Perform the given integer operation, which is known to need at most BitWidth /// bits, and check for overflow in the original type (if that type was not an /// unsigned type). @@ -7011,10 +6964,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. @@ -7101,6 +7055,72 @@ 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 (EltTy->isRealFloatingType() && &Info.Ctx.getFloatTypeSemantics(EltTy) == + &APFloat::x87DoubleExtended()) { + // The layout for x86_fp80 vectors seems to be handled very inconsistently + // by both clang and LLVM, so for now we won't allow bit_casts involving + // it in a constexpr context. + Info.FFDiag(BCE->getBeginLoc(), + diag::note_constexpr_bit_cast_unsupported_type) + << EltTy; + 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); + for (unsigned I = 0; I < NElts; ++I) { + if (!visit(Val.getVectorElt(I), EltTy, Offset + I * EltSizeChars)) + return false; + } + } + + return true; + } + bool visitInt(const APSInt &Val, QualType Ty, CharUnits Offset) { APSInt AdjustedVal = Val; unsigned Width = AdjustedVal.getBitWidth(); @@ -7109,7 +7129,7 @@ class APValueToBufferConverter { AdjustedVal = AdjustedVal.extend(Width); } - SmallVector<unsigned char, 8> Bytes(Width / 8); + SmallVector<uint8_t, 8> Bytes(Width / 8); llvm::StoreIntToMemory(AdjustedVal, &*Bytes.begin(), Width / 8); Buffer.writeObject(Offset, Bytes); return true; @@ -7310,6 +7330,77 @@ class BufferToAPValueConverter { return ArrayValue; } + std::optional<APValue> visit(const VectorType *VTy, CharUnits Offset) { + 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) + << QualType(VTy, 0) << EltSize << NElts << Info.Ctx.getCharWidth(); + return std::nullopt; + } + + if (EltTy->isRealFloatingType() && &Info.Ctx.getFloatTypeSemantics(EltTy) == + &APFloat::x87DoubleExtended()) { + // The layout for x86_fp80 vectors seems to be handled very inconsistently + // by both clang and LLVM, so for now we won't allow bit_casts involving + // it in a constexpr context. + Info.FFDiag(BCE->getBeginLoc(), + diag::note_constexpr_bit_cast_unsupported_type) + << EltTy; + return std::nullopt; + } + + SmallVector<APValue, 4> Elts; + Elts.reserve(NElts); + if (VTy->isExtVectorBoolType()) { + // Special handling for OpenCL bool vectors: + // Since these vectors are stored as packed bits, but we can't read + // individual bits from 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 reading any padding data which didn't + // actually need to be accessed. + bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); + + SmallVector<uint8_t, 8> Bytes; + Bytes.reserve(NElts / 8); + if (!Buffer.readObject(Offset, CharUnits::fromQuantity(NElts / 8), Bytes)) + return std::nullopt; + + APSInt SValInt(NElts, true); + llvm::LoadIntFromMemory(SValInt, &*Bytes.begin(), Bytes.size()); + + for (unsigned I = 0; I < NElts; ++I) { + llvm::APInt Elt = + SValInt.extractBits(1, (BigEndian ? NElts - I - 1 : I) * EltSize); + Elts.emplace_back( + APSInt(std::move(Elt), !EltTy->isSignedIntegerType())); + } + } else { + // Iterate over each of the elements and read them from the buffer at + // the appropriate offset. + CharUnits EltSizeChars = Info.Ctx.getTypeSizeInChars(EltTy); + for (unsigned I = 0; I < NElts; ++I) { + std::optional<APValue> EltValue = + visitType(EltTy, Offset + I * EltSizeChars); + if (!EltValue) + return std::nullopt; + Elts.push_back(std::move(*EltValue)); + } + } + + return APValue(Elts.data(), Elts.size()); + } + std::optional<APValue> visit(const Type *Ty, CharUnits Offset) { return unsupportedType(QualType(Ty, 0)); } @@ -7409,25 +7500,15 @@ static bool checkBitCastConstexprEligibility(EvalInfo *Info, return SourceOK; } -static bool handleLValueToRValueBitCast(EvalInfo &Info, APValue &DestValue, - APValue &SourceValue, +static bool handleRValueToRValueBitCast(EvalInfo &Info, APValue &DestValue, + const APValue &SourceRValue, const CastExpr *BCE) { assert(CHAR_BIT == 8 && Info.Ctx.getTargetInfo().getCharWidth() == 8 && "no host or target supports non 8-bit chars"); - assert(SourceValue.isLValue() && - "LValueToRValueBitcast requires an lvalue operand!"); if (!checkBitCastConstexprEligibility(&Info, Info.Ctx, BCE)) return false; - LValue SourceLValue; - APValue SourceRValue; - SourceLValue.setFrom(Info.Ctx, SourceValue); - if (!handleLValueToRValueConversion( - Info, BCE, BCE->getSubExpr()->getType().withConst(), SourceLValue, - SourceRValue, /*WantObjectRepresentation=*/true)) - return false; - // Read out SourceValue into a char buffer. std::optional<BitCastBuffer> Buffer = APValueToBufferConverter::convert(Info, SourceRValue, BCE); @@ -7444,6 +7525,25 @@ static bool handleLValueToRValueBitCast(EvalInfo &Info, APValue &DestValue, return true; } +static bool handleLValueToRValueBitCast(EvalInfo &Info, APValue &DestValue, + APValue &SourceValue, + const CastExpr *BCE) { + assert(CHAR_BIT == 8 && Info.Ctx.getTargetInfo().getCharWidth() == 8 && + "no host or target supports non 8-bit chars"); + assert(SourceValue.isLValue() && + "LValueToRValueBitcast requires an lvalue operand!"); + + LValue SourceLValue; + APValue SourceRValue; + SourceLValue.setFrom(Info.Ctx, SourceValue); + if (!handleLValueToRValueConversion( + Info, BCE, BCE->getSubExpr()->getType().withConst(), SourceLValue, + SourceRValue, /*WantObjectRepresentation=*/true)) + return false; + + return handleRValueToRValueBitCast(Info, DestValue, SourceRValue, BCE); +} + template <class Derived> class ExprEvaluatorBase : public ConstStmtVisitor<Derived, bool> { @@ -10526,41 +10626,22 @@ bool VectorExprEvaluator::VisitCastExpr(const CastExpr *E) { return Success(Elts, E); } case CK_BitCast: { - // Evaluate the operand into an APInt we can extract from. - llvm::APInt SValInt; - if (!EvalAndBitcastToAPInt(Info, SE, SValInt)) + APValue SVal; + if (!Evaluate(SVal, Info, SE)) + return false; + + if (!SVal.isInt() && !SVal.isFloat() && !SVal.isVector()) { + // Give up if the input isn't an int, float, or vector. For example, we + // reject "(v4i16)(intptr_t)&a". + Info.FFDiag(E, diag::note_constexpr_invalid_cast) + << 2 << Info.Ctx.getLangOpts().CPlusPlus; return false; - // Extract the elements - QualType EltTy = VTy->getElementType(); - unsigned EltSize = Info.Ctx.getTypeSize(EltTy); - bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); - SmallVector<APValue, 4> Elts; - if (EltTy->isRealFloatingType()) { - const llvm::fltSemantics &Sem = Info.Ctx.getFloatTypeSemantics(EltTy); - unsigned FloatEltSize = EltSize; - if (&Sem == &APFloat::x87DoubleExtended()) - FloatEltSize = 80; - for (unsigned i = 0; i < NElts; i++) { - llvm::APInt Elt; - if (BigEndian) - Elt = SValInt.rotl(i * EltSize + FloatEltSize).trunc(FloatEltSize); - else - Elt = SValInt.rotr(i * EltSize).trunc(FloatEltSize); - Elts.push_back(APValue(APFloat(Sem, Elt))); - } - } else if (EltTy->isIntegerType()) { - for (unsigned i = 0; i < NElts; i++) { - llvm::APInt Elt; - if (BigEndian) - Elt = SValInt.rotl(i*EltSize+EltSize).zextOrTrunc(EltSize); - else - Elt = SValInt.rotr(i*EltSize).zextOrTrunc(EltSize); - Elts.push_back(APValue(APSInt(Elt, !EltTy->isSignedIntegerType()))); - } - } else { - return Error(E); } - return Success(Elts, E); + + if (!handleRValueToRValueBitCast(Info, Result, SVal, E)) + return false; + + return true; } default: return ExprEvaluatorBaseTy::VisitCastExpr(E); diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index 9b67a8b3335a165..29268907a88f508 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -2151,6 +2151,9 @@ llvm::Constant *ConstantEmitter::tryEmitPrivate(const APValue &Value, Inits[I] = llvm::ConstantInt::get(CGM.getLLVMContext(), Elt.getInt()); else if (Elt.isFloat()) Inits[I] = llvm::ConstantFP::get(CGM.getLLVMContext(), Elt.getFloat()); + else if (Elt.isIndeterminate()) + Inits[I] = llvm::UndefValue::get(CGM.getTypes().ConvertType( + DestType->castAs<VectorType>()->getElementType())); else llvm_unreachable("unsupported vector element type"); } diff --git a/clang/test/CodeGen/const-init.c b/clang/test/CodeGen/const-init.c index 7062393c450226a..0e4fc4ad48af8db 100644 --- a/clang/test/CodeGen/const-init.c +++ b/clang/test/CodeGen/const-init.c @@ -140,11 +140,12 @@ void g28(void) { typedef short v12i16 __attribute((vector_size(24))); typedef long double v2f80 __attribute((vector_size(24))); // CHECK: @g28.a = internal global <1 x i64> <i64 10> - // CHECK: @g28.b = internal global <12 x i16> <i16 0, i16 0, i16 0, i16 -32768, i16 16383, i16 0, i16 0, i16 0, i16 0, i16 -32768, i16 16384, i16 0> - // CHECK: @g28.c = internal global <2 x x86_fp80> <x86_fp80 0xK3FFF8000000000000000, x86_fp80 0xK40008000000000000000>, align 32 + // @g28.b = internal global <12 x i16> <i16 0, i16 0, i16 0, i16 -32768, i16 16383, i16 0, i16 0, i16 0, i16 0, i16 -32768, i16 16384, i16 0> + // @g28.c = internal global <2 x x86_fp80> <x86_fp80 0xK3FFF8000000000000000, x86_fp80 0xK40008000000000000000>, align 32 static v1i64 a = (v1i64)10LL; - static v12i16 b = (v12i16)(v2f80){1,2}; - static v2f80 c = (v2f80)(v12i16){0,0,0,-32768,16383,0,0,0,0,-32768,16384,0}; + //FIXME: support constant bitcast between vectors of x86_fp80 + //static v12i16 b = (v12i16)(v2f80){1,2}; + //static v2f80 c = (v2f80)(v12i16){0,0,0,-32768,16383,0,0,0,0,-32768,16384,0}; } // PR13643 diff --git a/clang/test/SemaCXX/constexpr-builtin-bit-cast-fp80.cpp b/clang/test/SemaCXX/constexpr-builtin-bit-cast-fp80.cpp new file mode 100644 index 000000000000000..aa1b7a6b7fac77d --- /dev/null +++ b/clang/test/SemaCXX/constexpr-builtin-bit-cast-fp80.cpp @@ -0,0 +1,48 @@ +// RUN: %clang_cc1 -verify -std=c++2a -fsyntax-only -triple i386-pc-linux-gnu %s + +// This is separate from constexpr-builtin-bit-cast.cpp because we want to +// compile for i386 so that sizeof(long double) is 12. + +typedef long double fp80x2_v __attribute__((ext_vector_type(2))); + +static_assert(sizeof(long double) == 12, ""); +static_assert(sizeof(fp80x2_v) == 32, ""); + +struct fp80x2_s { + char _data[2 * 10]; + unsigned char _pad[sizeof(fp80x2_v) - 2 * 10]; + + constexpr bool operator==(const fp80x2_s& rhs) const { + for (int i = 0; i < 2 * 10; ++i) + if (_data[i] != rhs._data[i]) + return false; + return true; + } +}; + +constexpr static fp80x2_v test_vec_fp80 = { 1, 2 }; +constexpr static fp80x2_s test_str_fp80 = { { 0, 0, 0, 0, 0, 0, 0, -128, -1, 63, 0, 0, 0, 0, 0, 0, 0, -128, 0, 64 }, {} }; + +// expected-error@+2 {{static assertion expression is not an integral constant expression}} +// expected-note@+1 {{constexpr bit_cast involving type 'long double' is not yet supported}} +static_assert(__builtin_bit_cast(fp80x2_s, test_vec_fp80) == test_str_fp80, ""); + +// expected-error@+2 {{static assertion expression is not an integral constant expression}} +// expected-note@+1 {{constexpr bit_cast involving type 'long double' is not yet supported}} +static_assert(__builtin_bit_cast(fp80x2_s, __builtin_bit_cast(fp80x2_v, test_str_fp80)) == test_str_fp80, ""); + +// expected-error@+2 {{constexpr variable 'bad_str_fp80_0' must be initialized by a constant expression}} +// expected-note@+1 {{constexpr bit_cast involving type 'long double' is not yet supported}} +constexpr static char bad_str_fp80_0 = __builtin_bit_cast(fp80x2_s, test_vec_fp80)._pad[0]; + +// expected-error@+2 {{constexpr variable 'bad_str_fp80_1' must be initialized by a constant expression}} +// expected-note@+1 {{constexpr bit_cast involving type 'long double' is not yet supported}} +constexpr static char bad_str_fp80_1 = __builtin_bit_cast(fp80x2_s, test_vec_fp80)._pad[1]; + +// expected-error@+2 {{constexpr variable 'bad_str_fp80_11' must be initialized by a constant expression}} +// expected-note@+1 {{constexpr bit_cast involving type 'long double' is not yet supported}} +constexpr static char bad_str_fp80_11 = __builtin_bit_cast(fp80x2_s, test_vec_fp80)._pad[11]; + +// expected-error@+2 {{constexpr variable 'struct2v' must be initialized by a constant expression}} +// expected-note@+1 {{constexpr bit_cast involving type 'long double' is not yet supported}} +constexpr static fp80x2_v struct2v = __builtin_bit_cast(fp80x2_v, test_str_fp80); diff --git a/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp b/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp index a6ebe0572d063bb..c5b8032f40b131a 100644 --- a/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp +++ b/clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp @@ -463,3 +463,47 @@ 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 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), ""); +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>(bool16{1,1,1,1,1,0,0,0, 1,1,1,1,0,1,0,0}) == (LITTLE_END ? 0x2F1F : 0xF8F4), ""); + +static_assert(round_trip<bool16>(static_cast<short>(0xCAFE)), ""); +static_assert(round_trip<bool32>(static_cast<int>(0xCAFEBABE)), ""); +static_assert(round_trip<bool128>(static_cast<__int128_t>(0xCAFEBABE0C05FEFEULL)), ""); + +// expected-error@+2 {{constexpr variable 'bad_bool9_to_short' must be initialized by a constant expression}} +// expected-note@+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@+2 {{constexpr variable 'bad_short_to_bool9' must be initialized by a constant expression}} +// expected-note@+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@+2 {{constexpr variable 'bad_int_to_bool17' must be initialized by a constant expression}} +// expected-note@+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); + +} >From 32cbfd1e72b5c18bc71728a0fd8fec0e04ee2e41 Mon Sep 17 00:00:00 2001 From: DaPorkchop_ <daporkc...@daporkchop.net> Date: Tue, 24 Oct 2023 08:44:25 +0200 Subject: [PATCH 2/2] Change and add test case for diagnostic when doing a C-style bitcast on vectors of x86_fp80 --- .../include/clang/Basic/DiagnosticASTKinds.td | 2 +- .../constexpr-builtin-bit-cast-fp80.cpp | 58 ++++++++++++------- 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td index 3f06e18783dd558..d46533e69a26d9e 100644 --- a/clang/include/clang/Basic/DiagnosticASTKinds.td +++ b/clang/include/clang/Basic/DiagnosticASTKinds.td @@ -317,7 +317,7 @@ def note_constexpr_memcpy_unsupported : Note< "source is not a contiguous array of at least %4 elements of type %3|" "destination is not a contiguous array of at least %4 elements of type %3}2">; def note_constexpr_bit_cast_unsupported_type : Note< - "constexpr bit_cast involving type %0 is not yet supported">; + "constexpr bit cast involving type %0 is not yet supported">; def note_constexpr_bit_cast_unsupported_bitfield : Note< "constexpr bit_cast involving bit-field is not yet supported">; def note_constexpr_bit_cast_invalid_type : Note< diff --git a/clang/test/SemaCXX/constexpr-builtin-bit-cast-fp80.cpp b/clang/test/SemaCXX/constexpr-builtin-bit-cast-fp80.cpp index aa1b7a6b7fac77d..b37b362c81e75e6 100644 --- a/clang/test/SemaCXX/constexpr-builtin-bit-cast-fp80.cpp +++ b/clang/test/SemaCXX/constexpr-builtin-bit-cast-fp80.cpp @@ -20,29 +20,47 @@ struct fp80x2_s { } }; -constexpr static fp80x2_v test_vec_fp80 = { 1, 2 }; -constexpr static fp80x2_s test_str_fp80 = { { 0, 0, 0, 0, 0, 0, 0, -128, -1, 63, 0, 0, 0, 0, 0, 0, 0, -128, 0, 64 }, {} }; +namespace builtin_bit_cast { + constexpr static fp80x2_v test_vec_fp80 = { 1, 2 }; + constexpr static fp80x2_s test_str_fp80 = { { 0, 0, 0, 0, 0, 0, 0, -128, -1, 63, 0, 0, 0, 0, 0, 0, 0, -128, 0, 64 }, {} }; -// expected-error@+2 {{static assertion expression is not an integral constant expression}} -// expected-note@+1 {{constexpr bit_cast involving type 'long double' is not yet supported}} -static_assert(__builtin_bit_cast(fp80x2_s, test_vec_fp80) == test_str_fp80, ""); + // expected-error@+2 {{static assertion expression is not an integral constant expression}} + // expected-note@+1 {{constexpr bit cast involving type 'long double' is not yet supported}} + static_assert(__builtin_bit_cast(fp80x2_s, test_vec_fp80) == test_str_fp80, ""); -// expected-error@+2 {{static assertion expression is not an integral constant expression}} -// expected-note@+1 {{constexpr bit_cast involving type 'long double' is not yet supported}} -static_assert(__builtin_bit_cast(fp80x2_s, __builtin_bit_cast(fp80x2_v, test_str_fp80)) == test_str_fp80, ""); + // expected-error@+2 {{static assertion expression is not an integral constant expression}} + // expected-note@+1 {{constexpr bit cast involving type 'long double' is not yet supported}} + static_assert(__builtin_bit_cast(fp80x2_s, __builtin_bit_cast(fp80x2_v, test_str_fp80)) == test_str_fp80, ""); -// expected-error@+2 {{constexpr variable 'bad_str_fp80_0' must be initialized by a constant expression}} -// expected-note@+1 {{constexpr bit_cast involving type 'long double' is not yet supported}} -constexpr static char bad_str_fp80_0 = __builtin_bit_cast(fp80x2_s, test_vec_fp80)._pad[0]; + // expected-error@+2 {{constexpr variable 'bad_str_fp80_0' must be initialized by a constant expression}} + // expected-note@+1 {{constexpr bit cast involving type 'long double' is not yet supported}} + constexpr static char bad_str_fp80_0 = __builtin_bit_cast(fp80x2_s, test_vec_fp80)._pad[0]; -// expected-error@+2 {{constexpr variable 'bad_str_fp80_1' must be initialized by a constant expression}} -// expected-note@+1 {{constexpr bit_cast involving type 'long double' is not yet supported}} -constexpr static char bad_str_fp80_1 = __builtin_bit_cast(fp80x2_s, test_vec_fp80)._pad[1]; + // expected-error@+2 {{constexpr variable 'bad_str_fp80_1' must be initialized by a constant expression}} + // expected-note@+1 {{constexpr bit cast involving type 'long double' is not yet supported}} + constexpr static char bad_str_fp80_1 = __builtin_bit_cast(fp80x2_s, test_vec_fp80)._pad[1]; -// expected-error@+2 {{constexpr variable 'bad_str_fp80_11' must be initialized by a constant expression}} -// expected-note@+1 {{constexpr bit_cast involving type 'long double' is not yet supported}} -constexpr static char bad_str_fp80_11 = __builtin_bit_cast(fp80x2_s, test_vec_fp80)._pad[11]; + // expected-error@+2 {{constexpr variable 'bad_str_fp80_11' must be initialized by a constant expression}} + // expected-note@+1 {{constexpr bit cast involving type 'long double' is not yet supported}} + constexpr static char bad_str_fp80_11 = __builtin_bit_cast(fp80x2_s, test_vec_fp80)._pad[11]; -// expected-error@+2 {{constexpr variable 'struct2v' must be initialized by a constant expression}} -// expected-note@+1 {{constexpr bit_cast involving type 'long double' is not yet supported}} -constexpr static fp80x2_v struct2v = __builtin_bit_cast(fp80x2_v, test_str_fp80); + // expected-error@+2 {{constexpr variable 'struct2v' must be initialized by a constant expression}} + // expected-note@+1 {{constexpr bit cast involving type 'long double' is not yet supported}} + constexpr static fp80x2_v struct2v = __builtin_bit_cast(fp80x2_v, test_str_fp80); +} + +namespace c_cast { + typedef short v12i16 __attribute((vector_size(24))); + typedef long double v2f80 __attribute((vector_size(24))); + + // FIXME: re-enable the corresponding test cases in CodeGen/const-init.c when + // constexpr bitcast with x86_fp80 is supported + + // expected-error@+2 {{constexpr variable 'b' must be initialized by a constant expression}} + // expected-note@+1 {{constexpr bit cast involving type 'long double' is not yet supported}} + constexpr static v12i16 b = (v12i16)(v2f80){1,2}; + + // expected-error@+2 {{constexpr variable 'c' must be initialized by a constant expression}} + // expected-note@+1 {{constexpr bit cast involving type 'long double' is not yet supported}} + constexpr static v2f80 c = (v2f80)(v12i16){0,0,0,-32768,16383,0,0,0,0,-32768,16384,0}; +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits