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 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: 56 using AsUnsigned = IntegralAP<false>; 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, 1024) {} 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 return IntegralAP(V.trunc(BitWidth)); 158 } 159 160 IntegralAP<false> toUnsigned() const { 161 APInt Copy = V; 162 return IntegralAP<false>(Copy); 163 } 164 165 ComparisonCategoryResult compare(const IntegralAP &RHS) const { 166 assert(Signed == RHS.isSigned()); 167 assert(bitWidth() == RHS.bitWidth()); 168 if constexpr (Signed) { 169 if (V.slt(RHS.V)) 170 return ComparisonCategoryResult::Less; 171 if (V.sgt(RHS.V)) 172 return ComparisonCategoryResult::Greater; 173 return ComparisonCategoryResult::Equal; 174 } 175 176 assert(!Signed); 177 if (V.ult(RHS.V)) 178 return ComparisonCategoryResult::Less; 179 if (V.ugt(RHS.V)) 180 return ComparisonCategoryResult::Greater; 181 return ComparisonCategoryResult::Equal; 182 } 183 184 static bool increment(IntegralAP A, IntegralAP *R) { 185 IntegralAP<Signed> One(1, A.bitWidth()); 186 return add(A, One, A.bitWidth() + 1, R); 187 } 188 189 static bool decrement(IntegralAP A, IntegralAP *R) { 190 IntegralAP<Signed> One(1, A.bitWidth()); 191 return sub(A, One, A.bitWidth() + 1, R); 192 } 193 194 static bool add(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { 195 return CheckAddSubMulUB<std::plus>(A, B, OpBits, R); 196 } 197 198 static bool sub(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { 199 return CheckAddSubMulUB<std::minus>(A, B, OpBits, R); 200 } 201 202 static bool mul(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { 203 return CheckAddSubMulUB<std::multiplies>(A, B, OpBits, R); 204 } 205 206 static bool rem(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { 207 if constexpr (Signed) 208 *R = IntegralAP(A.V.srem(B.V)); 209 else 210 *R = IntegralAP(A.V.urem(B.V)); 211 return false; 212 } 213 214 static bool div(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { 215 if constexpr (Signed) 216 *R = IntegralAP(A.V.sdiv(B.V)); 217 else 218 *R = IntegralAP(A.V.udiv(B.V)); 219 return false; 220 } 221 222 static bool bitAnd(IntegralAP A, IntegralAP B, unsigned OpBits, 223 IntegralAP *R) { 224 *R = IntegralAP(A.V & B.V); 225 return false; 226 } 227 228 static bool bitOr(IntegralAP A, IntegralAP B, unsigned OpBits, 229 IntegralAP *R) { 230 *R = IntegralAP(A.V | B.V); 231 return false; 232 } 233 234 static bool bitXor(IntegralAP A, IntegralAP B, unsigned OpBits, 235 IntegralAP *R) { 236 *R = IntegralAP(A.V ^ B.V); 237 return false; 238 } 239 240 static bool neg(const IntegralAP &A, IntegralAP *R) { 241 APInt AI = A.V; 242 AI.negate(); 243 *R = IntegralAP(AI); 244 return false; 245 } 246 247 static bool comp(IntegralAP A, IntegralAP *R) { 248 *R = IntegralAP(~A.V); 249 return false; 250 } 251 252 static void shiftLeft(const IntegralAP A, const IntegralAP B, unsigned OpBits, 253 IntegralAP *R) { 254 *R = IntegralAP(A.V.shl(B.V.getZExtValue())); 255 } 256 257 static void shiftRight(const IntegralAP A, const IntegralAP B, 258 unsigned OpBits, IntegralAP *R) { 259 unsigned ShiftAmount = B.V.getZExtValue(); 260 if constexpr (Signed) 261 *R = IntegralAP(A.V.ashr(ShiftAmount)); 262 else 263 *R = IntegralAP(A.V.lshr(ShiftAmount)); 264 } 265 266 private: 267 template <template <typename T> class Op> 268 static bool CheckAddSubMulUB(const IntegralAP &A, const IntegralAP &B, 269 unsigned BitWidth, IntegralAP *R) { 270 if constexpr (!Signed) { 271 R->V = Op<APInt>{}(A.V, B.V); 272 return false; 273 } 274 275 const APSInt &LHS = A.toAPSInt(); 276 const APSInt &RHS = B.toAPSInt(); 277 APSInt Value = Op<APSInt>{}(LHS.extend(BitWidth), RHS.extend(BitWidth)); 278 APSInt Result = Value.trunc(LHS.getBitWidth()); 279 R->V = Result; 280 281 return Result.extend(BitWidth) != Value; 282 } 283 }; 284 285 template <bool Signed> 286 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, 287 IntegralAP<Signed> I) { 288 I.print(OS); 289 return OS; 290 } 291 292 } // namespace interp 293 } // namespace clang 294 295 #endif 296