1 //===--- Integral.h - Wrapper for numeric types for the VM ------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // Defines the VM types and helpers operating on types.
11 //===----------------------------------------------------------------------===//
13 #ifndef LLVM_CLANG_AST_INTERP_INTEGRAL_AP_H
14 #define LLVM_CLANG_AST_INTERP_INTEGRAL_AP_H
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"
24 #include "Primitives.h"
29 using APInt
= llvm::APInt
;
30 using APSInt
= llvm::APSInt
;
31 template <unsigned Bits
, bool Signed
> class Integral
;
33 template <bool Signed
> class IntegralAP final
{
35 friend IntegralAP
<!Signed
>;
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()) {
43 if constexpr (InputSigned
)
44 Extended
= V
.sext(BitSize
);
46 Extended
= V
.zext(BitSize
);
47 return std::is_signed_v
<T
> ? Extended
.getSExtValue()
48 : Extended
.getZExtValue();
51 return std::is_signed_v
<T
> ? V
.trunc(BitSize
).getSExtValue()
52 : V
.trunc(BitSize
).getZExtValue();
56 using AsUnsigned
= IntegralAP
<false>;
59 IntegralAP(T Value
, unsigned BitWidth
)
60 : V(APInt(BitWidth
, static_cast<uint64_t>(Value
), Signed
)) {}
62 IntegralAP(APInt V
) : V(V
) {}
63 /// Arbitrary value for uninitialized variables.
64 IntegralAP() : IntegralAP(-1, 1024) {}
66 IntegralAP
operator-() const { return IntegralAP(-V
); }
67 IntegralAP
operator-(const IntegralAP
&Other
) const {
68 return IntegralAP(V
- Other
.V
);
70 bool operator>(const IntegralAP
&RHS
) const {
75 bool operator>=(IntegralAP RHS
) const {
80 bool operator<(IntegralAP RHS
) const {
85 bool operator<=(IntegralAP RHS
) const {
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
);
96 template <typename T
> static IntegralAP
from(T Value
, unsigned NumBits
= 0) {
98 APInt Copy
= APInt(NumBits
, static_cast<uint64_t>(Value
), Signed
);
100 return IntegralAP
<Signed
>(Copy
);
103 template <bool InputSigned
>
104 static IntegralAP
from(IntegralAP
<InputSigned
> V
, unsigned NumBits
= 0) {
105 return IntegralAP
<Signed
>(V
.V
);
108 template <unsigned Bits
, bool InputSigned
>
109 static IntegralAP
from(Integral
<Bits
, InputSigned
> I
, unsigned BitWidth
) {
110 APInt Copy
= APInt(BitWidth
, static_cast<uint64_t>(I
), InputSigned
);
112 return IntegralAP
<Signed
>(Copy
);
115 static IntegralAP
zero(int32_t BitWidth
) {
116 APInt V
= APInt(BitWidth
, 0LL, Signed
);
117 return IntegralAP(V
);
120 constexpr unsigned bitWidth() const { return V
.getBitWidth(); }
122 APSInt
toAPSInt(unsigned Bits
= 0) const { return APSInt(V
, Signed
); }
123 APValue
toAPValue() const { return APValue(APSInt(V
, Signed
)); }
125 bool isZero() const { return V
.isZero(); }
126 bool isPositive() const { return V
.isNonNegative(); }
127 bool isNegative() const { return !V
.isNonNegative(); }
128 bool isMin() const { return V
.isMinValue(); }
129 bool isMax() const { return V
.isMaxValue(); }
130 static constexpr bool isSigned() { return Signed
; }
131 bool isMinusOne() const { return Signed
&& V
== -1; }
133 unsigned countLeadingZeros() const { return V
.countl_zero(); }
135 void print(llvm::raw_ostream
&OS
) const { OS
<< V
; }
136 std::string
toDiagnosticString(const ASTContext
&Ctx
) const {
138 llvm::raw_string_ostream
OS(NameStr
);
143 IntegralAP
truncate(unsigned bitWidth
) const {
148 IntegralAP
<false> toUnsigned() const {
150 return IntegralAP
<false>(Copy
);
153 ComparisonCategoryResult
compare(const IntegralAP
&RHS
) const {
154 assert(Signed
== RHS
.isSigned());
155 assert(bitWidth() == RHS
.bitWidth());
156 if constexpr (Signed
) {
158 return ComparisonCategoryResult::Less
;
160 return ComparisonCategoryResult::Greater
;
161 return ComparisonCategoryResult::Equal
;
166 return ComparisonCategoryResult::Less
;
168 return ComparisonCategoryResult::Greater
;
169 return ComparisonCategoryResult::Equal
;
172 static bool increment(IntegralAP A
, IntegralAP
*R
) {
175 *R
= IntegralAP(A
.V
- 1);
179 static bool decrement(IntegralAP A
, IntegralAP
*R
) {
182 *R
= IntegralAP(A
.V
- 1);
186 static bool add(IntegralAP A
, IntegralAP B
, unsigned OpBits
, IntegralAP
*R
) {
187 return CheckAddUB(A
, B
, OpBits
, R
);
190 static bool sub(IntegralAP A
, IntegralAP B
, unsigned OpBits
, IntegralAP
*R
) {
191 /// FIXME: Gotta check if the result fits into OpBits bits.
192 return CheckSubUB(A
, B
, R
);
195 static bool mul(IntegralAP A
, IntegralAP B
, unsigned OpBits
, IntegralAP
*R
) {
201 static bool rem(IntegralAP A
, IntegralAP B
, unsigned OpBits
, IntegralAP
*R
) {
207 static bool div(IntegralAP A
, IntegralAP B
, unsigned OpBits
, IntegralAP
*R
) {
213 static bool bitAnd(IntegralAP A
, IntegralAP B
, unsigned OpBits
,
220 static bool bitOr(IntegralAP A
, IntegralAP B
, unsigned OpBits
,
226 static bool bitXor(IntegralAP A
, IntegralAP B
, unsigned OpBits
,
233 static bool neg(const IntegralAP
&A
, IntegralAP
*R
) {
240 static bool comp(IntegralAP A
, IntegralAP
*R
) {
241 *R
= IntegralAP(~A
.V
);
245 static void shiftLeft(const IntegralAP A
, const IntegralAP B
, unsigned OpBits
,
247 *R
= IntegralAP(A
.V
.shl(B
.V
.getZExtValue()));
250 static void shiftRight(const IntegralAP A
, const IntegralAP B
,
251 unsigned OpBits
, IntegralAP
*R
) {
252 *R
= IntegralAP(A
.V
.ashr(B
.V
.getZExtValue()));
256 static bool CheckAddUB(const IntegralAP
&A
, const IntegralAP
&B
,
257 unsigned BitWidth
, IntegralAP
*R
) {
263 const APSInt
&LHS
= APSInt(A
.V
, A
.isSigned());
264 const APSInt
&RHS
= APSInt(B
.V
, B
.isSigned());
266 APSInt
Value(LHS
.extend(BitWidth
) + RHS
.extend(BitWidth
), false);
267 APSInt Result
= Value
.trunc(LHS
.getBitWidth());
268 if (Result
.extend(BitWidth
) != Value
)
274 static bool CheckSubUB(const IntegralAP
&A
, const IntegralAP
&B
,
277 return false; // Success!
281 template <bool Signed
>
282 inline llvm::raw_ostream
&operator<<(llvm::raw_ostream
&OS
,
283 IntegralAP
<Signed
> I
) {
288 } // namespace interp