Skip to content

Commit 13b8fa2

Browse files
committed
[clang][Interp] Support arbitrary precision constants
Add (de)serialization support for them, like we do for Floating values.
1 parent c61686e commit 13b8fa2

File tree

7 files changed

+123
-4
lines changed

7 files changed

+123
-4
lines changed

clang/lib/AST/Interp/ByteCodeEmitter.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "ByteCodeGenError.h"
1111
#include "Context.h"
1212
#include "Floating.h"
13+
#include "IntegralAP.h"
1314
#include "Opcode.h"
1415
#include "Program.h"
1516
#include "clang/AST/ASTLambda.h"
@@ -228,6 +229,42 @@ void emit(Program &P, std::vector<std::byte> &Code, const Floating &Val,
228229
Val.serialize(Code.data() + ValPos);
229230
}
230231

232+
template <>
233+
void emit(Program &P, std::vector<std::byte> &Code,
234+
const IntegralAP<false> &Val, bool &Success) {
235+
size_t Size = Val.bytesToSerialize();
236+
237+
if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
238+
Success = false;
239+
return;
240+
}
241+
242+
// Access must be aligned!
243+
size_t ValPos = align(Code.size());
244+
Size = align(Size);
245+
assert(aligned(ValPos + Size));
246+
Code.resize(ValPos + Size);
247+
Val.serialize(Code.data() + ValPos);
248+
}
249+
250+
template <>
251+
void emit(Program &P, std::vector<std::byte> &Code, const IntegralAP<true> &Val,
252+
bool &Success) {
253+
size_t Size = Val.bytesToSerialize();
254+
255+
if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
256+
Success = false;
257+
return;
258+
}
259+
260+
// Access must be aligned!
261+
size_t ValPos = align(Code.size());
262+
Size = align(Size);
263+
assert(aligned(ValPos + Size));
264+
Code.resize(ValPos + Size);
265+
Val.serialize(Code.data() + ValPos);
266+
}
267+
231268
template <typename... Tys>
232269
bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) {
233270
bool Success = true;

clang/lib/AST/Interp/ByteCodeExprGen.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2191,15 +2191,13 @@ bool ByteCodeExprGen<Emitter>::emitConst(T Value, PrimType Ty, const Expr *E) {
21912191
return this->emitConstSint64(Value, E);
21922192
case PT_Uint64:
21932193
return this->emitConstUint64(Value, E);
2194-
case PT_IntAP:
2195-
case PT_IntAPS:
2196-
assert(false);
2197-
return false;
21982194
case PT_Bool:
21992195
return this->emitConstBool(Value, E);
22002196
case PT_Ptr:
22012197
case PT_FnPtr:
22022198
case PT_Float:
2199+
case PT_IntAP:
2200+
case PT_IntAPS:
22032201
llvm_unreachable("Invalid integral type");
22042202
break;
22052203
}
@@ -2215,6 +2213,11 @@ bool ByteCodeExprGen<Emitter>::emitConst(T Value, const Expr *E) {
22152213
template <class Emitter>
22162214
bool ByteCodeExprGen<Emitter>::emitConst(const APSInt &Value, PrimType Ty,
22172215
const Expr *E) {
2216+
if (Ty == PT_IntAPS)
2217+
return this->emitConstIntAPS(Value, E);
2218+
else if (Ty == PT_IntAP)
2219+
return this->emitConstIntAP(Value, E);
2220+
22182221
if (Value.isSigned())
22192222
return this->emitConst(Value.getSExtValue(), Ty, E);
22202223
return this->emitConst(Value.getZExtValue(), Ty, E);

clang/lib/AST/Interp/Disasm.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include "Floating.h"
1414
#include "Function.h"
15+
#include "IntegralAP.h"
1516
#include "Opcode.h"
1617
#include "PrimType.h"
1718
#include "Program.h"
@@ -37,6 +38,20 @@ template <> inline Floating ReadArg<Floating>(Program &P, CodePtr &OpPC) {
3738
return F;
3839
}
3940

41+
template <>
42+
inline IntegralAP<false> ReadArg<IntegralAP<false>>(Program &P, CodePtr &OpPC) {
43+
IntegralAP<false> I = IntegralAP<false>::deserialize(*OpPC);
44+
OpPC += align(I.bytesToSerialize());
45+
return I;
46+
}
47+
48+
template <>
49+
inline IntegralAP<true> ReadArg<IntegralAP<true>>(Program &P, CodePtr &OpPC) {
50+
IntegralAP<true> I = IntegralAP<true>::deserialize(*OpPC);
51+
OpPC += align(I.bytesToSerialize());
52+
return I;
53+
}
54+
4055
LLVM_DUMP_METHOD void Function::dump() const { dump(llvm::errs()); }
4156

4257
LLVM_DUMP_METHOD void Function::dump(llvm::raw_ostream &OS) const {

clang/lib/AST/Interp/IntegralAP.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,31 @@ template <bool Signed> class IntegralAP final {
263263
*R = IntegralAP(A.V.lshr(ShiftAmount));
264264
}
265265

266+
// === Serialization support ===
267+
size_t bytesToSerialize() const {
268+
// 4 bytes for the BitWidth followed by N bytes for the actual APInt.
269+
return sizeof(uint32_t) + (V.getBitWidth() / CHAR_BIT);
270+
}
271+
272+
void serialize(std::byte *Buff) const {
273+
assert(V.getBitWidth() < std::numeric_limits<uint8_t>::max());
274+
uint32_t BitWidth = V.getBitWidth();
275+
276+
std::memcpy(Buff, &BitWidth, sizeof(uint32_t));
277+
llvm::StoreIntToMemory(V, (uint8_t *)(Buff + sizeof(uint32_t)),
278+
BitWidth / CHAR_BIT);
279+
}
280+
281+
static IntegralAP<Signed> deserialize(const std::byte *Buff) {
282+
uint32_t BitWidth;
283+
std::memcpy(&BitWidth, Buff, sizeof(uint32_t));
284+
IntegralAP<Signed> Val(APInt(BitWidth, 0ull, !Signed));
285+
286+
llvm::LoadIntFromMemory(Val.V, (const uint8_t *)Buff + sizeof(uint32_t),
287+
BitWidth / CHAR_BIT);
288+
return Val;
289+
}
290+
266291
private:
267292
template <template <typename T> class Op>
268293
static bool CheckAddSubMulUB(const IntegralAP &A, const IntegralAP &B,
@@ -289,6 +314,11 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
289314
return OS;
290315
}
291316

317+
template <bool Signed>
318+
IntegralAP<Signed> getSwappedBytes(IntegralAP<Signed> F) {
319+
return F;
320+
}
321+
292322
} // namespace interp
293323
} // namespace clang
294324

clang/lib/AST/Interp/Interp.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2041,6 +2041,22 @@ template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) {
20412041
return F;
20422042
}
20432043

2044+
template <>
2045+
inline IntegralAP<false> ReadArg<IntegralAP<false>>(InterpState &S,
2046+
CodePtr &OpPC) {
2047+
IntegralAP<false> I = IntegralAP<false>::deserialize(*OpPC);
2048+
OpPC += align(I.bytesToSerialize());
2049+
return I;
2050+
}
2051+
2052+
template <>
2053+
inline IntegralAP<true> ReadArg<IntegralAP<true>>(InterpState &S,
2054+
CodePtr &OpPC) {
2055+
IntegralAP<true> I = IntegralAP<true>::deserialize(*OpPC);
2056+
OpPC += align(I.bytesToSerialize());
2057+
return I;
2058+
}
2059+
20442060
} // namespace interp
20452061
} // namespace clang
20462062

