clang  19.0.0git
IntegralAP.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_AP_H
14 #define LLVM_CLANG_AST_INTERP_INTEGRAL_AP_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 
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 
33 template <bool Signed> class IntegralAP final {
34 private:
35  friend IntegralAP<!Signed>;
36  APInt V;
37 
38  template <typename T, bool InputSigned>
39  static T truncateCast(const APInt &V) {
40  constexpr unsigned BitSize = sizeof(T) * 8;
41  if (BitSize >= V.getBitWidth()) {
42  APInt Extended;
43  if constexpr (InputSigned)
44  Extended = V.sext(BitSize);
45  else
46  Extended = V.zext(BitSize);
47  return std::is_signed_v<T> ? Extended.getSExtValue()
48  : Extended.getZExtValue();
49  }
50 
51  return std::is_signed_v<T> ? V.trunc(BitSize).getSExtValue()
52  : V.trunc(BitSize).getZExtValue();
53  }
54 
55 public:
57 
58  template <typename T>
59  IntegralAP(T Value, unsigned BitWidth)
60  : V(APInt(BitWidth, static_cast<uint64_t>(Value), Signed)) {}
61 
62  IntegralAP(APInt V) : V(V) {}
63  /// Arbitrary value for uninitialized variables.
64  IntegralAP() : IntegralAP(-1, 3) {}
65 
66  IntegralAP operator-() const { return IntegralAP(-V); }
67  IntegralAP operator-(const IntegralAP &Other) const {
68  return IntegralAP(V - Other.V);
69  }
70  bool operator>(const IntegralAP &RHS) const {
71  if constexpr (Signed)
72  return V.ugt(RHS.V);
73  return V.sgt(RHS.V);
74  }
75  bool operator>=(IntegralAP RHS) const {
76  if constexpr (Signed)
77  return V.uge(RHS.V);
78  return V.sge(RHS.V);
79  }
80  bool operator<(IntegralAP RHS) const {
81  if constexpr (Signed)
82  return V.slt(RHS.V);
83  return V.slt(RHS.V);
84  }
85  bool operator<=(IntegralAP RHS) const {
86  if constexpr (Signed)
87  return V.ult(RHS.V);
88  return V.ult(RHS.V);
89  }
90 
91  template <typename Ty, typename = std::enable_if_t<std::is_integral_v<Ty>>>
92  explicit operator Ty() const {
93  return truncateCast<Ty, Signed>(V);
94  }
95 
96  template <typename T> static IntegralAP from(T Value, unsigned NumBits = 0) {
97  assert(NumBits > 0);
98  APInt Copy = APInt(NumBits, static_cast<uint64_t>(Value), Signed);
99 
100  return IntegralAP<Signed>(Copy);
101  }
102 
103  template <bool InputSigned>
104  static IntegralAP from(IntegralAP<InputSigned> V, unsigned NumBits = 0) {
105  if (NumBits == 0)
106  NumBits = V.bitWidth();
107 
108  if constexpr (InputSigned)
109  return IntegralAP<Signed>(V.V.sextOrTrunc(NumBits));
110  return IntegralAP<Signed>(V.V.zextOrTrunc(NumBits));
111  }
112 
113  template <unsigned Bits, bool InputSigned>
114  static IntegralAP from(Integral<Bits, InputSigned> I, unsigned BitWidth) {
115  APInt Copy = APInt(BitWidth, static_cast<uint64_t>(I), InputSigned);
116 
117  return IntegralAP<Signed>(Copy);
118  }
119 
120  static IntegralAP zero(int32_t BitWidth) {
121  APInt V = APInt(BitWidth, 0LL, Signed);
122  return IntegralAP(V);
123  }
124 
125  constexpr unsigned bitWidth() const { return V.getBitWidth(); }
126 
127  APSInt toAPSInt(unsigned Bits = 0) const {
128  if (Bits == 0)
129  Bits = bitWidth();
130 
131  if constexpr (Signed)
132  return APSInt(V.sext(Bits), !Signed);
133  else
134  return APSInt(V.zext(Bits), !Signed);
135  }
136  APValue toAPValue() const { return APValue(toAPSInt()); }
137 
138  bool isZero() const { return V.isZero(); }
139  bool isPositive() const { return V.isNonNegative(); }
140  bool isNegative() const { return !V.isNonNegative(); }
141  bool isMin() const { return V.isMinValue(); }
142  bool isMax() const { return V.isMaxValue(); }
143  static constexpr bool isSigned() { return Signed; }
144  bool isMinusOne() const { return Signed && V == -1; }
145 
146  unsigned countLeadingZeros() const { return V.countl_zero(); }
147 
148  void print(llvm::raw_ostream &OS) const { OS << V; }
149  std::string toDiagnosticString(const ASTContext &Ctx) const {
150  std::string NameStr;
151  llvm::raw_string_ostream OS(NameStr);
152  print(OS);
153  return NameStr;
154  }
155 
156  IntegralAP truncate(unsigned BitWidth) const {
157  if constexpr (Signed)
158  return IntegralAP(V.trunc(BitWidth).sextOrTrunc(this->bitWidth()));
159  else
160  return IntegralAP(V.trunc(BitWidth).zextOrTrunc(this->bitWidth()));
161  }
162 
164  APInt Copy = V;
165  return IntegralAP<false>(Copy);
166  }
167 
169  assert(Signed == RHS.isSigned());
170  assert(bitWidth() == RHS.bitWidth());
171  if constexpr (Signed) {
172  if (V.slt(RHS.V))
174  if (V.sgt(RHS.V))
177  }
178 
179  assert(!Signed);
180  if (V.ult(RHS.V))
182  if (V.ugt(RHS.V))
185  }
186 
187  static bool increment(IntegralAP A, IntegralAP *R) {
188  IntegralAP<Signed> One(1, A.bitWidth());
189  return add(A, One, A.bitWidth() + 1, R);
190  }
191 
192  static bool decrement(IntegralAP A, IntegralAP *R) {
193  IntegralAP<Signed> One(1, A.bitWidth());
194  return sub(A, One, A.bitWidth() + 1, R);
195  }
196 
197  static bool add(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
198  return CheckAddSubMulUB<std::plus>(A, B, OpBits, R);
199  }
200 
201  static bool sub(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
202  return CheckAddSubMulUB<std::minus>(A, B, OpBits, R);
203  }
204 
205  static bool mul(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
206  return CheckAddSubMulUB<std::multiplies>(A, B, OpBits, R);
207  }
208 
209  static bool rem(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
210  if constexpr (Signed)
211  *R = IntegralAP(A.V.srem(B.V));
212  else
213  *R = IntegralAP(A.V.urem(B.V));
214  return false;
215  }
216 
217  static bool div(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
218  if constexpr (Signed)
219  *R = IntegralAP(A.V.sdiv(B.V));
220  else
221  *R = IntegralAP(A.V.udiv(B.V));
222  return false;
223  }
224 
225  static bool bitAnd(IntegralAP A, IntegralAP B, unsigned OpBits,
226  IntegralAP *R) {
227  *R = IntegralAP(A.V & B.V);
228  return false;
229  }
230 
231  static bool bitOr(IntegralAP A, IntegralAP B, unsigned OpBits,
232  IntegralAP *R) {
233  *R = IntegralAP(A.V | B.V);
234  return false;
235  }
236 
237  static bool bitXor(IntegralAP A, IntegralAP B, unsigned OpBits,
238  IntegralAP *R) {
239  *R = IntegralAP(A.V ^ B.V);
240  return false;
241  }
242 
243  static bool neg(const IntegralAP &A, IntegralAP *R) {
244  APInt AI = A.V;
245  AI.negate();
246  *R = IntegralAP(AI);
247  return false;
248  }
249 
250  static bool comp(IntegralAP A, IntegralAP *R) {
251  *R = IntegralAP(~A.V);
252  return false;
253  }
254 
255  static void shiftLeft(const IntegralAP A, const IntegralAP B, unsigned OpBits,
256  IntegralAP *R) {
257  *R = IntegralAP(A.V.shl(B.V.getZExtValue()));
258  }
259 
260  static void shiftRight(const IntegralAP A, const IntegralAP B,
261  unsigned OpBits, IntegralAP *R) {
262  unsigned ShiftAmount = B.V.getZExtValue();
263  if constexpr (Signed)
264  *R = IntegralAP(A.V.ashr(ShiftAmount));
265  else
266  *R = IntegralAP(A.V.lshr(ShiftAmount));
267  }
268 
269  // === Serialization support ===
270  size_t bytesToSerialize() const {
271  // 4 bytes for the BitWidth followed by N bytes for the actual APInt.
272  return sizeof(uint32_t) + (V.getBitWidth() / CHAR_BIT);
273  }
274 
275  void serialize(std::byte *Buff) const {
276  assert(V.getBitWidth() < std::numeric_limits<uint8_t>::max());
277  uint32_t BitWidth = V.getBitWidth();
278 
279  std::memcpy(Buff, &BitWidth, sizeof(uint32_t));
280  llvm::StoreIntToMemory(V, (uint8_t *)(Buff + sizeof(uint32_t)),
281  BitWidth / CHAR_BIT);
282  }
283 
284  static IntegralAP<Signed> deserialize(const std::byte *Buff) {
285  uint32_t BitWidth;
286  std::memcpy(&BitWidth, Buff, sizeof(uint32_t));
287  IntegralAP<Signed> Val(APInt(BitWidth, 0ull, !Signed));
288 
289  llvm::LoadIntFromMemory(Val.V, (const uint8_t *)Buff + sizeof(uint32_t),
290  BitWidth / CHAR_BIT);
291  return Val;
292  }
293 
294 private:
295  template <template <typename T> class Op>
296  static bool CheckAddSubMulUB(const IntegralAP &A, const IntegralAP &B,
297  unsigned BitWidth, IntegralAP *R) {
298  if constexpr (!Signed) {
299  R->V = Op<APInt>{}(A.V, B.V);
300  return false;
301  }
302 
303  const APSInt &LHS = A.toAPSInt();
304  const APSInt &RHS = B.toAPSInt();
305  APSInt Value = Op<APSInt>{}(LHS.extend(BitWidth), RHS.extend(BitWidth));
306  APSInt Result = Value.trunc(LHS.getBitWidth());
307  R->V = Result;
308 
309  return Result.extend(BitWidth) != Value;
310  }
311 };
312 
313 template <bool Signed>
314 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
315  IntegralAP<Signed> I) {
316  I.print(OS);
317  return OS;
318 }
319 
320 template <bool Signed>
322  return F;
323 }
324 
325 } // namespace interp
326 } // namespace clang
327 
328 #endif
#define V(N, I)
Definition: ASTContext.h:3299
llvm::APSInt APSInt
__DEVICE__ void * memcpy(void *__a, const void *__b, size_t __c)
__DEVICE__ int max(int __a, int __b)
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:185
void print(llvm::raw_ostream &OS) const
Definition: IntegralAP.h:148
static constexpr bool isSigned()
Definition: IntegralAP.h:143
static void shiftLeft(const IntegralAP A, const IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition: IntegralAP.h:255
static IntegralAP zero(int32_t BitWidth)
Definition: IntegralAP.h:120
bool operator<=(IntegralAP RHS) const
Definition: IntegralAP.h:85
static IntegralAP from(IntegralAP< InputSigned > V, unsigned NumBits=0)
Definition: IntegralAP.h:104
static bool rem(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition: IntegralAP.h:209
void serialize(std::byte *Buff) const
Definition: IntegralAP.h:275
static IntegralAP< Signed > deserialize(const std::byte *Buff)
Definition: IntegralAP.h:284
static bool decrement(IntegralAP A, IntegralAP *R)
Definition: IntegralAP.h:192
static bool increment(IntegralAP A, IntegralAP *R)
Definition: IntegralAP.h:187
static bool bitOr(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition: IntegralAP.h:231
static void shiftRight(const IntegralAP A, const IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition: IntegralAP.h:260
IntegralAP operator-(const IntegralAP &Other) const
Definition: IntegralAP.h:67
bool operator>(const IntegralAP &RHS) const
Definition: IntegralAP.h:70
std::string toDiagnosticString(const ASTContext &Ctx) const
Definition: IntegralAP.h:149
IntegralAP(T Value, unsigned BitWidth)
Definition: IntegralAP.h:59
APSInt toAPSInt(unsigned Bits=0) const
Definition: IntegralAP.h:127
IntegralAP< false > toUnsigned() const
Definition: IntegralAP.h:163
static IntegralAP from(T Value, unsigned NumBits=0)
Definition: IntegralAP.h:96
ComparisonCategoryResult compare(const IntegralAP &RHS) const
Definition: IntegralAP.h:168
IntegralAP truncate(unsigned BitWidth) const
Definition: IntegralAP.h:156
APValue toAPValue() const
Definition: IntegralAP.h:136
constexpr unsigned bitWidth() const
Definition: IntegralAP.h:125
static bool add(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition: IntegralAP.h:197
static bool bitXor(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition: IntegralAP.h:237
IntegralAP operator-() const
Definition: IntegralAP.h:66
size_t bytesToSerialize() const
Definition: IntegralAP.h:270
static bool div(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition: IntegralAP.h:217
static bool sub(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition: IntegralAP.h:201
static bool mul(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition: IntegralAP.h:205
bool operator>=(IntegralAP RHS) const
Definition: IntegralAP.h:75
unsigned countLeadingZeros() const
Definition: IntegralAP.h:146
static bool comp(IntegralAP A, IntegralAP *R)
Definition: IntegralAP.h:250
bool operator<(IntegralAP RHS) const
Definition: IntegralAP.h:80
static IntegralAP from(Integral< Bits, InputSigned > I, unsigned BitWidth)
Definition: IntegralAP.h:114
IntegralAP()
Arbitrary value for uninitialized variables.
Definition: IntegralAP.h:64
static bool bitAnd(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R)
Definition: IntegralAP.h:225
static bool neg(const IntegralAP &A, IntegralAP *R)
Definition: IntegralAP.h:243
Wrapper around numeric types.
Definition: Integral.h:50
#define CHAR_BIT
Definition: limits.h:71
llvm::APInt APInt
Definition: Integral.h:29
Floating getSwappedBytes(Floating F)
Definition: Floating.cpp:19
llvm::APSInt APSInt
Definition: Floating.h:24
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const Boolean &B)
Definition: Boolean.h:156
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