Skip to content

Commit 1fbbf4c

Browse files
authored
[clang][bytecode] Pass (float) BitWidth to DoBitCast (llvm#119119)
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 8843d2b commit 1fbbf4c

File tree

5 files changed

+42
-24
lines changed

5 files changed

+42
-24
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: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@
66
// RUN: %clang_cc1 -verify=expected,both -std=c++2a -fsyntax-only -triple x86_64-apple-macosx10.14.0 %s -fno-signed-char -fexperimental-new-constant-interpreter
77
// RUN: %clang_cc1 -verify=expected,both -std=c++2a -fsyntax-only -triple aarch64_be-linux-gnu %s -fexperimental-new-constant-interpreter
88

9+
#if !__x86_64
910
// both-no-diagnostics
11+
#endif
12+
1013

1114
typedef decltype(nullptr) nullptr_t;
1215
typedef __INTPTR_TYPE__ intptr_t;
@@ -35,6 +38,7 @@ constexpr Init round_trip(const Init &init) {
3538

3639
namespace test_long_double {
3740
#if __x86_64
41+
/// FIXME: We could enable this, but since it aborts, it causes the usual mempory leak.
3842
#if 0
3943
constexpr __int128_t test_cast_to_int128 = bit_cast<__int128_t>((long double)0); // expected-error{{must be initialized by a constant expression}}\
4044
// expected-note{{in call}}
@@ -49,7 +53,13 @@ static_assert(round_trip<bytes>(ld), "");
4953

5054
static_assert(round_trip<long double>(10.0L));
5155

52-
#if 0
56+
constexpr long double foo() {
57+
bytes A = __builtin_bit_cast(bytes, ld);
58+
long double ld = __builtin_bit_cast(long double, A);
59+
return ld;
60+
}
61+
static_assert(foo() == ld);
62+
5363
constexpr bool f(bool read_uninit) {
5464
bytes b = bit_cast<bytes>(ld);
5565
unsigned char ld_bytes[10] = {
@@ -61,16 +71,15 @@ constexpr bool f(bool read_uninit) {
6171
if (ld_bytes[i] != b.d[i])
6272
return false;
6373

64-
if (read_uninit && b.d[10]) // expected-note{{read of uninitialized object is not allowed in a constant expression}}
74+
if (read_uninit && b.d[10]) // both-note{{read of uninitialized object is not allowed in a constant expression}}
6575
return false;
6676

6777
return true;
6878
}
6979

7080
static_assert(f(/*read_uninit=*/false), "");
71-
static_assert(f(/*read_uninit=*/true), ""); // expected-error{{static assertion expression is not an integral constant expression}} \
72-
// expected-note{{in call to 'f(true)'}}
73-
#endif
81+
static_assert(f(/*read_uninit=*/true), ""); // both-error{{static assertion expression is not an integral constant expression}} \
82+
// both-note{{in call to 'f(true)'}}
7483
constexpr bytes ld539 = {
7584
0x0, 0x0, 0x0, 0x0,
7685
0x0, 0x0, 0xc0, 0x86,

0 commit comments

Comments
 (0)