Skip to content

Commit 5546a04

Browse files
SC llvm teamSC llvm team
authored andcommitted
Merged main:18461dc45483 into amd-gfx:2f63a363aacc
Local branch amd-gfx 2f63a36 Merged main:e7247f1010b5 into amd-gfx:b3bef5344f47 Remote branch main 18461dc [clang][Interp] Add IntegralAP for arbitrary-precision integers (llvm#65844)
2 parents 2f63a36 + 18461dc commit 5546a04

File tree

13 files changed

+392
-15
lines changed

13 files changed

+392
-15
lines changed

clang/lib/AST/Interp/ByteCodeExprGen.cpp

Lines changed: 12 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
}
@@ -1638,6 +1641,10 @@ bool ByteCodeExprGen<Emitter>::visitZeroInitializer(QualType QT,
16381641
return this->emitZeroSint64(E);
16391642
case PT_Uint64:
16401643
return this->emitZeroUint64(E);
1644+
case PT_IntAP:
1645+
case PT_IntAPS:
1646+
assert(false);
1647+
return false;
16411648
case PT_Ptr:
16421649
return this->emitNullPtr(E);
16431650
case PT_FnPtr:
@@ -1877,6 +1884,10 @@ bool ByteCodeExprGen<Emitter>::emitConst(T Value, PrimType Ty, const Expr *E) {
18771884
return this->emitConstSint64(Value, E);
18781885
case PT_Uint64:
18791886
return this->emitConstUint64(Value, E);
1887+
case PT_IntAP:
1888+
case PT_IntAPS:
1889+
assert(false);
1890+
return false;
18801891
case PT_Bool:
18811892
return this->emitConstBool(Value, E);
18821893
case PT_Ptr:

clang/lib/AST/Interp/Context.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ 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;
107107
}
108108
}
109109

