Skip to content

Commit 0d879e0

Browse files
committed
[clang][Interp] Add IntegralAP for arbitrary-precision integers
1 parent 38018ec commit 0d879e0

File tree

12 files changed

+343
-13
lines changed

12 files changed

+343
-13
lines changed

clang/lib/AST/Interp/ByteCodeExprGen.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,14 +171,17 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
171171
return this->discard(SubExpr);
172172
std::optional<PrimType> FromT = classify(SubExpr->getType());
173173
std::optional<PrimType> ToT = classify(CE->getType());
174+
174175
if (!FromT || !ToT)
175176
return false;
176177

177178
if (!this->visit(SubExpr))
178179
return false;
179180

180-
if (FromT == ToT)
181+
if (FromT == ToT) {
182+
assert(ToT != PT_IntAP && ToT != PT_IntAPS);
181183
return true;
184+
}
182185

183186
return this->emitCast(*FromT, *ToT, CE);
184187
}
@@ -1598,6 +1601,9 @@ bool ByteCodeExprGen<Emitter>::visitZeroInitializer(QualType QT,
15981601
return this->emitZeroSint64(E);
15991602
case PT_Uint64:
16001603
return this->emitZeroUint64(E);
1604+
case PT_IntAP:
1605+
case PT_IntAPS:
1606+
assert(false);
16011607
case PT_Ptr:
16021608
return this->emitNullPtr(E);
16031609
case PT_FnPtr:
@@ -1837,6 +1843,9 @@ bool ByteCodeExprGen<Emitter>::emitConst(T Value, PrimType Ty, const Expr *E) {
18371843
return this->emitConstSint64(Value, E);
18381844
case PT_Uint64:
18391845
return this->emitConstUint64(Value, E);
1846+
case PT_IntAP:
1847+
case PT_IntAPS:
1848+
assert(false);
18401849
case PT_Bool:
18411850
return this->emitConstBool(Value, E);
18421851
case PT_Ptr:

clang/lib/AST/Interp/Context.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,8 @@ std::optional<PrimType> Context::classify(QualType T) const {
103103
case 8:
104104
return PT_Sint8;
105105
default:
106-
return std::nullopt;
106+
return PT_IntAPS;
107+
// return std::nullopt;
107108
}
108109
}
109110

@@ -118,7 +119,8 @@ std::optional<PrimType> Context::classify(QualType T) const {
118119
case 8:
119120
return PT_Uint8;
120121
default:
121-
return std::nullopt;
122+
return PT_IntAP;
123+
// return std::nullopt;
122124
}
123125
}
124126

clang/lib/AST/Interp/Descriptor.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "Boolean.h"
1111
#include "Floating.h"
1212
#include "FunctionPointer.h"
13+
#include "IntegralAP.h"
1314
#include "Pointer.h"
1415
#include "PrimType.h"
1516
#include "Record.h"
@@ -182,6 +183,10 @@ static BlockCtorFn getCtorPrim(PrimType Type) {
182183
// constructor called.
183184
if (Type == PT_Float)
184185
return ctorTy<PrimConv<PT_Float>::T>;
186+
if (Type == PT_IntAP)
187+
return ctorTy<PrimConv<PT_IntAP>::T>;
188+
if (Type == PT_IntAPS)
189+
return ctorTy<PrimConv<PT_IntAPS>::T>;
185190

186191
COMPOSITE_TYPE_SWITCH(Type, return ctorTy<T>, return nullptr);
187192
}
@@ -191,6 +196,10 @@ static BlockDtorFn getDtorPrim(PrimType Type) {
191196
// destructor called, since they might allocate memory.
192197
if (Type == PT_Float)
193198
return dtorTy<PrimConv<PT_Float>::T>;
199+
if (Type == PT_IntAP)
200+
return dtorTy<PrimConv<PT_IntAP>::T>;
201+
if (Type == PT_IntAPS)
202+
return dtorTy<PrimConv<PT_IntAPS>::T>;
194203

195204
COMPOSITE_TYPE_SWITCH(Type, return dtorTy<T>, return nullptr);
196205
}

clang/lib/AST/Interp/EvalEmitter.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "EvalEmitter.h"
1010
#include "ByteCodeGenError.h"
1111
#include "Context.h"
12+
#include "IntegralAP.h"
1213
#include "Interp.h"
1314
#include "Opcode.h"
1415
#include "clang/AST/DeclCXX.h"

