Skip to content

Commit 7d58afa

Browse files
committed
Use Bits and Bytes structs
1 parent 441fd49 commit 7d58afa

File tree

4 files changed

+110
-78
lines changed

4 files changed

+110
-78
lines changed

clang/lib/AST/ByteCode/BitcastBuffer.cpp

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,44 +10,51 @@
1010
using namespace clang;
1111
using namespace clang::interp;
1212

13-
void BitcastBuffer::pushData(const std::byte *In, size_t BitOffset,
14-
size_t BitWidth, Endian TargetEndianness) {
15-
for (unsigned It = 0; It != BitWidth; ++It) {
16-
bool BitValue = bitof(In, It);
13+
/// Returns the value of the bit in the given sequence of bytes.
14+
static inline bool bitof(const std::byte *B, Bits BitIndex) {
15+
return (B[BitIndex.roundToBytes()] &
16+
(std::byte{1} << BitIndex.getOffsetInByte())) != std::byte{0};
17+
}
18+
19+
void BitcastBuffer::pushData(const std::byte *In, Bits BitOffset, Bits BitWidth,
20+
Endian TargetEndianness) {
21+
for (unsigned It = 0; It != BitWidth.getQuantity(); ++It) {
22+
bool BitValue = bitof(In, Bits(It));
1723
if (!BitValue)
1824
continue;
1925

20-
unsigned DstBit;
26+
Bits DstBit;
2127
if (TargetEndianness == Endian::Little)
22-
DstBit = BitOffset + It;
28+
DstBit = BitOffset + Bits(It);
2329
else
24-
DstBit = size() - BitOffset - BitWidth + It;
30+
DstBit = size() - BitOffset - BitWidth + Bits(It);
2531

26-
unsigned DstByte = (DstBit / 8);
27-
Data[DstByte] |= std::byte{1} << (DstBit % 8);
32+
size_t DstByte = DstBit.roundToBytes();
33+
Data[DstByte] |= std::byte{1} << DstBit.getOffsetInByte();
2834
}
2935
}
3036

3137
std::unique_ptr<std::byte[]>
32-
BitcastBuffer::copyBits(unsigned BitOffset, unsigned BitWidth,
33-
unsigned FullBitWidth, Endian TargetEndianness) const {
34-
assert(BitWidth <= FullBitWidth);
35-
assert(fullByte(FullBitWidth));
36-
auto Out = std::make_unique<std::byte[]>(FullBitWidth / 8);
38+
BitcastBuffer::copyBits(Bits BitOffset, Bits BitWidth, Bits FullBitWidth,
39+
Endian TargetEndianness) const {
40+
assert(BitWidth.getQuantity() <= FullBitWidth.getQuantity());
41+
assert(FullBitWidth.isFullByte());
42+
auto Out = std::make_unique<std::byte[]>(FullBitWidth.roundToBytes());
3743

38-
for (unsigned It = 0; It != BitWidth; ++It) {
39-
unsigned BitIndex;
44+
for (unsigned It = 0; It != BitWidth.getQuantity(); ++It) {
45+
Bits BitIndex;
4046
if (TargetEndianness == Endian::Little)
41-
BitIndex = BitOffset + It;
47+
BitIndex = BitOffset + Bits(It);
4248
else
43-
BitIndex = size() - BitWidth - BitOffset + It;
49+
BitIndex = size() - BitWidth - BitOffset + Bits(It);
4450

4551
bool BitValue = bitof(Data.get(), BitIndex);
4652
if (!BitValue)
4753
continue;
48-
unsigned DstBit = It;
49-
unsigned DstByte = (DstBit / 8);
50-
Out[DstByte] |= std::byte{1} << (DstBit % 8);
54+
55+
Bits DstBit = Bits(It);
56+
size_t DstByte = DstBit.roundToBytes();
57+
Out[DstByte] |= std::byte{1} << DstBit.getOffsetInByte();
5158
}
5259

5360
return Out;

clang/lib/AST/ByteCode/BitcastBuffer.h

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,29 +17,48 @@ namespace interp {
1717

1818
enum class Endian { Little, Big };
1919

20-
/// Returns the value of the bit in the given sequence of bytes.
21-
static inline bool bitof(const std::byte *B, unsigned BitIndex) {
22-
return (B[BitIndex / 8] & (std::byte{1} << (BitIndex % 8))) != std::byte{0};
23-
}
20+
/// A quantity in bits.
21+
struct Bits {
22+
size_t N = 0;
23+
Bits() = default;
24+
static Bits zero() { return Bits(0); }
25+
explicit Bits(size_t Quantity) : N(Quantity) {}
26+
size_t getQuantity() const { return N; }
27+
size_t roundToBytes() const { return N / 8; }
28+
size_t getOffsetInByte() const { return N % 8; }
29+
bool isFullByte() const { return N % 8 == 0; }
30+
bool nonZero() const { return N != 0; }
2431

25-
/// Returns whether \p N is a full byte offset or size.
26-
static inline bool fullByte(unsigned N) { return N % 8 == 0; }
32+
Bits operator-(Bits Other) { return Bits(N - Other.N); }
33+
Bits operator+(Bits Other) { return Bits(N + Other.N); }
34+
Bits operator+=(size_t O) {
35+
N += O;
36+
return *this;
37+
}
38+
};
39+
40+
/// A quantity in bytes.
41+
struct Bytes {
42+
size_t N;
43+
explicit Bytes(size_t Quantity) : N(Quantity) {}
44+
size_t getQuantity() const { return N; }
45+
Bits toBits() const { return Bits(N * 8); }
46+
};
2747

2848
/// Track what bits have been initialized to known values and which ones
2949
/// have indeterminate value.
30-
/// All offsets are in bits.
3150
struct BitcastBuffer {
32-
size_t FinalBitSize = 0;
51+
Bits FinalBitSize;
3352
std::unique_ptr<std::byte[]> Data;
3453

35-
BitcastBuffer(size_t FinalBitSize) : FinalBitSize(FinalBitSize) {
36-
assert(fullByte(FinalBitSize));
37-
unsigned ByteSize = FinalBitSize / 8;
54+
BitcastBuffer(Bits FinalBitSize) : FinalBitSize(FinalBitSize) {
55+
assert(FinalBitSize.isFullByte());
56+
unsigned ByteSize = FinalBitSize.roundToBytes();
3857
Data = std::make_unique<std::byte[]>(ByteSize);
3958
}
4059

4160
/// Returns the buffer size in bits.
42-
size_t size() const { return FinalBitSize; }
61+
Bits size() const { return FinalBitSize; }
4362

4463
/// Returns \c true if all bits in the buffer have been initialized.
4564
bool allInitialized() const {
@@ -50,15 +69,15 @@ struct BitcastBuffer {
5069
/// Push \p BitWidth bits at \p BitOffset from \p In into the buffer.
5170
/// \p TargetEndianness is the endianness of the target we're compiling for.
5271
/// \p In must hold at least \p BitWidth many bits.
53-
void pushData(const std::byte *In, size_t BitOffset, size_t BitWidth,
72+
void pushData(const std::byte *In, Bits BitOffset, Bits BitWidth,
5473
Endian TargetEndianness);
5574

5675
/// Copy \p BitWidth bits at offset \p BitOffset from the buffer.
5776
/// \p TargetEndianness is the endianness of the target we're compiling for.
5877
///
5978
/// The returned output holds exactly (\p FullBitWidth / 8) bytes.
60-
std::unique_ptr<std::byte[]> copyBits(unsigned BitOffset, unsigned BitWidth,
61-
unsigned FullBitWidth,
79+
std::unique_ptr<std::byte[]> copyBits(Bits BitOffset, Bits BitWidth,
80+
Bits FullBitWidth,
6281
Endian TargetEndianness) const;
6382
};
6483

clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp

Lines changed: 35 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ using namespace clang::interp;
3434

3535
/// Used to iterate over pointer fields.
3636
using DataFunc = llvm::function_ref<bool(const Pointer &P, PrimType Ty,
37-
size_t BitOffset, bool PackedBools)>;
37+
Bits BitOffset, bool PackedBools)>;
3838

3939
#define BITCAST_TYPE_SWITCH(Expr, B) \
4040
do { \
@@ -79,7 +79,7 @@ static void swapBytes(std::byte *M, size_t N) {
7979

8080
/// We use this to recursively iterate over all fields and elements of a pointer
8181
/// and extract relevant data for a bitcast.
82-
static bool enumerateData(const Pointer &P, const Context &Ctx, size_t Offset,
82+
static bool enumerateData(const Pointer &P, const Context &Ctx, Bits Offset,
8383
DataFunc F) {
8484
const Descriptor *FieldDesc = P.getFieldDesc();
8585
assert(FieldDesc);
@@ -124,15 +124,15 @@ static bool enumerateData(const Pointer &P, const Context &Ctx, size_t Offset,
124124

125125
for (const Record::Field &Fi : R->fields()) {
126126
Pointer Elem = P.atField(Fi.Offset);
127-
size_t BitOffset =
128-
Offset + Layout.getFieldOffset(Fi.Decl->getFieldIndex());
127+
Bits BitOffset =
128+
Offset + Bits(Layout.getFieldOffset(Fi.Decl->getFieldIndex()));
129129
Ok = Ok && enumerateData(Elem, Ctx, BitOffset, F);
130130
}
131131
for (const Record::Base &B : R->bases()) {
132132
Pointer Elem = P.atField(B.Offset);
133133
CharUnits ByteOffset =
134134
Layout.getBaseClassOffset(cast<CXXRecordDecl>(B.Decl));
135-
size_t BitOffset = Offset + Ctx.getASTContext().toBits(ByteOffset);
135+
Bits BitOffset = Offset + Bits(Ctx.getASTContext().toBits(ByteOffset));
136136
Ok = Ok && enumerateData(Elem, Ctx, BitOffset, F);
137137
}
138138

@@ -144,7 +144,7 @@ static bool enumerateData(const Pointer &P, const Context &Ctx, size_t Offset,
144144

145145
static bool enumeratePointerFields(const Pointer &P, const Context &Ctx,
146146
DataFunc F) {
147-
return enumerateData(P, Ctx, 0, F);
147+
return enumerateData(P, Ctx, Bits::zero(), F);
148148
}
149149

150150
// This function is constexpr if and only if To, From, and the types of
@@ -223,7 +223,7 @@ static bool readPointerToBuffer(const Context &Ctx, const Pointer &FromPtr,
223223

224224
return enumeratePointerFields(
225225
FromPtr, Ctx,
226-
[&](const Pointer &P, PrimType T, size_t BitOffset,
226+
[&](const Pointer &P, PrimType T, Bits BitOffset,
227227
bool PackedBools) -> bool {
228228
// if (!P.isInitialized()) {
229229
// assert(false && "Implement uninitialized value tracking");
@@ -236,35 +236,36 @@ static bool readPointerToBuffer(const Context &Ctx, const Pointer &FromPtr,
236236
assert(false && "Implement casting to pointer types");
237237

238238
CharUnits ObjectReprChars = ASTCtx.getTypeSizeInChars(P.getType());
239-
unsigned BitWidth = ASTCtx.toBits(ObjectReprChars);
240-
unsigned FullBitWidth = BitWidth;
239+
Bits BitWidth = Bits(ASTCtx.toBits(ObjectReprChars));
240+
Bits FullBitWidth = BitWidth;
241241
auto Buff =
242242
std::make_unique<std::byte[]>(ObjectReprChars.getQuantity());
243243
// Work around floating point types that contain unused padding bytes.
244244
// This is really just `long double` on x86, which is the only
245245
// fundamental type with padding bytes.
246246
if (T == PT_Float) {
247247
const Floating &F = P.deref<Floating>();
248-
unsigned NumBits =
249-
llvm::APFloatBase::getSizeInBits(F.getAPFloat().getSemantics());
250-
assert(fullByte(NumBits));
251-
assert(NumBits <= FullBitWidth);
248+
Bits NumBits = Bits(
249+
llvm::APFloatBase::getSizeInBits(F.getAPFloat().getSemantics()));
250+
assert(NumBits.isFullByte());
251+
assert(NumBits.getQuantity() <= FullBitWidth.getQuantity());
252252
F.bitcastToMemory(Buff.get());
253253
// Now, only (maybe) swap the actual size of the float, excluding the
254254
// padding bits.
255255
if (llvm::sys::IsBigEndianHost)
256-
swapBytes(Buff.get(), NumBits / 8);
256+
swapBytes(Buff.get(), NumBits.roundToBytes());
257257

258258
} else {
259259
if (const FieldDecl *FD = P.getField(); FD && FD->isBitField())
260-
BitWidth = std::min(FD->getBitWidthValue(ASTCtx), FullBitWidth);
260+
BitWidth = Bits(std::min(FD->getBitWidthValue(ASTCtx),
261+
(unsigned)FullBitWidth.getQuantity()));
261262
else if (T == PT_Bool && PackedBools)
262-
BitWidth = 1;
263+
BitWidth = Bits(1);
263264

264265
BITCAST_TYPE_SWITCH(T, { P.deref<T>().bitcastToMemory(Buff.get()); });
265266

266267
if (llvm::sys::IsBigEndianHost)
267-
swapBytes(Buff.get(), FullBitWidth / 8);
268+
swapBytes(Buff.get(), FullBitWidth.roundToBytes());
268269
}
269270

270271
Buffer.pushData(Buff.get(), BitOffset, BitWidth, TargetEndianness);
@@ -279,7 +280,7 @@ bool clang::interp::DoBitCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
279280
assert(Ptr.isBlockPointer());
280281
assert(Buff);
281282

282-
size_t BitSize = BuffSize * 8;
283+
Bits BitSize = Bytes(BuffSize).toBits();
283284
BitcastBuffer Buffer(BitSize);
284285
if (!CheckBitcastType(S, OpPC, Ptr.getType(), /*IsToType=*/false))
285286
return false;
@@ -291,7 +292,7 @@ bool clang::interp::DoBitCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
291292
const ASTContext &ASTCtx = S.getASTContext();
292293
Endian TargetEndianness =
293294
ASTCtx.getTargetInfo().isLittleEndian() ? Endian::Little : Endian::Big;
294-
auto B = Buffer.copyBits(0, BitSize, BitSize, TargetEndianness);
295+
auto B = Buffer.copyBits(Bits::zero(), BitSize, BitSize, TargetEndianness);
295296

296297
std::memcpy(Buff, B.get(), BuffSize);
297298

@@ -318,7 +319,7 @@ bool clang::interp::DoBitCastPtr(InterpState &S, CodePtr OpPC,
318319
const ASTContext &ASTCtx = S.getASTContext();
319320

320321
CharUnits ObjectReprChars = ASTCtx.getTypeSizeInChars(ToType);
321-
BitcastBuffer Buffer(ASTCtx.toBits(ObjectReprChars));
322+
BitcastBuffer Buffer(Bits(ASTCtx.toBits(ObjectReprChars)));
322323
readPointerToBuffer(S.getContext(), FromPtr, Buffer,
323324
/*ReturnOnUninit=*/false);
324325

@@ -327,43 +328,44 @@ bool clang::interp::DoBitCastPtr(InterpState &S, CodePtr OpPC,
327328
ASTCtx.getTargetInfo().isLittleEndian() ? Endian::Little : Endian::Big;
328329
bool Success = enumeratePointerFields(
329330
ToPtr, S.getContext(),
330-
[&](const Pointer &P, PrimType T, size_t BitOffset,
331+
[&](const Pointer &P, PrimType T, Bits BitOffset,
331332
bool PackedBools) -> bool {
332333
CharUnits ObjectReprChars = ASTCtx.getTypeSizeInChars(P.getType());
333-
unsigned FullBitWidth = ASTCtx.toBits(ObjectReprChars);
334+
Bits FullBitWidth = Bits(ASTCtx.toBits(ObjectReprChars));
334335
if (T == PT_Float) {
335336
const auto &Semantics = ASTCtx.getFloatTypeSemantics(P.getType());
336-
unsigned NumBits = llvm::APFloatBase::getSizeInBits(Semantics);
337-
assert(fullByte(NumBits));
338-
assert(NumBits <= FullBitWidth);
337+
Bits NumBits = Bits(llvm::APFloatBase::getSizeInBits(Semantics));
338+
assert(NumBits.isFullByte());
339+
assert(NumBits.getQuantity() <= FullBitWidth.getQuantity());
339340
auto M = Buffer.copyBits(BitOffset, NumBits, FullBitWidth,
340341
TargetEndianness);
341342

342343
if (llvm::sys::IsBigEndianHost)
343-
swapBytes(M.get(), NumBits / 8);
344+
swapBytes(M.get(), NumBits.roundToBytes());
344345

345346
P.deref<Floating>() = Floating::bitcastFromMemory(M.get(), Semantics);
346347
P.initialize();
347348
return true;
348349
}
349350

350-
unsigned BitWidth;
351+
Bits BitWidth;
351352
if (const FieldDecl *FD = P.getField(); FD && FD->isBitField())
352-
BitWidth = std::min(FD->getBitWidthValue(ASTCtx), FullBitWidth);
353+
BitWidth = Bits(std::min(FD->getBitWidthValue(ASTCtx),
354+
(unsigned)FullBitWidth.getQuantity()));
353355
else if (T == PT_Bool && PackedBools)
354-
BitWidth = 1;
356+
BitWidth = Bits(1);
355357
else
356-
BitWidth = ASTCtx.toBits(ObjectReprChars);
358+
BitWidth = FullBitWidth;
357359

358360
auto Memory = Buffer.copyBits(BitOffset, BitWidth, FullBitWidth,
359361
TargetEndianness);
360362
if (llvm::sys::IsBigEndianHost)
361-
swapBytes(Memory.get(), FullBitWidth / 8);
363+
swapBytes(Memory.get(), FullBitWidth.roundToBytes());
362364

363365
BITCAST_TYPE_SWITCH_FIXED_SIZE(T, {
364-
if (BitWidth > 0)
366+
if (BitWidth.nonZero())
365367
P.deref<T>() = T::bitcastFromMemory(Memory.get(), T::bitWidth())
366-
.truncate(BitWidth);
368+
.truncate(BitWidth.getQuantity());
367369
else
368370
P.deref<T>() = T::zero();
369371
});

0 commit comments

Comments
 (0)