clang/lib/AST/Interp/Opcodes.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ def ArgUint32 : ArgType { let Name = "uint32_t"; }
4545
def ArgSint64 : ArgType { let Name = "int64_t"; }
4646
def ArgUint64 : ArgType { let Name = "uint64_t"; }
4747
def ArgFloat : ArgType { let Name = "Floating"; }
48+
def ArgIntAP : ArgType { let Name = "IntegralAP<false>"; }
49+
def ArgIntAPS : ArgType { let Name = "IntegralAP<true>"; }
4850
def ArgBool : ArgType { let Name = "bool"; }
4951

5052
def ArgFunction : ArgType { let Name = "const Function *"; }
@@ -244,6 +246,8 @@ def ConstUint32 : ConstOpcode<Uint32, ArgUint32>;
244246
def ConstSint64 : ConstOpcode<Sint64, ArgSint64>;
245247
def ConstUint64 : ConstOpcode<Uint64, ArgUint64>;
246248
def ConstFloat : ConstOpcode<Float, ArgFloat>;
249+
def constIntAP : ConstOpcode<IntAP, ArgIntAP>;
250+
def constIntAPS : ConstOpcode<IntAPS, ArgIntAPS>;
247251
def ConstBool : ConstOpcode<Bool, ArgBool>;
248252

249253
// [] -> [Integer]

clang/test/AST/Interp/intap.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,20 @@ namespace i128 {
154154
constexpr uint128_t ui128Zero{};
155155
static_assert(ui128Zero == 0, "");
156156

157+
158+
enum LargeEnum : signed __int128 {
159+
LV = (signed __int128)1 << 127,
160+
};
161+
162+
constexpr LargeEnum F = LV;
163+
static_assert(F == (signed __int128)1 << 127, "");
164+
constexpr LargeEnum getLargeEnum() {
165+
return LV;
166+
}
167+
static_assert(getLargeEnum() == (signed __int128)1 << 127, "");
168+
169+
170+
157171
#if __cplusplus >= 201402L
158172
template <typename T>
159173
constexpr T CastFrom(__int128_t A) {

0 commit comments

Comments
 (0)