@@ -118,7 +118,7 @@ std::optional<PrimType> Context::classify(QualType T) const {
118118
case 8:
119119
return PT_Uint8;
120120
default:
121-
return std::nullopt;
121+
return PT_IntAP;
122122
}
123123
}
124124

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: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
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+
/// Arbitrary value for uninitialized variables.
47+
IntegralAP() : V(APSInt::getMaxValue(1024, Signed)) {}
48+
49+
IntegralAP operator-() const { return IntegralAP(-V); }
50+
bool operator>(IntegralAP RHS) const { return V > RHS.V; }
51+
bool operator>=(IntegralAP RHS) const { return V >= RHS.V; }
52+
bool operator<(IntegralAP RHS) const { return V < RHS.V; }
53+
bool operator<=(IntegralAP RHS) const { return V <= RHS.V; }
54+
55+
explicit operator bool() const { return !V.isZero(); }
56+
explicit operator int8_t() const { return V.getSExtValue(); }
57+
explicit operator uint8_t() const { return V.getZExtValue(); }
58+
explicit operator int16_t() const { return V.getSExtValue(); }
59+
explicit operator uint16_t() const { return V.getZExtValue(); }
60+
explicit operator int32_t() const { return V.getSExtValue(); }
61+
explicit operator uint32_t() const { return V.getZExtValue(); }
62+
explicit operator int64_t() const { return V.getSExtValue(); }
63+
explicit operator uint64_t() const { return V.getZExtValue(); }
64+
65+
template <typename T> static IntegralAP from(T Value, unsigned NumBits = 0) {
66+
assert(NumBits > 0);
67+
APSInt Copy = APSInt(APInt(NumBits, Value, Signed), !Signed);
68+
69+
return IntegralAP<Signed>(Copy);
70+
}
71+
72+
template <bool InputSigned>
73+
static IntegralAP from(IntegralAP<InputSigned> V, unsigned NumBits = 0) {
74+
if constexpr (Signed == InputSigned)
75+
return V;
76+
77+
APSInt Copy = V.V;
78+
Copy.setIsSigned(Signed);
79+
80+
return IntegralAP<Signed>(Copy);
81+
}
82+
83+
template <unsigned Bits, bool InputSigned>
84+
static IntegralAP from(Integral<Bits, InputSigned> I) {
85+
// FIXME: Take bits parameter.
86+
APSInt Copy =
87+
APSInt(APInt(128, static_cast<int64_t>(I), InputSigned), !Signed);
88+
Copy.setIsSigned(Signed);
89+
90+
assert(Copy.isSigned() == Signed);
91+
return IntegralAP<Signed>(Copy);
92+
}
93+
static IntegralAP from(const Boolean &B) {
94+
assert(false);
95+
return IntegralAP::zero();
96+
}
97+
98+
static IntegralAP zero() {
99+
assert(false);
100+
return IntegralAP(0);
101+
}
102+
103+
// FIXME: This can't be static if the bitwidth depends on V.
104+
static constexpr unsigned bitWidth() { return 128; }
105+
106+
APSInt toAPSInt(unsigned Bits = 0) const { return V; }
107+
APValue toAPValue() const { return APValue(V); }
108+
109+
bool isZero() const { return V.isZero(); }
110+
bool isPositive() const { return V.isNonNegative(); }
111+
bool isNegative() const { return !V.isNonNegative(); }
112+
bool isMin() const { return V.isMinValue(); }
113+
bool isMax() const { return V.isMaxValue(); }
114+
static bool isSigned() { return Signed; }
115+
bool isMinusOne() const { return Signed && V == -1; }
116+
117+
unsigned countLeadingZeros() const { return V.countl_zero(); }
118+
119+
void print(llvm::raw_ostream &OS) const { OS << V; }
120+
std::string toDiagnosticString(const ASTContext &Ctx) const {
121+
std::string NameStr;
122+
llvm::raw_string_ostream OS(NameStr);
123+
print(OS);
124+
return NameStr;
125+
}
126+
127+
IntegralAP truncate(unsigned bitWidth) const {
128+
assert(false);
129+
return V;
130+
}
131+
132+
IntegralAP<false> toUnsigned() const {
133+
APSInt Copy = V;
134+
Copy.setIsSigned(false);
135+
return IntegralAP<false>(Copy);
136+
}
137+
138+
ComparisonCategoryResult compare(const IntegralAP &RHS) const {
139+
return Compare(V, RHS.V);
140+
}
141+
142+
static bool increment(IntegralAP A, IntegralAP *R) {
143+
assert(false);
144+
*R = IntegralAP(A.V + 1);
145+
return false;
146+
}
147+
148+
static bool decrement(IntegralAP A, IntegralAP *R) {
149+
assert(false);
150+
*R = IntegralAP(A.V - 1);
151+
return false;
152+
}
153+
154+
static bool add(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
155+
return CheckAddUB(A, B, OpBits, R);
156+
}
157+
158+
static bool sub(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
159+
/// FIXME: Gotta check if the result fits into OpBits bits.
160+
return CheckSubUB(A, B, R);
161+
}
162+
163+
static bool mul(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
164+
assert(false);
165+
// return CheckMulUB(A.V, B.V, R->V);
166+
return false;
167+
}
168+
169+
static bool rem(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
170+
assert(false);
171+
*R = IntegralAP(A.V % B.V);
172+
return false;
173+
}
174+
175+
static bool div(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
176+
assert(false);
177+
*R = IntegralAP(A.V / B.V);
178+
return false;
179+
}
180+
181+
static bool bitAnd(IntegralAP A, IntegralAP B, unsigned OpBits,
182+
IntegralAP *R) {
183+
assert(false);
184+
*R = IntegralAP(A.V & B.V);
185+
return false;
186+
}
187+
188+
static bool bitOr(IntegralAP A, IntegralAP B, unsigned OpBits,
189+
IntegralAP *R) {
190+
assert(false);
191+
*R = IntegralAP(A.V | B.V);
192+
return false;
193+
}
194+
195+
static bool bitXor(IntegralAP A, IntegralAP B, unsigned OpBits,
196+
IntegralAP *R) {
197+
assert(false);
198+
*R = IntegralAP(A.V ^ B.V);
199+
return false;
200+
}
201+
202+
static bool neg(const IntegralAP &A, IntegralAP *R) {
203+
APSInt AI = A.V;
204+
205+
AI.setIsSigned(Signed);
206+
*R = IntegralAP(AI);
207+
return false;
208+
}
209+
210+
static bool comp(IntegralAP A, IntegralAP *R) {
211+
assert(false);
212+
*R = IntegralAP(~A.V);
213+
return false;
214+
}
215+
216+
static void shiftLeft(const IntegralAP A, const IntegralAP B, unsigned OpBits,
217+
IntegralAP *R) {
218+
*R = IntegralAP(A.V << B.V.getZExtValue());
219+
}
220+
221+
static void shiftRight(const IntegralAP A, const IntegralAP B,
222+
unsigned OpBits, IntegralAP *R) {
223+
*R = IntegralAP(A.V >> B.V.getZExtValue());
224+
}
225+
226+
private:
227+
static bool CheckAddUB(const IntegralAP &A, const IntegralAP &B,
228+
unsigned BitWidth, IntegralAP *R) {
229+
if (!A.isSigned()) {
230+
R->V = A.V + B.V;
231+
return false;
232+
}
233+
234+
const APSInt &LHS = A.V;
235+
const APSInt &RHS = B.V;
236+
237+
APSInt Value(LHS.extend(BitWidth) + RHS.extend(BitWidth), false);
238+
APSInt Result = Value.trunc(LHS.getBitWidth());
239+
if (Result.extend(BitWidth) != Value)
240+
return true;
241+
242+
R->V = Result;
243+
return false;
244+
}
245+
static bool CheckSubUB(const IntegralAP &A, const IntegralAP &B,
246+
IntegralAP *R) {
247+
R->V = A.V - B.V;
248+
return false; // Success!
249+
}
250+
};
251+
252+
template <bool Signed>
253+
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
254+
IntegralAP<Signed> I) {
255+
I.print(OS);
256+
return OS;
257+
}
258+
259+
} // namespace interp
260+
} // namespace clang
261+
262+
#endif

0 commit comments

Comments
 (0)