clang/lib/AST/Interp/Integral.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ namespace interp {
2929
using APInt = llvm::APInt;
3030
using APSInt = llvm::APSInt;
3131

32+
template <bool Signed> class IntegralAP;
33+
3234
// Helper structure to select the representation.
3335
template <unsigned Bits, bool Signed> struct Repr;
3436
template <> struct Repr<8, false> { using Type = uint8_t; };
@@ -61,6 +63,8 @@ template <unsigned Bits, bool Signed> class Integral final {
6163
template <typename T> explicit Integral(T V) : V(V) {}
6264

6365
public:
66+
using AsUnsigned = Integral<Bits, false>;
67+
6468
/// Zero-initializes an integral.
6569
Integral() : V(0) {}
6670

clang/lib/AST/Interp/IntegralAP.h

Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
//===--- Integral.h - Wrapper for numeric types for the VM ------*- 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+
//
9+
// Defines the VM types and helpers operating on types.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_CLANG_AST_INTERP_INTEGRAL_AP_H
14+
#define LLVM_CLANG_AST_INTERP_INTEGRAL_AP_H
15+
16+
#include "clang/AST/APValue.h"
17+
#include "clang/AST/ComparisonCategories.h"
18+
#include "llvm/ADT/APSInt.h"
19+
#include "llvm/Support/MathExtras.h"
20+
#include "llvm/Support/raw_ostream.h"
21+
#include <cstddef>
22+
#include <cstdint>
23+
24+
#include "Primitives.h"
25+
26+
namespace clang {
27+
namespace interp {
28+
29+
using APInt = llvm::APInt;
30+
using APSInt = llvm::APSInt;
31+
template <unsigned Bits, bool Signed> class Integral;
32+
class Boolean;
33+
34+
template <bool Signed> class IntegralAP final {
35+
public:
36+
APSInt V;
37+
38+
public:
39+
using AsUnsigned = IntegralAP<false>;
40+
41+
template <typename T>
42+
IntegralAP(T Value) : V(APInt(sizeof(T) * 8, Value, std::is_signed_v<T>)) {}
43+
44+
IntegralAP(APInt V) : V(V) {}
45+
IntegralAP(APSInt V) : V(V) {}
46+
IntegralAP(bool b) : V(APInt(8, b, Signed)) {}
47+
/// Bullshit value for initialized variables.
48+
IntegralAP() : V(APSInt::getMaxValue(1024, Signed)) {}
49+
50+
IntegralAP operator-() const { return IntegralAP(-V); }
51+
// bool operator <=> (const IntegralAP &RHS) const = default;
52+
bool operator>(IntegralAP RHS) const { return V > RHS.V; }
53+
bool operator>=(IntegralAP RHS) const { return V >= RHS.V; }
54+
bool operator<(IntegralAP RHS) const { return V < RHS.V; }
55+
bool operator<=(IntegralAP RHS) const { return V <= RHS.V; }
56+
57+
explicit operator bool() const { return !V.isZero(); }
58+
explicit operator int8_t() const { return V.getSExtValue(); }
59+
explicit operator uint8_t() const { return V.getZExtValue(); }
60+
explicit operator int16_t() const { return V.getSExtValue(); }
61+
explicit operator uint16_t() const { return V.getZExtValue(); }
62+
explicit operator int32_t() const { return V.getSExtValue(); }
63+
explicit operator uint32_t() const { return V.getZExtValue(); }
64+
explicit operator int64_t() const { return V.getSExtValue(); }
65+
explicit operator uint64_t() const { return V.getZExtValue(); }
66+
67+
template <typename T> static IntegralAP from(T Value, unsigned NumBits = 0) {
68+
assert(NumBits > 0);
69+
APSInt Copy = APSInt(APInt(NumBits, Value, Signed), !Signed);
70+
71+
return IntegralAP<Signed>(Copy);
72+
}
73+
74+
template <bool InputSigned>
75+
static IntegralAP from(IntegralAP<InputSigned> V, unsigned NumBits = 0) {
76+
if constexpr (Signed == InputSigned)
77+
return V;
78+
79+
APSInt Copy = V.V;
80+
Copy.setIsSigned(Signed);
81+
82+
return IntegralAP<Signed>(Copy);
83+
}
84+
85+
template <unsigned Bits, bool InputSigned>
86+
static IntegralAP from(Integral<Bits, InputSigned> I) {
87+
assert(InputSigned);
88+
/// TODO: Take bits parameter.
89+
APSInt Copy =
90+
APSInt(APInt(128, static_cast<int64_t>(I), InputSigned), !Signed);
91+
Copy.setIsSigned(Signed);
92+
93+
assert(Copy.isSigned() == Signed);
94+
return IntegralAP<Signed>(Copy);
95+
}
96+
static IntegralAP from(const Boolean &B) {
97+
assert(false);
98+
return IntegralAP::zero();
99+
}
100+
101+
static IntegralAP zero() {
102+
assert(false);
103+
return IntegralAP(0);
104+
}
105+
106+
static constexpr unsigned bitWidth() { return 128; }
107+
108+
APSInt toAPSInt(unsigned Bits = 0) const { return V; }
109+
APValue toAPValue() const { return APValue(V); }
110+
111+
bool isZero() const { return false; }
112+
bool isPositive() const { return true; }
113+
bool isNegative() const { return false; }
114+
bool isMin() const { return false; }
115+
bool isMax() const { return false; }
116+
static bool isSigned() { return Signed; }
117+
bool isMinusOne() const { return false; }
118+
119+
unsigned countLeadingZeros() const { return V.countl_zero(); }
120+
121+
void print(llvm::raw_ostream &OS) const { OS << V; }
122+
123+
IntegralAP truncate(unsigned bitWidth) const { return V; }
124+
IntegralAP<false> toUnsigned() const {
125+
APSInt Copy = V;
126+
Copy.setIsSigned(false);
127+
return IntegralAP<false>(Copy);
128+
}
129+
130+
ComparisonCategoryResult compare(const IntegralAP &RHS) const {
131+
return Compare(V, RHS.V);
132+
}
133+
134+
static bool increment(IntegralAP A, IntegralAP *R) {
135+
*R = IntegralAP(A.V - 1);
136+
return false;
137+
}
138+
139+
static bool decrement(IntegralAP A, IntegralAP *R) {
140+
*R = IntegralAP(A.V - 1);
141+
return false;
142+
}
143+
144+
static bool add(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
145+
/// TODO: Gotta check if the result fits into OpBits bits.
146+
return CheckAddUB(A, B, OpBits, R);
147+
}
148+
149+
static bool sub(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
150+
/// TODO: Gotta check if the result fits into OpBits bits.
151+
return CheckSubUB(A, B, R);
152+
}
153+
154+
static bool mul(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
155+
assert(false);
156+
// return CheckMulUB(A.V, B.V, R->V);
157+
return false;
158+
}
159+
160+
static bool rem(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
161+
assert(false);
162+
*R = IntegralAP(A.V % B.V);
163+
return false;
164+
}
165+
166+
static bool div(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
167+
assert(false);
168+
*R = IntegralAP(A.V / B.V);
169+
return false;
170+
}
171+
172+
static bool bitAnd(IntegralAP A, IntegralAP B, unsigned OpBits,
173+
IntegralAP *R) {
174+
assert(false);
175+
*R = IntegralAP(A.V & B.V);
176+
return false;
177+
}
178+
179+
static bool bitOr(IntegralAP A, IntegralAP B, unsigned OpBits,
180+
IntegralAP *R) {
181+
assert(false);
182+
*R = IntegralAP(A.V | B.V);
183+
return false;
184+
}
185+
186+
static bool bitXor(IntegralAP A, IntegralAP B, unsigned OpBits,
187+
IntegralAP *R) {
188+
assert(false);
189+
*R = IntegralAP(A.V ^ B.V);
190+
return false;
191+
}
192+
193+
static bool neg(const IntegralAP &A, IntegralAP *R) {
194+
APSInt AI = A.V;
195+
196+
AI.setIsSigned(Signed);
197+
*R = IntegralAP(AI);
198+
return false;
199+
}
200+
201+
static bool comp(IntegralAP A, IntegralAP *R) {
202+
assert(false);
203+
*R = IntegralAP(~A.V);
204+
return false;
205+
}
206+
207+
static void shiftLeft(const IntegralAP A, const IntegralAP B, unsigned OpBits,
208+
IntegralAP *R) {
209+
*R = IntegralAP(A.V << B.V.getZExtValue());
210+
}
211+
212+
static void shiftRight(const IntegralAP A, const IntegralAP B,
213+
unsigned OpBits, IntegralAP *R) {
214+
*R = IntegralAP(A.V >> B.V.getZExtValue());
215+
}
216+
217+
private:
218+
static bool CheckAddUB(const IntegralAP &A, const IntegralAP &B,
219+
unsigned BitWidth, IntegralAP *R) {
220+
if (!A.isSigned()) {
221+
R->V = A.V + B.V;
222+
return false;
223+
}
224+
225+
const APSInt &LHS = A.V;
226+
const APSInt &RHS = B.V;
227+
228+
APSInt Value(LHS.extend(BitWidth) + RHS.extend(BitWidth), false);
229+
APSInt Result = Value.trunc(LHS.getBitWidth());
230+
if (Result.extend(BitWidth) != Value)
231+
return true;
232+
233+
R->V = Result;
234+
return false;
235+
}
236+
static bool CheckSubUB(const IntegralAP &A, const IntegralAP &B,
237+
IntegralAP *R) {
238+
R->V = A.V - B.V;
239+
return false; // Success!
240+
}
241+
};
242+
243+
template <bool Signed>
244+
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
245+
IntegralAP<Signed> I) {
246+
I.print(OS);
247+
return OS;
248+
}
249+
250+
} // namespace interp
251+
} // namespace clang
252+
253+
#endif

0 commit comments

Comments
 (0)