Skip to content

Commit 5dde320

Browse files
committed
[clang][bytecode] Handle bitcasts involving bitfields
1 parent c727b48 commit 5dde320

File tree

10 files changed

+782
-246
lines changed

10 files changed

+782
-246
lines changed
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
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 *data, size_t BitOffset,
14+
size_t BitWidth, Endian DataEndianness) {
15+
for (unsigned It = 0; It != BitWidth; ++It) {
16+
bool BitValue;
17+
BitValue = bitof(data, It);
18+
if (!BitValue)
19+
continue;
20+
21+
unsigned DstBit;
22+
if (DataEndianness == Endian::Little)
23+
DstBit = BitOffset + It;
24+
else
25+
DstBit = size() - BitOffset - BitWidth + It;
26+
27+
unsigned DstByte = (DstBit / 8);
28+
Data[DstByte] |= std::byte{1} << (DstBit % 8);
29+
}
30+
}
31+
32+
std::unique_ptr<std::byte[]>
33+
BitcastBuffer::copyBits(unsigned BitOffset, unsigned BitWidth,
34+
unsigned FullBitWidth, Endian DataEndianness) const {
35+
assert(BitWidth <= FullBitWidth);
36+
assert(fullByte(FullBitWidth));
37+
auto Out = std::make_unique<std::byte[]>(FullBitWidth / 8);
38+
39+
for (unsigned It = 0; It != BitWidth; ++It) {
40+
unsigned BitIndex;
41+
if (DataEndianness == Endian::Little)
42+
BitIndex = BitOffset + It;
43+
else
44+
BitIndex = size() - BitWidth - BitOffset + It;
45+
46+
bool BitValue = bitof(Data.get(), BitIndex);
47+
if (!BitValue)
48+
continue;
49+
unsigned DstBit = It;
50+
unsigned DstByte = (DstBit / 8);
51+
Out[DstByte] |= std::byte{1} << (DstBit % 8);
52+
}
53+
54+
return Out;
55+
}
56+
57+
#if 0
58+
template<typename T>
59+
static std::string hex(T t) {
60+
std::stringstream stream;
61+
stream << std::hex << (int)t;
62+
return std::string(stream.str());
63+
}
64+
65+
66+
void BitcastBuffer::dump(bool AsHex = true) const {
67+
llvm::errs() << "LSB\n ";
68+
unsigned LineLength = 0;
69+
for (unsigned I = 0; I != (FinalBitSize / 8); ++I) {
70+
std::byte B = Data[I];
71+
if (AsHex) {
72+
std::stringstream stream;
73+
stream << std::hex << (int)B;
74+
llvm::errs() << stream.str();
75+
LineLength += stream.str().size() + 1;
76+
} else {
77+
llvm::errs() << std::bitset<8>((int)B).to_string();
78+
LineLength += 8 + 1;
79+
// llvm::errs() << (int)B;
80+
}
81+
llvm::errs() << ' ';
82+
}
83+
llvm::errs() << '\n';
84+
85+
for (unsigned I = 0; I != LineLength; ++I)
86+
llvm::errs() << ' ';
87+
llvm::errs() << "MSB\n";
88+
}
89+
#endif
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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+
size_t size() const { return FinalBitSize; }
42+
43+
bool allInitialized() const {
44+
// FIXME: Implement.
45+
return true;
46+
}
47+
48+
void pushData(const std::byte *data, size_t BitOffset, size_t BitWidth,
49+
Endian DataEndianness);
50+
std::unique_ptr<std::byte[]> copyBits(unsigned BitOffset, unsigned BitWidth,
51+
unsigned FullBitWidth,
52+
Endian DataEndianness) const;
53+
};
54+
55+
} // namespace interp
56+
} // namespace clang
57+
#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)