Skip to content

Commit 2f13fbf

Browse files
authored
[clang][bytecode] Support bitcasting into float fields (#114825)
1 parent 013f4a4 commit 2f13fbf

File tree

4 files changed

+49
-7
lines changed

4 files changed

+49
-7
lines changed

clang/lib/AST/ByteCode/Compiler.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2735,7 +2735,7 @@ bool Compiler<Emitter>::VisitMaterializeTemporaryExpr(
27352735
InitLinkScope<Emitter> ILS(this, InitLink::Temp(*LocalIndex));
27362736
if (!this->emitGetPtrLocal(*LocalIndex, E))
27372737
return false;
2738-
return this->visitInitializer(SubExpr);
2738+
return this->visitInitializer(SubExpr) && this->emitFinishInit(E);
27392739
}
27402740
}
27412741
return false;

clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -397,19 +397,35 @@ bool clang::interp::DoBitCastPtr(InterpState &S, CodePtr OpPC,
397397
/*ReturnOnUninit=*/false);
398398

399399
// Now read the values out of the buffer again and into ToPtr.
400+
const ASTContext &ASTCtx = S.getASTContext();
400401
size_t BitOffset = 0;
401402
bool Success = enumeratePointerFields(
402403
ToPtr, S.getContext(),
403404
[&](const Pointer &P, PrimType T, size_t _) -> bool {
404-
BITCAST_TYPE_SWITCH_FIXED_SIZE(T, {
405-
T &Val = P.deref<T>();
405+
if (T == PT_Float) {
406+
CharUnits ObjectReprChars = ASTCtx.getTypeSizeInChars(P.getType());
407+
const auto &Semantics = ASTCtx.getFloatTypeSemantics(P.getType());
408+
unsigned NumBits = llvm::APFloatBase::getSizeInBits(Semantics);
409+
assert(NumBits % 8 == 0);
410+
assert(NumBits <= ASTCtx.toBits(ObjectReprChars));
411+
std::byte *M = Buffer.getBytes(BitOffset);
412+
413+
if (llvm::sys::IsBigEndianHost)
414+
swapBytes(M, NumBits / 8);
406415

416+
P.deref<Floating>() = Floating::bitcastFromMemory(M, Semantics);
417+
P.initialize();
418+
BitOffset += ASTCtx.toBits(ObjectReprChars);
419+
return true;
420+
}
421+
422+
BITCAST_TYPE_SWITCH_FIXED_SIZE(T, {
407423
std::byte *M = Buffer.getBytes(BitOffset);
408424

409425
if (llvm::sys::IsBigEndianHost)
410426
swapBytes(M, T::bitWidth() / 8);
411427

412-
Val = T::bitcastFromMemory(M, T::bitWidth());
428+
P.deref<T>() = T::bitcastFromMemory(M, T::bitWidth());
413429
P.initialize();
414430
BitOffset += T::bitWidth();
415431
});

clang/test/AST/ByteCode/builtin-bit-cast-long-double.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ struct bytes {
4545
unsigned char d[16];
4646
};
4747

48-
// static_assert(round_trip<bytes>(ld), "");
48+
static_assert(round_trip<bytes>(ld), "");
4949

5050
static_assert(round_trip<long double>(10.0L));
5151

@@ -77,10 +77,17 @@ constexpr bytes ld539 = {
7777
0x8, 0x40, 0x0, 0x0,
7878
0x0, 0x0, 0x0, 0x0,
7979
};
80-
8180
constexpr long double fivehundredandthirtynine = 539.0;
82-
8381
static_assert(bit_cast<long double>(ld539) == fivehundredandthirtynine, "");
82+
83+
struct LD {
84+
long double v;
85+
};
86+
87+
constexpr LD ld2 = __builtin_bit_cast(LD, ld539.d);
88+
constexpr long double five39 = __builtin_bit_cast(long double, ld539.d);
89+
static_assert(ld2.v == five39);
90+
8491
#else
8592
static_assert(round_trip<__int128_t>(34.0L));
8693
#endif

clang/test/AST/ByteCode/builtin-bit-cast.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,3 +467,22 @@ struct ref_mem {
467467
// both-error@+2 {{constexpr variable 'run_ref_mem' must be initialized by a constant expression}}
468468
// both-note@+1 {{bit_cast from a type with a reference member is not allowed in a constant expression}}
469469
constexpr intptr_t run_ref_mem = __builtin_bit_cast(intptr_t, ref_mem{global_int});
470+
471+
472+
473+
474+
namespace test_complex {
475+
constexpr _Complex unsigned test_int_complex = { 0x0C05FEFE, 0xCAFEBABE };
476+
static_assert(round_trip<_Complex unsigned>(0xCAFEBABE0C05FEFEULL), "");
477+
static_assert(bit_cast<unsigned long long>(test_int_complex) == (LITTLE_END
478+
? 0xCAFEBABE0C05FEFE
479+
: 0x0C05FEFECAFEBABE), "");
480+
static_assert(sizeof(double) == 2 * sizeof(float));
481+
struct TwoFloats { float A; float B; };
482+
constexpr _Complex float test_float_complex = {1.0f, 2.0f};
483+
constexpr TwoFloats TF = __builtin_bit_cast(TwoFloats, test_float_complex);
484+
static_assert(TF.A == 1.0f && TF.B == 2.0f);
485+
486+
constexpr double D = __builtin_bit_cast(double, test_float_complex);
487+
constexpr int M = __builtin_bit_cast(int, test_int_complex); // both-error {{__builtin_bit_cast source size does not equal destination size}}
488+
}

0 commit comments

Comments
 (0)