Skip to content

Commit 441fd49

Browse files
committed
[clang][bytecode] Handle bitcasts involving bitfields
1 parent 6f16a8b commit 441fd49

File tree

10 files changed

+790
-246
lines changed

10 files changed

+790
-246
lines changed
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
//===-------------------- Bitcastbuffer.cpp ---------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
#include "BitcastBuffer.h"
9+
10+
using namespace clang;
11+
using namespace clang::interp;
12+
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);
17+
if (!BitValue)
18+
continue;
19+
20+
unsigned DstBit;
21+
if (TargetEndianness == Endian::Little)
22+
DstBit = BitOffset + It;
23+
else
24+
DstBit = size() - BitOffset - BitWidth + It;
25+
26+
unsigned DstByte = (DstBit / 8);
27+
Data[DstByte] |= std::byte{1} << (DstBit % 8);
28+
}
29+
}
30+
31+
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);
37+
38+
for (unsigned It = 0; It != BitWidth; ++It) {
39+
unsigned BitIndex;
40+
if (TargetEndianness == Endian::Little)
41+
BitIndex = BitOffset + It;
42+
else
43+
BitIndex = size() - BitWidth - BitOffset + It;
44+
45+
bool BitValue = bitof(Data.get(), BitIndex);
46+
if (!BitValue)
47+
continue;
48+
unsigned DstBit = It;
49+
unsigned DstByte = (DstBit / 8);
50+
Out[DstByte] |= std::byte{1} << (DstBit % 8);
51+
}
52+
53+
return Out;
54+
}
55+
56+
#if 0
57+
template<typename T>
58+
static std::string hex(T t) {
59+
std::stringstream stream;
60+
stream << std::hex << (int)t;
61+
return std::string(stream.str());
62+
}
63+
64+
65+
void BitcastBuffer::dump(bool AsHex = true) const {
66+
llvm::errs() << "LSB\n ";
67+
unsigned LineLength = 0;
68+
for (unsigned I = 0; I != (FinalBitSize / 8); ++I) {
69+
std::byte B = Data[I];
70+
if (AsHex) {
71+
std::stringstream stream;
72+
stream << std::hex << (int)B;
73+
llvm::errs() << stream.str();
74+
LineLength += stream.str().size() + 1;
75+
} else {
76+
llvm::errs() << std::bitset<8>((int)B).to_string();
77+
LineLength += 8 + 1;
78+
// llvm::errs() << (int)B;
79+
}
80+
llvm::errs() << ' ';
81+
}
82+
llvm::errs() << '\n';
83+
84+
for (unsigned I = 0; I != LineLength; ++I)
85+
llvm::errs() << ' ';
86+
llvm::errs() << "MSB\n";
87+
}
88+
#endif
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//===--------------------- BitcastBuffer.h ----------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
#ifndef LLVM_CLANG_AST_INTERP_BITCAST_BUFFER_H
9+
#define LLVM_CLANG_AST_INTERP_BITCAST_BUFFER_H
10+
11+
#include <cassert>
12+
#include <cstddef>
13+
#include <memory>
14+
15+
namespace clang {
16+
namespace interp {
17+
18+
enum class Endian { Little, Big };
19+
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+
}
24+
25+
/// Returns whether \p N is a full byte offset or size.
26+
static inline bool fullByte(unsigned N) { return N % 8 == 0; }
27+
28+
/// Track what bits have been initialized to known values and which ones
29+
/// have indeterminate value.
30+
/// All offsets are in bits.
31+
struct BitcastBuffer {
32+
size_t FinalBitSize = 0;
33+
std::unique_ptr<std::byte[]> Data;
34+
35+
BitcastBuffer(size_t FinalBitSize) : FinalBitSize(FinalBitSize) {
36+
assert(fullByte(FinalBitSize));
37+
unsigned ByteSize = FinalBitSize / 8;
38+
Data = std::make_unique<std::byte[]>(ByteSize);
39+
}
40+
41+
/// Returns the buffer size in bits.
42+
size_t size() const { return FinalBitSize; }
43+
44+
/// Returns \c true if all bits in the buffer have been initialized.
45+
bool allInitialized() const {
46+
// FIXME: Implement.
47+
return true;
48+
}
49+
50+
/// Push \p BitWidth bits at \p BitOffset from \p In into the buffer.
51+
/// \p TargetEndianness is the endianness of the target we're compiling for.
52+
/// \p In must hold at least \p BitWidth many bits.
53+
void pushData(const std::byte *In, size_t BitOffset, size_t BitWidth,
54+
Endian TargetEndianness);
55+
56+
/// Copy \p BitWidth bits at offset \p BitOffset from the buffer.
57+
/// \p TargetEndianness is the endianness of the target we're compiling for.
58+
///
59+
/// The returned output holds exactly (\p FullBitWidth / 8) bytes.
60+
std::unique_ptr<std::byte[]> copyBits(unsigned BitOffset, unsigned BitWidth,
61+
unsigned FullBitWidth,
62+
Endian TargetEndianness) const;
63+
};
64+
65+
} // namespace interp
66+
} // namespace clang
67+
#endif

clang/lib/AST/ByteCode/Boolean.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,7 @@ class Boolean final {
8282
Boolean truncate(unsigned TruncBits) const { return *this; }
8383

8484
static Boolean bitcastFromMemory(const std::byte *Buff, unsigned BitWidth) {
85-
// Boolean width is currently always 8 for all supported targets. If this
86-
// changes we need to get the bool width from the target info.
87-
assert(BitWidth == 8);
85+
// Just load the first byte.
8886
bool Val = static_cast<bool>(*Buff);
8987
return Boolean(Val);
9088
}

clang/lib/AST/ByteCode/Integral.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ template <unsigned Bits, bool Signed> class Integral final {
181181
}
182182

183183
Integral truncate(unsigned TruncBits) const {
184+
assert(TruncBits >= 1);
184185
if (TruncBits >= Bits)
185186
return *this;
186187
const ReprT BitMask = (ReprT(1) << ReprT(TruncBits)) - 1;

0 commit comments

Comments
 (0)