@@ -2737,53 +2737,6 @@ static bool truncateBitfieldValue(EvalInfo &Info, const Expr *E,
2737
2737
return true;
2738
2738
}
2739
2739
2740
- static bool EvalAndBitcastToAPInt(EvalInfo &Info, const Expr *E,
2741
- llvm::APInt &Res) {
2742
- APValue SVal;
2743
- if (!Evaluate(SVal, Info, E))
2744
- return false;
2745
- if (SVal.isInt()) {
2746
- Res = SVal.getInt();
2747
- return true;
2748
- }
2749
- if (SVal.isFloat()) {
2750
- Res = SVal.getFloat().bitcastToAPInt();
2751
- return true;
2752
- }
2753
- if (SVal.isVector()) {
2754
- QualType VecTy = E->getType();
2755
- unsigned VecSize = Info.Ctx.getTypeSize(VecTy);
2756
- QualType EltTy = VecTy->castAs<VectorType>()->getElementType();
2757
- unsigned EltSize = Info.Ctx.getTypeSize(EltTy);
2758
- bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian();
2759
- Res = llvm::APInt::getZero(VecSize);
2760
- for (unsigned i = 0; i < SVal.getVectorLength(); i++) {
2761
- APValue &Elt = SVal.getVectorElt(i);
2762
- llvm::APInt EltAsInt;
2763
- if (Elt.isInt()) {
2764
- EltAsInt = Elt.getInt();
2765
- } else if (Elt.isFloat()) {
2766
- EltAsInt = Elt.getFloat().bitcastToAPInt();
2767
- } else {
2768
- // Don't try to handle vectors of anything other than int or float
2769
- // (not sure if it's possible to hit this case).
2770
- Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);
2771
- return false;
2772
- }
2773
- unsigned BaseEltSize = EltAsInt.getBitWidth();
2774
- if (BigEndian)
2775
- Res |= EltAsInt.zextOrTrunc(VecSize).rotr(i*EltSize+BaseEltSize);
2776
- else
2777
- Res |= EltAsInt.zextOrTrunc(VecSize).rotl(i*EltSize);
2778
- }
2779
- return true;
2780
- }
2781
- // Give up if the input isn't an int, float, or vector. For example, we
2782
- // reject "(v4i16)(intptr_t)&a".
2783
- Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);
2784
- return false;
2785
- }
2786
-
2787
2740
/// Perform the given integer operation, which is known to need at most BitWidth
2788
2741
/// bits, and check for overflow in the original type (if that type was not an
2789
2742
/// unsigned type).
@@ -7023,10 +6976,11 @@ class APValueToBufferConverter {
7023
6976
return visitArray(Val, Ty, Offset);
7024
6977
case APValue::Struct:
7025
6978
return visitRecord(Val, Ty, Offset);
6979
+ case APValue::Vector:
6980
+ return visitVector(Val, Ty, Offset);
7026
6981
7027
6982
case APValue::ComplexInt:
7028
6983
case APValue::ComplexFloat:
7029
- case APValue::Vector:
7030
6984
case APValue::FixedPoint:
7031
6985
// FIXME: We should support these.
7032
6986
@@ -7113,6 +7067,72 @@ class APValueToBufferConverter {
7113
7067
return true;
7114
7068
}
7115
7069
7070
+ bool visitVector(const APValue &Val, QualType Ty, CharUnits Offset) {
7071
+ const VectorType *VTy = Ty->castAs<VectorType>();
7072
+ QualType EltTy = VTy->getElementType();
7073
+ unsigned NElts = VTy->getNumElements();
7074
+ unsigned EltSize =
7075
+ VTy->isExtVectorBoolType() ? 1 : Info.Ctx.getTypeSize(EltTy);
7076
+
7077
+ if ((NElts * EltSize) % Info.Ctx.getCharWidth() != 0) {
7078
+ // The vector's size in bits is not a multiple of the target's byte size,
7079
+ // so its layout is unspecified. For now, we'll simply treat these cases
7080
+ // as unsupported (this should only be possible with OpenCL bool vectors
7081
+ // whose element count isn't a multiple of the byte size).
7082
+ Info.FFDiag(BCE->getBeginLoc(),
7083
+ diag::note_constexpr_bit_cast_invalid_vector)
7084
+ << Ty.getCanonicalType() << EltSize << NElts
7085
+ << Info.Ctx.getCharWidth();
7086
+ return false;
7087
+ }
7088
+
7089
+ if (EltTy->isRealFloatingType() && &Info.Ctx.getFloatTypeSemantics(EltTy) ==
7090
+ &APFloat::x87DoubleExtended()) {
7091
+ // The layout for x86_fp80 vectors seems to be handled very inconsistently
7092
+ // by both clang and LLVM, so for now we won't allow bit_casts involving
7093
+ // it in a constexpr context.
7094
+ Info.FFDiag(BCE->getBeginLoc(),
7095
+ diag::note_constexpr_bit_cast_unsupported_type)
7096
+ << EltTy;
7097
+ return false;
7098
+ }
7099
+
7100
+ if (VTy->isExtVectorBoolType()) {
7101
+ // Special handling for OpenCL bool vectors:
7102
+ // Since these vectors are stored as packed bits, but we can't write
7103
+ // individual bits to the BitCastBuffer, we'll buffer all of the elements
7104
+ // together into an appropriately sized APInt and write them all out at
7105
+ // once. Because we don't accept vectors where NElts * EltSize isn't a
7106
+ // multiple of the char size, there will be no padding space, so we don't
7107
+ // have to worry about writing data which should have been left
7108
+ // uninitialized.
7109
+ bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian();
7110
+
7111
+ llvm::APInt Res = llvm::APInt::getZero(NElts);
7112
+ for (unsigned I = 0; I < NElts; ++I) {
7113
+ const llvm::APSInt &EltAsInt = Val.getVectorElt(I).getInt();
7114
+ assert(EltAsInt.isUnsigned() && EltAsInt.getBitWidth() == 1 &&
7115
+ "bool vector element must be 1-bit unsigned integer!");
7116
+
7117
+ Res.insertBits(EltAsInt, BigEndian ? (NElts - I - 1) : I);
7118
+ }
7119
+
7120
+ SmallVector<uint8_t, 8> Bytes(NElts / 8);
7121
+ llvm::StoreIntToMemory(Res, &*Bytes.begin(), NElts / 8);
7122
+ Buffer.writeObject(Offset, Bytes);
7123
+ } else {
7124
+ // Iterate over each of the elements and write them out to the buffer at
7125
+ // the appropriate offset.
7126
+ CharUnits EltSizeChars = Info.Ctx.getTypeSizeInChars(EltTy);
7127
+ for (unsigned I = 0; I < NElts; ++I) {
7128
+ if (!visit(Val.getVectorElt(I), EltTy, Offset + I * EltSizeChars))
7129
+ return false;
7130
+ }
7131
+ }
7132
+
7133
+ return true;
7134
+ }
7135
+
7116
7136
bool visitInt(const APSInt &Val, QualType Ty, CharUnits Offset) {
7117
7137
APSInt AdjustedVal = Val;
7118
7138
unsigned Width = AdjustedVal.getBitWidth();
@@ -7121,7 +7141,7 @@ class APValueToBufferConverter {
7121
7141
AdjustedVal = AdjustedVal.extend(Width);
7122
7142
}
7123
7143
7124
- SmallVector<unsigned char , 8> Bytes(Width / 8);
7144
+ SmallVector<uint8_t , 8> Bytes(Width / 8);
7125
7145
llvm::StoreIntToMemory(AdjustedVal, &*Bytes.begin(), Width / 8);
7126
7146
Buffer.writeObject(Offset, Bytes);
7127
7147
return true;
@@ -7322,6 +7342,77 @@ class BufferToAPValueConverter {
7322
7342
return ArrayValue;
7323
7343
}
7324
7344
7345
+ std::optional<APValue> visit(const VectorType *VTy, CharUnits Offset) {
7346
+ QualType EltTy = VTy->getElementType();
7347
+ unsigned NElts = VTy->getNumElements();
7348
+ unsigned EltSize =
7349
+ VTy->isExtVectorBoolType() ? 1 : Info.Ctx.getTypeSize(EltTy);
7350
+
7351
+ if ((NElts * EltSize) % Info.Ctx.getCharWidth() != 0) {
7352
+ // The vector's size in bits is not a multiple of the target's byte size,
7353
+ // so its layout is unspecified. For now, we'll simply treat these cases
7354
+ // as unsupported (this should only be possible with OpenCL bool vectors
7355
+ // whose element count isn't a multiple of the byte size).
7356
+ Info.FFDiag(BCE->getBeginLoc(),
7357
+ diag::note_constexpr_bit_cast_invalid_vector)
7358
+ << QualType(VTy, 0) << EltSize << NElts << Info.Ctx.getCharWidth();
7359
+ return std::nullopt;
7360
+ }
7361
+
7362
+ if (EltTy->isRealFloatingType() && &Info.Ctx.getFloatTypeSemantics(EltTy) ==
7363
+ &APFloat::x87DoubleExtended()) {
7364
+ // The layout for x86_fp80 vectors seems to be handled very inconsistently
7365
+ // by both clang and LLVM, so for now we won't allow bit_casts involving
7366
+ // it in a constexpr context.
7367
+ Info.FFDiag(BCE->getBeginLoc(),
7368
+ diag::note_constexpr_bit_cast_unsupported_type)
7369
+ << EltTy;
7370
+ return std::nullopt;
7371
+ }
7372
+
7373
+ SmallVector<APValue, 4> Elts;
7374
+ Elts.reserve(NElts);
7375
+ if (VTy->isExtVectorBoolType()) {
7376
+ // Special handling for OpenCL bool vectors:
7377
+ // Since these vectors are stored as packed bits, but we can't read
7378
+ // individual bits from the BitCastBuffer, we'll buffer all of the
7379
+ // elements together into an appropriately sized APInt and write them all
7380
+ // out at once. Because we don't accept vectors where NElts * EltSize
7381
+ // isn't a multiple of the char size, there will be no padding space, so
7382
+ // we don't have to worry about reading any padding data which didn't
7383
+ // actually need to be accessed.
7384
+ bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian();
7385
+
7386
+ SmallVector<uint8_t, 8> Bytes;
7387
+ Bytes.reserve(NElts / 8);
7388
+ if (!Buffer.readObject(Offset, CharUnits::fromQuantity(NElts / 8), Bytes))
7389
+ return std::nullopt;
7390
+
7391
+ APSInt SValInt(NElts, true);
7392
+ llvm::LoadIntFromMemory(SValInt, &*Bytes.begin(), Bytes.size());
7393
+
7394
+ for (unsigned I = 0; I < NElts; ++I) {
7395
+ llvm::APInt Elt =
7396
+ SValInt.extractBits(1, (BigEndian ? NElts - I - 1 : I) * EltSize);
7397
+ Elts.emplace_back(
7398
+ APSInt(std::move(Elt), !EltTy->isSignedIntegerType()));
7399
+ }
7400
+ } else {
7401
+ // Iterate over each of the elements and read them from the buffer at
7402
+ // the appropriate offset.
7403
+ CharUnits EltSizeChars = Info.Ctx.getTypeSizeInChars(EltTy);
7404
+ for (unsigned I = 0; I < NElts; ++I) {
7405
+ std::optional<APValue> EltValue =
7406
+ visitType(EltTy, Offset + I * EltSizeChars);
7407
+ if (!EltValue)
7408
+ return std::nullopt;
7409
+ Elts.push_back(std::move(*EltValue));
7410
+ }
7411
+ }
7412
+
7413
+ return APValue(Elts.data(), Elts.size());
7414
+ }
7415
+
7325
7416
std::optional<APValue> visit(const Type *Ty, CharUnits Offset) {
7326
7417
return unsupportedType(QualType(Ty, 0));
7327
7418
}
@@ -7421,25 +7512,15 @@ static bool checkBitCastConstexprEligibility(EvalInfo *Info,
7421
7512
return SourceOK;
7422
7513
}
7423
7514
7424
- static bool handleLValueToRValueBitCast (EvalInfo &Info, APValue &DestValue,
7425
- APValue &SourceValue ,
7515
+ static bool handleRValueToRValueBitCast (EvalInfo &Info, APValue &DestValue,
7516
+ const APValue &SourceRValue ,
7426
7517
const CastExpr *BCE) {
7427
7518
assert(CHAR_BIT == 8 && Info.Ctx.getTargetInfo().getCharWidth() == 8 &&
7428
7519
"no host or target supports non 8-bit chars");
7429
- assert(SourceValue.isLValue() &&
7430
- "LValueToRValueBitcast requires an lvalue operand!");
7431
7520
7432
7521
if (!checkBitCastConstexprEligibility(&Info, Info.Ctx, BCE))
7433
7522
return false;
7434
7523
7435
- LValue SourceLValue;
7436
- APValue SourceRValue;
7437
- SourceLValue.setFrom(Info.Ctx, SourceValue);
7438
- if (!handleLValueToRValueConversion(
7439
- Info, BCE, BCE->getSubExpr()->getType().withConst(), SourceLValue,
7440
- SourceRValue, /*WantObjectRepresentation=*/true))
7441
- return false;
7442
-
7443
7524
// Read out SourceValue into a char buffer.
7444
7525
std::optional<BitCastBuffer> Buffer =
7445
7526
APValueToBufferConverter::convert(Info, SourceRValue, BCE);
@@ -7456,6 +7537,25 @@ static bool handleLValueToRValueBitCast(EvalInfo &Info, APValue &DestValue,
7456
7537
return true;
7457
7538
}
7458
7539
7540
+ static bool handleLValueToRValueBitCast(EvalInfo &Info, APValue &DestValue,
7541
+ APValue &SourceValue,
7542
+ const CastExpr *BCE) {
7543
+ assert(CHAR_BIT == 8 && Info.Ctx.getTargetInfo().getCharWidth() == 8 &&
7544
+ "no host or target supports non 8-bit chars");
7545
+ assert(SourceValue.isLValue() &&
7546
+ "LValueToRValueBitcast requires an lvalue operand!");
7547
+
7548
+ LValue SourceLValue;
7549
+ APValue SourceRValue;
7550
+ SourceLValue.setFrom(Info.Ctx, SourceValue);
7551
+ if (!handleLValueToRValueConversion(
7552
+ Info, BCE, BCE->getSubExpr()->getType().withConst(), SourceLValue,
7553
+ SourceRValue, /*WantObjectRepresentation=*/true))
7554
+ return false;
7555
+
7556
+ return handleRValueToRValueBitCast(Info, DestValue, SourceRValue, BCE);
7557
+ }
7558
+
7459
7559
template <class Derived>
7460
7560
class ExprEvaluatorBase
7461
7561
: public ConstStmtVisitor<Derived, bool> {
@@ -10540,41 +10640,22 @@ bool VectorExprEvaluator::VisitCastExpr(const CastExpr *E) {
10540
10640
return Success(Elts, E);
10541
10641
}
10542
10642
case CK_BitCast: {
10543
- // Evaluate the operand into an APInt we can extract from.
10544
- llvm::APInt SValInt;
10545
- if (!EvalAndBitcastToAPInt(Info, SE, SValInt))
10643
+ APValue SVal;
10644
+ if (!Evaluate(SVal, Info, SE))
10645
+ return false;
10646
+
10647
+ if (!SVal.isInt() && !SVal.isFloat() && !SVal.isVector()) {
10648
+ // Give up if the input isn't an int, float, or vector. For example, we
10649
+ // reject "(v4i16)(intptr_t)&a".
10650
+ Info.FFDiag(E, diag::note_constexpr_invalid_cast)
10651
+ << 2 << Info.Ctx.getLangOpts().CPlusPlus;
10546
10652
return false;
10547
- // Extract the elements
10548
- QualType EltTy = VTy->getElementType();
10549
- unsigned EltSize = Info.Ctx.getTypeSize(EltTy);
10550
- bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian();
10551
- SmallVector<APValue, 4> Elts;
10552
- if (EltTy->isRealFloatingType()) {
10553
- const llvm::fltSemantics &Sem = Info.Ctx.getFloatTypeSemantics(EltTy);
10554
- unsigned FloatEltSize = EltSize;
10555
- if (&Sem == &APFloat::x87DoubleExtended())
10556
- FloatEltSize = 80;
10557
- for (unsigned i = 0; i < NElts; i++) {
10558
- llvm::APInt Elt;
10559
- if (BigEndian)
10560
- Elt = SValInt.rotl(i * EltSize + FloatEltSize).trunc(FloatEltSize);
10561
- else
10562
- Elt = SValInt.rotr(i * EltSize).trunc(FloatEltSize);
10563
- Elts.push_back(APValue(APFloat(Sem, Elt)));
10564
- }
10565
- } else if (EltTy->isIntegerType()) {
10566
- for (unsigned i = 0; i < NElts; i++) {
10567
- llvm::APInt Elt;
10568
- if (BigEndian)
10569
- Elt = SValInt.rotl(i*EltSize+EltSize).zextOrTrunc(EltSize);
10570
- else
10571
- Elt = SValInt.rotr(i*EltSize).zextOrTrunc(EltSize);
10572
- Elts.push_back(APValue(APSInt(Elt, !EltTy->isSignedIntegerType())));
10573
- }
10574
- } else {
10575
- return Error(E);
10576
10653
}
10577
- return Success(Elts, E);
10654
+
10655
+ if (!handleRValueToRValueBitCast(Info, Result, SVal, E))
10656
+ return false;
10657
+
10658
+ return true;
10578
10659
}
10579
10660
default:
10580
10661
return ExprEvaluatorBaseTy::VisitCastExpr(E);
0 commit comments