Skip to content

Commit efb64b9

Browse files
committed
[clang][bytecode] Pass (float) BitWidth to DoBitCast
In certain cases (i.e. long double on x86), the bit with we get from the floating point semantics is different than the type size we compute for the BitCast instruction. Pass this along to DoBitCast, so in there we can check only the relevant bits for being initialized. This also fixes a weirdness we still had in DoBitCast.
1 parent 416e4cd commit efb64b9

File tree

5 files changed

+35
-19
lines changed

5 files changed

+35
-19
lines changed

clang/lib/AST/ByteCode/BitcastBuffer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ struct Bits {
4545
bool operator>=(Bits Other) const { return N >= Other.N; }
4646
bool operator<=(Bits Other) const { return N <= Other.N; }
4747
bool operator==(Bits Other) const { return N == Other.N; }
48+
bool operator!=(Bits Other) const { return N != Other.N; }
4849
};
4950

5051
/// A quantity in bytes.

clang/lib/AST/ByteCode/Interp.h

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#define LLVM_CLANG_AST_INTERP_INTERP_H
1515

1616
#include "../ExprConstShared.h"
17+
#include "BitcastBuffer.h"
1718
#include "Boolean.h"
1819
#include "DynamicAllocator.h"
1920
#include "FixedPoint.h"
@@ -3050,24 +3051,24 @@ inline bool BitCast(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte,
30503051
llvm::SmallVector<std::byte> Buff(BuffSize);
30513052
bool HasIndeterminateBits = false;
30523053

3053-
if (!DoBitCast(S, OpPC, FromPtr, Buff.data(), BuffSize, HasIndeterminateBits))
3054+
Bits FullBitWidth(ResultBitWidth);
3055+
Bits BitWidth = FullBitWidth;
3056+
3057+
if constexpr (std::is_same_v<T, Floating>) {
3058+
assert(Sem);
3059+
BitWidth = Bits(llvm::APFloatBase::getSizeInBits(*Sem));
3060+
}
3061+
3062+
if (!DoBitCast(S, OpPC, FromPtr, Buff.data(), BitWidth, FullBitWidth,
3063+
HasIndeterminateBits))
30543064
return false;
30553065

30563066
if (!CheckBitCast(S, OpPC, HasIndeterminateBits, TargetIsUCharOrByte))
30573067
return false;
30583068

30593069
if constexpr (std::is_same_v<T, Floating>) {
30603070
assert(Sem);
3061-
ptrdiff_t Offset = 0;
3062-
3063-
if (llvm::sys::IsBigEndianHost) {
3064-
unsigned NumBits = llvm::APFloatBase::getSizeInBits(*Sem);
3065-
assert(NumBits % 8 == 0);
3066-
assert(NumBits <= ResultBitWidth);
3067-
Offset = (ResultBitWidth - NumBits) / 8;
3068-
}
3069-
3070-
S.Stk.push<Floating>(T::bitcastFromMemory(Buff.data() + Offset, *Sem));
3071+
S.Stk.push<Floating>(T::bitcastFromMemory(Buff.data(), *Sem));
30713072
} else {
30723073
assert(!Sem);
30733074
S.Stk.push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));

clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -278,44 +278,49 @@ static bool readPointerToBuffer(const Context &Ctx, const Pointer &FromPtr,
278278
if (llvm::sys::IsBigEndianHost)
279279
swapBytes(Buff.get(), NumBits.roundToBytes());
280280

281+
Buffer.markInitialized(BitOffset, NumBits);
281282
} else {
282283
BITCAST_TYPE_SWITCH(T, { P.deref<T>().bitcastToMemory(Buff.get()); });
283284

284285
if (llvm::sys::IsBigEndianHost)
285286
swapBytes(Buff.get(), FullBitWidth.roundToBytes());
287+
Buffer.markInitialized(BitOffset, BitWidth);
286288
}
287289

288290
Buffer.pushData(Buff.get(), BitOffset, BitWidth, TargetEndianness);
289-
Buffer.markInitialized(BitOffset, BitWidth);
290291
return true;
291292
});
292293
}
293294

294295
bool clang::interp::DoBitCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
295-
std::byte *Buff, size_t BuffSize,
296+
std::byte *Buff, Bits BitWidth, Bits FullBitWidth,
296297
bool &HasIndeterminateBits) {
297298
assert(Ptr.isLive());
298299
assert(Ptr.isBlockPointer());
299300
assert(Buff);
301+
assert(BitWidth <= FullBitWidth);
302+
assert(FullBitWidth.isFullByte());
303+
assert(BitWidth.isFullByte());
300304

301-
Bits BitSize = Bytes(BuffSize).toBits();
302-
BitcastBuffer Buffer(BitSize);
305+
BitcastBuffer Buffer(FullBitWidth);
306+
size_t BuffSize = FullBitWidth.roundToBytes();
303307
if (!CheckBitcastType(S, OpPC, Ptr.getType(), /*IsToType=*/false))
304308
return false;
305309

306310
bool Success = readPointerToBuffer(S.getContext(), Ptr, Buffer,
307311
/*ReturnOnUninit=*/false);
308-
HasIndeterminateBits = !Buffer.allInitialized();
312+
HasIndeterminateBits = !Buffer.rangeInitialized(Bits::zero(), BitWidth);
309313

310314
const ASTContext &ASTCtx = S.getASTContext();
311315
Endian TargetEndianness =
312316
ASTCtx.getTargetInfo().isLittleEndian() ? Endian::Little : Endian::Big;
313-
auto B = Buffer.copyBits(Bits::zero(), BitSize, BitSize, TargetEndianness);
317+
auto B =
318+
Buffer.copyBits(Bits::zero(), BitWidth, FullBitWidth, TargetEndianness);
314319

315320
std::memcpy(Buff, B.get(), BuffSize);
316321

317322
if (llvm::sys::IsBigEndianHost)
318-
swapBytes(Buff, BuffSize);
323+
swapBytes(Buff, BitWidth.roundToBytes());
319324

320325
return Success;
321326
}

clang/lib/AST/ByteCode/InterpBuiltinBitCast.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#ifndef LLVM_CLANG_AST_INTERP_BUILITN_BIT_CAST_H
1010
#define LLVM_CLANG_AST_INTERP_BUILITN_BIT_CAST_H
1111

12+
#include "BitcastBuffer.h"
1213
#include <cstddef>
1314

1415
namespace clang {
@@ -18,7 +19,8 @@ class InterpState;
1819
class CodePtr;
1920

2021
bool DoBitCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
21-
std::byte *Buff, size_t BuffSize, bool &HasIndeterminateBits);
22+
std::byte *Buff, Bits BitWidth, Bits FullBitWidth,
23+
bool &HasIndeterminateBits);
2224
bool DoBitCastPtr(InterpState &S, CodePtr OpPC, const Pointer &FromPtr,
2325
Pointer &ToPtr);
2426
bool DoBitCastPtr(InterpState &S, CodePtr OpPC, const Pointer &FromPtr,

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@ static_assert(round_trip<bytes>(ld), "");
4949

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

52+
constexpr long double foo() {
53+
bytes A = __builtin_bit_cast(bytes, ld);
54+
long double ld = __builtin_bit_cast(long double, A);
55+
return ld;
56+
}
57+
static_assert(foo() == ld);
58+
5259
#if 0
5360
constexpr bool f(bool read_uninit) {
5461
bytes b = bit_cast<bytes>(ld);

0 commit comments

Comments
 (0)