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, 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 ASTContext &) 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 163 IntegralAP<false> toUnsigned() const { 164 APInt Copy = V; 165 return IntegralAP<false>(Copy); 166 } 167 168 ComparisonCategoryResult compare(const IntegralAP &RHS) const { 169 assert(Signed == RHS.isSigned()); 170 assert(bitWidth() == RHS.bitWidth()); 171 if constexpr (Signed) { 172 if (V.slt(RHS.V)) 173 return ComparisonCategoryResult::Less; 174 if (V.sgt(RHS.V)) 175 return ComparisonCategoryResult::Greater; 176 return ComparisonCategoryResult::Equal; 177 } 178 179 assert(!Signed); 180 if (V.ult(RHS.V)) 181 return ComparisonCategoryResult::Less; 182 if (V.ugt(RHS.V)) 183 return ComparisonCategoryResult::Greater; 184 return ComparisonCategoryResult::Equal; 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> 321 IntegralAP<Signed> getSwappedBytes(IntegralAP<Signed> F) { 322 return F; 323 } 324 325 } // namespace interp 326 } // namespace clang 327 328 #endif 329