Skip to content

Commit afd8a49

Browse files
committed
Support IntegralAP bit casts
1 parent 5c77f91 commit afd8a49

File tree

8 files changed

+54
-17
lines changed

8 files changed

+54
-17
lines changed

clang/lib/AST/Interp/Boolean.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616
#include "llvm/ADT/APSInt.h"
1717
#include "llvm/Support/MathExtras.h"
1818
#include "llvm/Support/raw_ostream.h"
19-
#include <cstddef>
20-
#include <cstdint>
2119

2220
namespace clang {
2321
namespace interp {
@@ -114,7 +112,8 @@ class Boolean final {
114112
return Boolean(!Value.isZero());
115113
}
116114

117-
static Boolean bitcastFromMemory(const std::byte *Buff) {
115+
static Boolean bitcastFromMemory(const std::byte *Buff, unsigned BitWidth) {
116+
assert(BitWidth == 8);
118117
bool Val = static_cast<bool>(*Buff);
119118
return Boolean(Val);
120119
}

clang/lib/AST/Interp/ByteCodeExprGen.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,10 @@ bool ByteCodeExprGen<Emitter>::emitBuiltinBitCast(const CastExpr *E) {
130130

131131
bool ToTypeIsUChar = (ToType->isSpecificBuiltinType(BuiltinType::UChar) ||
132132
ToType->isSpecificBuiltinType(BuiltinType::Char_U));
133+
uint32_t ResultBitWidth = std::max(Ctx.getBitWidth(ToType), 8u);
133134

134-
if (!this->emitBitCast(*ToT, ToTypeIsUChar || ToType->isStdByteType(), E))
135+
if (!this->emitBitCast(*ToT, ToTypeIsUChar || ToType->isStdByteType(),
136+
ResultBitWidth, E))
135137
return false;
136138

137139
if (DiscardResult)

clang/lib/AST/Interp/Integral.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,8 @@ template <unsigned Bits, bool Signed> class Integral final {
193193
return Integral(Value);
194194
}
195195

196-
static Integral bitcastFromMemory(const std::byte *Buff) {
196+
static Integral bitcastFromMemory(const std::byte *Buff, unsigned BitWidth) {
197+
assert(BitWidth == sizeof(ReprT) * 8);
197198
ReprT V;
198199

199200
std::memcpy(&V, Buff, sizeof(ReprT));

clang/lib/AST/Interp/IntegralAP.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
#include "clang/AST/APValue.h"
1717
#include "clang/AST/ComparisonCategories.h"
18+
#include "llvm/ADT/APInt.h"
1819
#include "llvm/ADT/APSInt.h"
1920
#include "llvm/Support/MathExtras.h"
2021
#include "llvm/Support/raw_ostream.h"
@@ -61,7 +62,7 @@ template <bool Signed> class IntegralAP final {
6162

6263
IntegralAP(APInt V) : V(V) {}
6364
/// Arbitrary value for uninitialized variables.
64-
IntegralAP() : IntegralAP(-1, 1024) {}
65+
IntegralAP() : IntegralAP(-1, 17) {}
6566

6667
IntegralAP operator-() const { return IntegralAP(-V); }
6768
IntegralAP operator-(const IntegralAP &Other) const {
@@ -123,6 +124,11 @@ template <bool Signed> class IntegralAP final {
123124
}
124125

125126
constexpr unsigned bitWidth() const { return V.getBitWidth(); }
127+
constexpr unsigned objectReprBits() { return bitWidth(); }
128+
constexpr unsigned valueReprBits(const ASTContext &Ctx) { return bitWidth(); }
129+
constexpr unsigned valueReprBytes(const ASTContext &Ctx) {
130+
return Ctx.toCharUnitsFromBits(bitWidth()).getQuantity();
131+
}
126132

127133
APSInt toAPSInt(unsigned Bits = 0) const {
128134
if (Bits == 0)
@@ -145,6 +151,17 @@ template <bool Signed> class IntegralAP final {
145151

146152
unsigned countLeadingZeros() const { return V.countl_zero(); }
147153

154+
static IntegralAP bitcastFromMemory(const std::byte *Buff,
155+
unsigned BitWidth) {
156+
APInt V(BitWidth, static_cast<uint64_t>(0), Signed);
157+
llvm::LoadIntFromMemory(V, (const uint8_t *)Buff, BitWidth / 8);
158+
return IntegralAP(V);
159+
}
160+
161+
void bitcastToMemory(std::byte *Buff) const {
162+
llvm::StoreIntToMemory(V, (uint8_t *)Buff, bitWidth() / 8);
163+
}
164+
148165
void print(llvm::raw_ostream &OS) const { OS << V; }
149166
std::string toDiagnosticString(const ASTContext &Ctx) const {
150167
std::string NameStr;

clang/lib/AST/Interp/Interp.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1577,11 +1577,12 @@ template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
15771577
}
15781578

15791579
template <PrimType Name, class ToT = typename PrimConv<Name>::T>
1580-
bool BitCast(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte) {
1580+
bool BitCast(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte,
1581+
uint32_t ResultBitWidth) {
15811582
const Pointer &FromPtr = S.Stk.pop<Pointer>();
15821583

1583-
size_t BuffSize = ToT::valueReprBytes(S.getCtx());
1584-
std::vector<std::byte> Buff(BuffSize);
1584+
size_t BuffSize = ResultBitWidth / 8;
1585+
llvm::SmallVector<std::byte> Buff(BuffSize);
15851586
bool HasIndeterminateBits = false;
15861587

15871588
if (!DoBitCast(S, OpPC, FromPtr, Buff.data(), BuffSize, HasIndeterminateBits))
@@ -1590,7 +1591,7 @@ bool BitCast(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte) {
15901591
if (!CheckBitcast(S, OpPC, HasIndeterminateBits, TargetIsUCharOrByte))
15911592
return false;
15921593

1593-
S.Stk.push<ToT>(ToT::bitcastFromMemory(Buff.data()));
1594+
S.Stk.push<ToT>(ToT::bitcastFromMemory(Buff.data(), ResultBitWidth));
15941595
return true;
15951596
}
15961597

clang/lib/AST/Interp/InterpBitcast.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ using DataFunc =
3232
TYPE_SWITCH_CASE(PT_Uint32, B) \
3333
TYPE_SWITCH_CASE(PT_Sint64, B) \
3434
TYPE_SWITCH_CASE(PT_Uint64, B) \
35+
TYPE_SWITCH_CASE(PT_IntAP, B) \
36+
TYPE_SWITCH_CASE(PT_IntAPS, B) \
3537
TYPE_SWITCH_CASE(PT_Bool, B) \
3638
default: \
3739
llvm_unreachable("Unhandled bitcast type"); \
@@ -51,6 +53,8 @@ using DataFunc =
5153
TYPE_SWITCH_CASE(PT_Uint32, B) \
5254
TYPE_SWITCH_CASE(PT_Sint64, B) \
5355
TYPE_SWITCH_CASE(PT_Uint64, B) \
56+
TYPE_SWITCH_CASE(PT_IntAP, B) \
57+
TYPE_SWITCH_CASE(PT_IntAPS, B) \
5458
TYPE_SWITCH_CASE(PT_Bool, B) \
5559
TYPE_SWITCH_CASE(PT_Float, B) \
5660
default: \
@@ -384,10 +388,10 @@ bool DoBitCastToPtr(InterpState &S, const Pointer &P, Pointer &DestPtr,
384388

385389
CharUnits ObjectReprChars = ASTCtx.getTypeSizeInChars(P.getType());
386390
const std::byte *M = Bytes.getBytes(BitOffset, 1234);
387-
std::byte *Buff = (std::byte *)std::malloc(
388-
ObjectReprChars.getQuantity()); //[sizeof(T)];
391+
std::byte *Buff =
392+
(std::byte *)std::malloc(ObjectReprChars.getQuantity());
389393
std::memcpy(Buff, M, ObjectReprChars.getQuantity());
390-
// Val.bitcastToMemory(Buff);
394+
391395
if (BigEndian)
392396
swapBytes(Buff, ObjectReprChars.getQuantity());
393397

@@ -407,7 +411,7 @@ bool DoBitCastToPtr(InterpState &S, const Pointer &P, Pointer &DestPtr,
407411
BITCAST_TYPE_SWITCH(T, {
408412
T &Val = P.deref<T>();
409413

410-
size_t ValueReprBits = T::valueReprBits(ASTCtx);
414+
size_t ValueReprBits = Val.valueReprBits(ASTCtx);
411415
// Check if any of the bits we're about to read are uninitialized.
412416
bool HasIndeterminateBits =
413417
!Bytes.allInitialized(BitOffset, ValueReprBits);
@@ -440,7 +444,7 @@ bool DoBitCastToPtr(InterpState &S, const Pointer &P, Pointer &DestPtr,
440444
if (BigEndian) {
441445
swapBytes(Copy, ValueReprBits / 8);
442446
}
443-
Val = T::bitcastFromMemory(Copy);
447+
Val = T::bitcastFromMemory(Copy, Val.bitWidth());
444448
std::free(Copy);
445449

446450
if (!HasIndeterminateBits)

clang/lib/AST/Interp/Opcodes.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -586,13 +586,13 @@ def Cast: Opcode {
586586
}
587587

588588
def BitCastTypeClass : TypeClass {
589-
let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, Bool];
589+
let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, IntAP, IntAPS, Bool];
590590
}
591591

592592
def BitCast : Opcode {
593593
let Types = [BitCastTypeClass];
594594
let HasGroup = 1;
595-
let Args = [ArgBool];
595+
let Args = [ArgBool, ArgUint32];
596596
}
597597

598598
def BitCastPtr : Opcode;

clang/test/AST/Interp/builtin-bit-cast.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,19 @@ constexpr int foo() {
7474
}
7575
static_assert(foo() == 1, "");
7676

77+
78+
namespace bitint {
79+
constexpr _BitInt(sizeof(int) * 8) BI = ~0;
80+
constexpr unsigned int I = __builtin_bit_cast(unsigned int, BI);
81+
static_assert(I == ~0u, "");
82+
83+
constexpr _BitInt(sizeof(int) * 8) IB = __builtin_bit_cast(_BitInt(sizeof(int) * 8), I); // ref-error {{must be initialized by a constant expression}} \
84+
// ref-note {{constexpr bit cast involving type '_BitInt(32)' is not yet supported}} \
85+
// ref-note {{declared here}}
86+
static_assert(IB == ~0u, ""); // ref-error {{not an integral constant expression}} \
87+
// ref-note {{initializer of 'IB' is not a constant expression}}
88+
}
89+
7790
namespace Ints {
7891
static_assert(round_trip<unsigned>((int)-1));
7992
static_assert(round_trip<unsigned>((int)0x12345678));

0 commit comments

Comments
 (0)