Skip to content

Commit 12ca72b

Browse files
committed
Reapply "[clang][bytecode] Handle bitcasts involving bitfields (#116843)"
This reverts commit 54db162. Check for existence of __SIZOEF_INT128__ so we don't run those tests on targets that don't have int128.
1 parent ecbe4d1 commit 12ca72b

File tree

10 files changed

+861
-260
lines changed

10 files changed

+861
-260
lines changed
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
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+
/// 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));
23+
if (!BitValue)
24+
continue;
25+
26+
Bits DstBit;
27+
if (TargetEndianness == Endian::Little)
28+
DstBit = BitOffset + Bits(It);
29+
else
30+
DstBit = size() - BitOffset - BitWidth + Bits(It);
31+
32+
size_t DstByte = DstBit.roundToBytes();
33+
Data[DstByte] |= std::byte{1} << DstBit.getOffsetInByte();
34+
}
35+
}
36+
37+
std::unique_ptr<std::byte[]>
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());
43+
44+
for (unsigned It = 0; It != BitWidth.getQuantity(); ++It) {
45+
Bits BitIndex;
46+
if (TargetEndianness == Endian::Little)
47+
BitIndex = BitOffset + Bits(It);
48+
else
49+
BitIndex = size() - BitWidth - BitOffset + Bits(It);
50+
51+
bool BitValue = bitof(Data.get(), BitIndex);
52+
if (!BitValue)
53+
continue;
54+
55+
Bits DstBit = Bits(It);
56+
size_t DstByte = DstBit.roundToBytes();
57+
Out[DstByte] |= std::byte{1} << DstBit.getOffsetInByte();
58+
}
59+
60+
return Out;
61+
}
62+
63+
#if 0
64+
template<typename T>
65+
static std::string hex(T t) {
66+
std::stringstream stream;
67+
stream << std::hex << (int)t;
68+
return std::string(stream.str());
69+
}
70+
71+
72+
void BitcastBuffer::dump(bool AsHex = true) const {
73+
llvm::errs() << "LSB\n ";
74+
unsigned LineLength = 0;
75+
for (unsigned I = 0; I != (FinalBitSize / 8); ++I) {
76+
std::byte B = Data[I];
77+
if (AsHex) {
78+
std::stringstream stream;
79+
stream << std::hex << (int)B;
80+
llvm::errs() << stream.str();
81+
LineLength += stream.str().size() + 1;
82+
} else {
83+
llvm::errs() << std::bitset<8>((int)B).to_string();
84+
LineLength += 8 + 1;
85+
// llvm::errs() << (int)B;
86+
}
87+
llvm::errs() << ' ';
88+
}
89+
llvm::errs() << '\n';
90+
91+
for (unsigned I = 0; I != LineLength; ++I)
92+
llvm::errs() << ' ';
93+
llvm::errs() << "MSB\n";
94+
}
95+
#endif
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
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+
/// 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; }
31+
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+
bool operator>=(Bits Other) { return N >= Other.N; }
40+
};
41+
42+
/// A quantity in bytes.
43+
struct Bytes {
44+
size_t N;
45+
explicit Bytes(size_t Quantity) : N(Quantity) {}
46+
size_t getQuantity() const { return N; }
47+
Bits toBits() const { return Bits(N * 8); }
48+
};
49+
50+
/// Track what bits have been initialized to known values and which ones
51+
/// have indeterminate value.
52+
struct BitcastBuffer {
53+
Bits FinalBitSize;
54+
std::unique_ptr<std::byte[]> Data;
55+
56+
BitcastBuffer(Bits FinalBitSize) : FinalBitSize(FinalBitSize) {
57+
assert(FinalBitSize.isFullByte());
58+
unsigned ByteSize = FinalBitSize.roundToBytes();
59+
Data = std::make_unique<std::byte[]>(ByteSize);
60+
}
61+
62+
/// Returns the buffer size in bits.
63+
Bits size() const { return FinalBitSize; }
64+
65+
/// Returns \c true if all bits in the buffer have been initialized.
66+
bool allInitialized() const {
67+
// FIXME: Implement.
68+
return true;
69+
}
70+
71+
/// Push \p BitWidth bits at \p BitOffset from \p In into the buffer.
72+
/// \p TargetEndianness is the endianness of the target we're compiling for.
73+
/// \p In must hold at least \p BitWidth many bits.
74+
void pushData(const std::byte *In, Bits BitOffset, Bits BitWidth,
75+
Endian TargetEndianness);
76+
77+
/// Copy \p BitWidth bits at offset \p BitOffset from the buffer.
78+
/// \p TargetEndianness is the endianness of the target we're compiling for.
79+
///
80+
/// The returned output holds exactly (\p FullBitWidth / 8) bytes.
81+
std::unique_ptr<std::byte[]> copyBits(Bits BitOffset, Bits BitWidth,
82+
Bits FullBitWidth,
83+
Endian TargetEndianness) const;
84+
};
85+
86+
} // namespace interp
87+
} // namespace clang
88+
#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
@@ -183,6 +183,7 @@ template <unsigned Bits, bool Signed> class Integral final {
183183
}
184184

185185
Integral truncate(unsigned TruncBits) const {
186+
assert(TruncBits >= 1);
186187
if (TruncBits >= Bits)
187188
return *this;
188189
const ReprT BitMask = (ReprT(1) << ReprT(TruncBits)) - 1;

0 commit comments

Comments
 (0)