clang 20.0.0git
Integral.h
Go to the documentation of this file.
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_H
14#define LLVM_CLANG_AST_INTERP_INTEGRAL_H
15
16#include "clang/AST/APValue.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
26namespace clang {
27namespace interp {
28
29using APInt = llvm::APInt;
30using APSInt = llvm::APSInt;
31
32template <bool Signed> class IntegralAP;
33
34// Helper structure to select the representation.
35template <unsigned Bits, bool Signed> struct Repr;
36template <> struct Repr<8, false> {
37 using Type = uint8_t;
38};
39template <> struct Repr<16, false> {
40 using Type = uint16_t;
41};
42template <> struct Repr<32, false> {
43 using Type = uint32_t;
44};
45template <> struct Repr<64, false> {
46 using Type = uint64_t;
47};
48template <> struct Repr<8, true> {
49 using Type = int8_t;
50};
51template <> struct Repr<16, true> {
52 using Type = int16_t;
53};
54template <> struct Repr<32, true> {
55 using Type = int32_t;
56};
57template <> struct Repr<64, true> {
58 using Type = int64_t;
59};
60
61/// Wrapper around numeric types.
62///
63/// These wrappers are required to shared an interface between APSint and
64/// builtin primitive numeral types, while optimising for storage and
65/// allowing methods operating on primitive type to compile to fast code.
66template <unsigned Bits, bool Signed> class Integral final {
67private:
68 template <unsigned OtherBits, bool OtherSigned> friend class Integral;
69
70 // The primitive representing the integral.
71 using ReprT = typename Repr<Bits, Signed>::Type;
72 ReprT V;
73 static_assert(std::is_trivially_copyable_v<ReprT>);
74
75 /// Primitive representing limits.
76 static const auto Min = std::numeric_limits<ReprT>::min();
77 static const auto Max = std::numeric_limits<ReprT>::max();
78
79 /// Construct an integral from anything that is convertible to storage.
80 template <typename T> explicit Integral(T V) : V(V) {}
81
82public:
84
85 /// Zero-initializes an integral.
86 Integral() : V(0) {}
87
88 /// Constructs an integral from another integral.
89 template <unsigned SrcBits, bool SrcSign>
91
92 /// Construct an integral from a value based on signedness.
93 explicit Integral(const APSInt &V)
94 : V(V.isSigned() ? V.getSExtValue() : V.getZExtValue()) {}
95
96 bool operator<(Integral RHS) const { return V < RHS.V; }
97 bool operator>(Integral RHS) const { return V > RHS.V; }
98 bool operator<=(Integral RHS) const { return V <= RHS.V; }
99 bool operator>=(Integral RHS) const { return V >= RHS.V; }
100 bool operator==(Integral RHS) const { return V == RHS.V; }
101 bool operator!=(Integral RHS) const { return V != RHS.V; }
102
103 bool operator>(unsigned RHS) const {
104 return V >= 0 && static_cast<unsigned>(V) > RHS;
105 }
106
107 Integral operator-() const { return Integral(-V); }
109 return Integral(V - Other.V);
110 }
111 Integral operator~() const { return Integral(~V); }
112
113 template <unsigned DstBits, bool DstSign>
114 explicit operator Integral<DstBits, DstSign>() const {
116 }
117
118 template <typename Ty, typename = std::enable_if_t<std::is_integral_v<Ty>>>
119 explicit operator Ty() const {
120 return V;
121 }
122
123 APSInt toAPSInt() const {
124 return APSInt(APInt(Bits, static_cast<uint64_t>(V), Signed), !Signed);
125 }
126 APSInt toAPSInt(unsigned BitWidth) const {
127 return APSInt(toAPInt(BitWidth), !Signed);
128 }
129 APInt toAPInt(unsigned BitWidth) const {
130 if constexpr (Signed)
131 return APInt(Bits, static_cast<uint64_t>(V), Signed)
132 .sextOrTrunc(BitWidth);
133 else
134 return APInt(Bits, static_cast<uint64_t>(V), Signed)
135 .zextOrTrunc(BitWidth);
136 }
137 APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); }
138
140 return Integral<Bits, false>(*this);
141 }
142
143 constexpr static unsigned bitWidth() { return Bits; }
144
145 bool isZero() const { return !V; }
146
147 bool isMin() const { return *this == min(bitWidth()); }
148
149 bool isMinusOne() const { return Signed && V == ReprT(-1); }
150
151 constexpr static bool isSigned() { return Signed; }
152
153 bool isNegative() const { return V < ReprT(0); }
154 bool isPositive() const { return !isNegative(); }
155
157 return Compare(V, RHS.V);
158 }
159
160 void bitcastToMemory(std::byte *Dest) const {
161 std::memcpy(Dest, &V, sizeof(V));
162 }
163
164 static Integral bitcastFromMemory(const std::byte *Src, unsigned BitWidth) {
165 assert(BitWidth == sizeof(ReprT) * 8);
166 ReprT V;
167
168 std::memcpy(&V, Src, sizeof(ReprT));
169 return Integral(V);
170 }
171
172 std::string toDiagnosticString(const ASTContext &Ctx) const {
173 std::string NameStr;
174 llvm::raw_string_ostream OS(NameStr);
175 OS << V;
176 return NameStr;
177 }
178
179 unsigned countLeadingZeros() const {
180 if constexpr (!Signed)
181 return llvm::countl_zero<ReprT>(V);
182 if (isPositive())
183 return llvm::countl_zero<typename AsUnsigned::ReprT>(
184 static_cast<typename AsUnsigned::ReprT>(V));
185 llvm_unreachable("Don't call countLeadingZeros() on negative values.");
186 }
187
188 Integral truncate(unsigned TruncBits) const {
189 assert(TruncBits >= 1);
190 if (TruncBits >= Bits)
191 return *this;
192 const ReprT BitMask = (ReprT(1) << ReprT(TruncBits)) - 1;
193 const ReprT SignBit = ReprT(1) << (TruncBits - 1);
194 const ReprT ExtMask = ~BitMask;
195 return Integral((V & BitMask) | (Signed && (V & SignBit) ? ExtMask : 0));
196 }
197
198 void print(llvm::raw_ostream &OS) const { OS << V; }
199
200 static Integral min(unsigned NumBits) { return Integral(Min); }
201 static Integral max(unsigned NumBits) { return Integral(Max); }
202
203 template <typename ValT> static Integral from(ValT Value) {
204 if constexpr (std::is_integral<ValT>::value)
205 return Integral(Value);
206 else
207 return Integral::from(static_cast<Integral::ReprT>(Value));
208 }
209
210 template <unsigned SrcBits, bool SrcSign>
211 static std::enable_if_t<SrcBits != 0, Integral>
213 return Integral(Value.V);
214 }
215
216 static Integral zero(unsigned BitWidth = 0) { return from(0); }
217
218 template <typename T> static Integral from(T Value, unsigned NumBits) {
219 return Integral(Value);
220 }
221
222 static bool inRange(int64_t Value, unsigned NumBits) {
223 return CheckRange<ReprT, Min, Max>(Value);
224 }
225
226 static bool increment(Integral A, Integral *R) {
227 return add(A, Integral(ReprT(1)), A.bitWidth(), R);
228 }
229
230 static bool decrement(Integral A, Integral *R) {
231 return sub(A, Integral(ReprT(1)), A.bitWidth(), R);
232 }
233
234 static bool add(Integral A, Integral B, unsigned OpBits, Integral *R) {
235 return CheckAddUB(A.V, B.V, R->V);
236 }
237
238 static bool sub(Integral A, Integral B, unsigned OpBits, Integral *R) {
239 return CheckSubUB(A.V, B.V, R->V);
240 }
241
242 static bool mul(Integral A, Integral B, unsigned OpBits, Integral *R) {
243 return CheckMulUB(A.V, B.V, R->V);
244 }
245
246 static bool rem(Integral A, Integral B, unsigned OpBits, Integral *R) {
247 *R = Integral(A.V % B.V);
248 return false;
249 }
250
251 static bool div(Integral A, Integral B, unsigned OpBits, Integral *R) {
252 *R = Integral(A.V / B.V);
253 return false;
254 }
255
256 static bool bitAnd(Integral A, Integral B, unsigned OpBits, Integral *R) {
257 *R = Integral(A.V & B.V);
258 return false;
259 }
260
261 static bool bitOr(Integral A, Integral B, unsigned OpBits, Integral *R) {
262 *R = Integral(A.V | B.V);
263 return false;
264 }
265
266 static bool bitXor(Integral A, Integral B, unsigned OpBits, Integral *R) {
267 *R = Integral(A.V ^ B.V);
268 return false;
269 }
270
271 static bool neg(Integral A, Integral *R) {
272 if (Signed && A.isMin())
273 return true;
274
275 *R = -A;
276 return false;
277 }
278
279 static bool comp(Integral A, Integral *R) {
280 *R = Integral(~A.V);
281 return false;
282 }
283
284 template <unsigned RHSBits, bool RHSSign>
285 static void shiftLeft(const Integral A, const Integral<RHSBits, RHSSign> B,
286 unsigned OpBits, Integral *R) {
287 *R = Integral::from(A.V << B.V, OpBits);
288 }
289
290 template <unsigned RHSBits, bool RHSSign>
291 static void shiftRight(const Integral A, const Integral<RHSBits, RHSSign> B,
292 unsigned OpBits, Integral *R) {
293 *R = Integral::from(A.V >> B.V, OpBits);
294 }
295
296private:
297 template <typename T> static bool CheckAddUB(T A, T B, T &R) {
298 if constexpr (std::is_signed_v<T>) {
299 return llvm::AddOverflow<T>(A, B, R);
300 } else {
301 R = A + B;
302 return false;
303 }
304 }
305
306 template <typename T> static bool CheckSubUB(T A, T B, T &R) {
307 if constexpr (std::is_signed_v<T>) {
308 return llvm::SubOverflow<T>(A, B, R);
309 } else {
310 R = A - B;
311 return false;
312 }
313 }
314
315 template <typename T> static bool CheckMulUB(T A, T B, T &R) {
316 if constexpr (std::is_signed_v<T>) {
317 return llvm::MulOverflow<T>(A, B, R);
318 } else {
319 R = A * B;
320 return false;
321 }
322 }
323 template <typename T, T Min, T Max> static bool CheckRange(int64_t V) {
324 if constexpr (std::is_signed_v<T>) {
325 return Min <= V && V <= Max;
326 } else {
327 return V >= 0 && static_cast<uint64_t>(V) <= Max;
328 }
329 }
330};
331
332template <unsigned Bits, bool Signed>
333llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Integral<Bits, Signed> I) {
334 I.print(OS);
335 return OS;
336}
337
338} // namespace interp
339} // namespace clang
340
341#endif
#define V(N, I)
Definition: ASTContext.h:3443
llvm::APSInt APSInt
Definition: Compiler.cpp:23
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
Definition: APValue.h:122
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:188
Wrapper around numeric types.
Definition: Integral.h:66
static Integral bitcastFromMemory(const std::byte *Src, unsigned BitWidth)
Definition: Integral.h:164
Integral< Bits, false > toUnsigned() const
Definition: Integral.h:139
bool isMinusOne() const
Definition: Integral.h:149
bool isNegative() const
Definition: Integral.h:153
static Integral max(unsigned NumBits)
Definition: Integral.h:201
Integral()
Zero-initializes an integral.
Definition: Integral.h:86
std::string toDiagnosticString(const ASTContext &Ctx) const
Definition: Integral.h:172
static bool mul(Integral A, Integral B, unsigned OpBits, Integral *R)
Definition: Integral.h:242
bool operator>=(Integral RHS) const
Definition: Integral.h:99
friend class Integral
Definition: Integral.h:68
void print(llvm::raw_ostream &OS) const
Definition: Integral.h:198
static bool sub(Integral A, Integral B, unsigned OpBits, Integral *R)
Definition: Integral.h:238
static constexpr unsigned bitWidth()
Definition: Integral.h:143
APSInt toAPSInt() const
Definition: Integral.h:123
static void shiftRight(const Integral A, const Integral< RHSBits, RHSSign > B, unsigned OpBits, Integral *R)
Definition: Integral.h:291
bool operator>(Integral RHS) const
Definition: Integral.h:97
bool operator>(unsigned RHS) const
Definition: Integral.h:103
Integral operator-(const Integral &Other) const
Definition: Integral.h:108
bool isZero() const
Definition: Integral.h:145
unsigned countLeadingZeros() const
Definition: Integral.h:179
Integral operator~() const
Definition: Integral.h:111
Integral truncate(unsigned TruncBits) const
Definition: Integral.h:188
bool operator<(Integral RHS) const
Definition: Integral.h:96
static Integral zero(unsigned BitWidth=0)
Definition: Integral.h:216
ComparisonCategoryResult compare(const Integral &RHS) const
Definition: Integral.h:156
static Integral from(ValT Value)
Definition: Integral.h:203
bool isMin() const
Definition: Integral.h:147
static bool neg(Integral A, Integral *R)
Definition: Integral.h:271
bool operator!=(Integral RHS) const
Definition: Integral.h:101
APValue toAPValue(const ASTContext &) const
Definition: Integral.h:137
APSInt toAPSInt(unsigned BitWidth) const
Definition: Integral.h:126
static bool decrement(Integral A, Integral *R)
Definition: Integral.h:230
static bool comp(Integral A, Integral *R)
Definition: Integral.h:279
Integral(Integral< SrcBits, SrcSign > V)
Constructs an integral from another integral.
Definition: Integral.h:90
static Integral from(T Value, unsigned NumBits)
Definition: Integral.h:218
bool operator<=(Integral RHS) const
Definition: Integral.h:98
static bool div(Integral A, Integral B, unsigned OpBits, Integral *R)
Definition: Integral.h:251
static bool inRange(int64_t Value, unsigned NumBits)
Definition: Integral.h:222
static bool bitXor(Integral A, Integral B, unsigned OpBits, Integral *R)
Definition: Integral.h:266
static bool rem(Integral A, Integral B, unsigned OpBits, Integral *R)
Definition: Integral.h:246
bool operator==(Integral RHS) const
Definition: Integral.h:100
Integral(const APSInt &V)
Construct an integral from a value based on signedness.
Definition: Integral.h:93
static Integral min(unsigned NumBits)
Definition: Integral.h:200
static constexpr bool isSigned()
Definition: Integral.h:151
APInt toAPInt(unsigned BitWidth) const
Definition: Integral.h:129
static void shiftLeft(const Integral A, const Integral< RHSBits, RHSSign > B, unsigned OpBits, Integral *R)
Definition: Integral.h:285
static bool bitOr(Integral A, Integral B, unsigned OpBits, Integral *R)
Definition: Integral.h:261
void bitcastToMemory(std::byte *Dest) const
Definition: Integral.h:160
Integral operator-() const
Definition: Integral.h:107
bool isPositive() const
Definition: Integral.h:154
static std::enable_if_t< SrcBits !=0, Integral > from(Integral< SrcBits, SrcSign > Value)
Definition: Integral.h:212
static bool add(Integral A, Integral B, unsigned OpBits, Integral *R)
Definition: Integral.h:234
static bool increment(Integral A, Integral *R)
Definition: Integral.h:226
static bool bitAnd(Integral A, Integral B, unsigned OpBits, Integral *R)
Definition: Integral.h:256
llvm::APInt APInt
Definition: FixedPoint.h:19
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const Boolean &B)
Definition: Boolean.h:160
ComparisonCategoryResult Compare(const T &X, const T &Y)
Helper to compare two comparable types.
Definition: Primitives.h:25
llvm::APSInt APSInt
Definition: FixedPoint.h:20
The JSON file list parser is used to communicate input to InstallAPI.
ComparisonCategoryResult
An enumeration representing the possible results of a three-way comparison.
const FunctionProtoType * T
@ Other
Other implicit parameter.
unsigned long uint64_t
#define true
Definition: stdbool.h:25
#define false
Definition: stdbool.h:26
A quantity in bits.
Definition: BitcastBuffer.h:24