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 32 /// If an IntegralAP is constructed from Memory, it DOES NOT OWN THAT MEMORY. 33 /// It will NOT copy the memory (unless, of course, copy() is called) and it 34 /// won't alllocate anything. The allocation should happen via InterpState or 35 /// Program. 36 template <bool Signed> class IntegralAP final { 37 public: 38 union { 39 uint64_t *Memory = nullptr; 40 uint64_t Val; 41 }; 42 uint32_t BitWidth = 0; 43 friend IntegralAP<!Signed>; 44 45 template <typename T, bool InputSigned> 46 static T truncateCast(const APInt &V) { 47 constexpr unsigned BitSize = sizeof(T) * 8; 48 if (BitSize >= V.getBitWidth()) { 49 APInt Extended; 50 if constexpr (InputSigned) 51 Extended = V.sext(BitSize); 52 else 53 Extended = V.zext(BitSize); 54 return std::is_signed_v<T> ? Extended.getSExtValue() 55 : Extended.getZExtValue(); 56 } 57 58 return std::is_signed_v<T> ? V.trunc(BitSize).getSExtValue() 59 : V.trunc(BitSize).getZExtValue(); 60 } 61 62 APInt getValue() const { 63 if (singleWord()) 64 return APInt(BitWidth, Val, Signed); 65 unsigned NumWords = llvm::APInt::getNumWords(BitWidth); 66 return llvm::APInt(BitWidth, NumWords, Memory); 67 } 68 69 public: 70 using AsUnsigned = IntegralAP<false>; 71 72 void take(uint64_t *NewMemory) { 73 assert(!singleWord()); 74 std::memcpy(NewMemory, Memory, numWords() * sizeof(uint64_t)); 75 Memory = NewMemory; 76 } 77 78 void copy(const APInt &V) { 79 assert(BitWidth == V.getBitWidth()); 80 assert(numWords() == V.getNumWords()); 81 82 if (V.isSingleWord()) { 83 if constexpr (Signed) 84 Val = V.getSExtValue(); 85 else 86 Val = V.getZExtValue(); 87 return; 88 } 89 assert(Memory); 90 std::memcpy(Memory, V.getRawData(), V.getNumWords() * sizeof(uint64_t)); 91 } 92 93 IntegralAP() = default; 94 /// Zeroed, single-word IntegralAP of the given bitwidth. 95 IntegralAP(unsigned BitWidth) : Val(0), BitWidth(BitWidth) { 96 assert(singleWord()); 97 } 98 IntegralAP(uint64_t *Memory, unsigned BitWidth) 99 : Memory(Memory), BitWidth(BitWidth) {} 100 IntegralAP(const APInt &V) : BitWidth(V.getBitWidth()) { 101 if (V.isSingleWord()) { 102 Val = Signed ? V.getSExtValue() : V.getZExtValue(); 103 } else { 104 Memory = const_cast<uint64_t *>(V.getRawData()); 105 } 106 } 107 108 IntegralAP operator-() const { return IntegralAP(-getValue()); } 109 bool operator>(const IntegralAP &RHS) const { 110 if constexpr (Signed) 111 return getValue().sgt(RHS.getValue()); 112 return getValue().ugt(RHS.getValue()); 113 } 114 bool operator>=(unsigned RHS) const { 115 if constexpr (Signed) 116 return getValue().sge(RHS); 117 return getValue().uge(RHS); 118 } 119 bool operator<(IntegralAP RHS) const { 120 if constexpr (Signed) 121 return getValue().slt(RHS.getValue()); 122 return getValue().ult(RHS.getValue()); 123 } 124 125 template <typename Ty, typename = std::enable_if_t<std::is_integral_v<Ty>>> 126 explicit operator Ty() const { 127 return truncateCast<Ty, Signed>(getValue()); 128 } 129 130 template <typename T> static IntegralAP from(T Value, unsigned NumBits = 0) { 131 if (NumBits == 0) 132 NumBits = sizeof(T) * 8; 133 assert(NumBits > 0); 134 assert(APInt::getNumWords(NumBits) == 1); 135 APInt Copy = APInt(NumBits, static_cast<uint64_t>(Value), Signed); 136 return IntegralAP<Signed>(Copy); 137 } 138 139 constexpr uint32_t bitWidth() const { return BitWidth; } 140 constexpr unsigned numWords() const { return APInt::getNumWords(BitWidth); } 141 constexpr bool singleWord() const { return numWords() == 1; } 142 143 APSInt toAPSInt(unsigned Bits = 0) const { 144 if (Bits == 0) 145 Bits = bitWidth(); 146 147 APInt V = getValue(); 148 if constexpr (Signed) 149 return APSInt(getValue().sext(Bits), !Signed); 150 else 151 return APSInt(getValue().zext(Bits), !Signed); 152 } 153 APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); } 154 155 bool isZero() const { return getValue().isZero(); } 156 bool isPositive() const { 157 if constexpr (Signed) 158 return getValue().isNonNegative(); 159 return true; 160 } 161 bool isNegative() const { 162 if constexpr (Signed) 163 return !getValue().isNonNegative(); 164 return false; 165 } 166 bool isMin() const { 167 if constexpr (Signed) 168 return getValue().isMinSignedValue(); 169 return getValue().isMinValue(); 170 } 171 bool isMax() const { 172 if constexpr (Signed) 173 return getValue().isMaxSignedValue(); 174 return getValue().isMaxValue(); 175 } 176 static constexpr bool isSigned() { return Signed; } 177 bool isMinusOne() const { return Signed && getValue().isAllOnes(); } 178 179 unsigned countLeadingZeros() const { return getValue().countl_zero(); } 180 181 void print(llvm::raw_ostream &OS) const { getValue().print(OS, Signed); } 182 std::string toDiagnosticString(const ASTContext &Ctx) const { 183 std::string NameStr; 184 llvm::raw_string_ostream OS(NameStr); 185 print(OS); 186 return NameStr; 187 } 188 189 IntegralAP truncate(unsigned BitWidth) const { 190 if constexpr (Signed) 191 return IntegralAP( 192 getValue().trunc(BitWidth).sextOrTrunc(this->bitWidth())); 193 else 194 return IntegralAP( 195 getValue().trunc(BitWidth).zextOrTrunc(this->bitWidth())); 196 } 197 198 IntegralAP<false> toUnsigned() const { 199 return IntegralAP<false>(Memory, BitWidth); 200 } 201 202 void bitcastToMemory(std::byte *Dest) const { 203 llvm::StoreIntToMemory(getValue(), (uint8_t *)Dest, bitWidth() / 8); 204 } 205 206 static void bitcastFromMemory(const std::byte *Src, unsigned BitWidth, 207 IntegralAP *Result) { 208 APInt V(BitWidth, static_cast<uint64_t>(0), Signed); 209 llvm::LoadIntFromMemory(V, (const uint8_t *)Src, BitWidth / 8); 210 Result->copy(V); 211 } 212 213 ComparisonCategoryResult compare(const IntegralAP &RHS) const { 214 assert(Signed == RHS.isSigned()); 215 assert(bitWidth() == RHS.bitWidth()); 216 APInt V1 = getValue(); 217 APInt V2 = RHS.getValue(); 218 if constexpr (Signed) { 219 if (V1.slt(V2)) 220 return ComparisonCategoryResult::Less; 221 if (V1.sgt(V2)) 222 return ComparisonCategoryResult::Greater; 223 return ComparisonCategoryResult::Equal; 224 } 225 226 assert(!Signed); 227 if (V1.ult(V2)) 228 return ComparisonCategoryResult::Less; 229 if (V1.ugt(V2)) 230 return ComparisonCategoryResult::Greater; 231 return ComparisonCategoryResult::Equal; 232 } 233 234 static bool increment(IntegralAP A, IntegralAP *R) { 235 APSInt One(APInt(A.bitWidth(), 1ull, Signed), !Signed); 236 return add(A, IntegralAP<Signed>(One), A.bitWidth() + 1, R); 237 } 238 239 static bool decrement(IntegralAP A, IntegralAP *R) { 240 APSInt One(APInt(A.bitWidth(), 1ull, Signed), !Signed); 241 return sub(A, IntegralAP<Signed>(One), A.bitWidth() + 1, R); 242 } 243 244 static bool add(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { 245 return CheckAddSubMulUB<std::plus>(A, B, OpBits, R); 246 } 247 248 static bool sub(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { 249 return CheckAddSubMulUB<std::minus>(A, B, OpBits, R); 250 } 251 252 static bool mul(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { 253 return CheckAddSubMulUB<std::multiplies>(A, B, OpBits, R); 254 } 255 256 static bool rem(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { 257 if constexpr (Signed) 258 R->copy(A.getValue().srem(B.getValue())); 259 else 260 R->copy(A.getValue().urem(B.getValue())); 261 return false; 262 } 263 264 static bool div(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { 265 if constexpr (Signed) 266 R->copy(A.getValue().sdiv(B.getValue())); 267 else 268 R->copy(A.getValue().udiv(B.getValue())); 269 return false; 270 } 271 272 static bool bitAnd(IntegralAP A, IntegralAP B, unsigned OpBits, 273 IntegralAP *R) { 274 R->copy(A.getValue() & B.getValue()); 275 return false; 276 } 277 278 static bool bitOr(IntegralAP A, IntegralAP B, unsigned OpBits, 279 IntegralAP *R) { 280 R->copy(A.getValue() | B.getValue()); 281 return false; 282 } 283 284 static bool bitXor(IntegralAP A, IntegralAP B, unsigned OpBits, 285 IntegralAP *R) { 286 R->copy(A.getValue() ^ B.getValue()); 287 return false; 288 } 289 290 static bool neg(const IntegralAP &A, IntegralAP *R) { 291 APInt AI = A.getValue(); 292 AI.negate(); 293 R->copy(AI); 294 return false; 295 } 296 297 static bool comp(IntegralAP A, IntegralAP *R) { 298 R->copy(~A.getValue()); 299 return false; 300 } 301 302 static void shiftLeft(const IntegralAP A, const IntegralAP B, unsigned OpBits, 303 IntegralAP *R) { 304 *R = IntegralAP(A.getValue().shl(B.getValue().getZExtValue())); 305 } 306 307 static void shiftRight(const IntegralAP A, const IntegralAP B, 308 unsigned OpBits, IntegralAP *R) { 309 unsigned ShiftAmount = B.getValue().getZExtValue(); 310 if constexpr (Signed) 311 R->copy(A.getValue().ashr(ShiftAmount)); 312 else 313 R->copy(A.getValue().lshr(ShiftAmount)); 314 } 315 316 // === Serialization support === 317 size_t bytesToSerialize() const { 318 assert(BitWidth != 0); 319 return sizeof(uint32_t) + (numWords() * sizeof(uint64_t)); 320 } 321 322 void serialize(std::byte *Buff) const { 323 std::memcpy(Buff, &BitWidth, sizeof(uint32_t)); 324 if (singleWord()) 325 std::memcpy(Buff + sizeof(uint32_t), &Val, sizeof(uint64_t)); 326 else { 327 std::memcpy(Buff + sizeof(uint32_t), Memory, 328 numWords() * sizeof(uint64_t)); 329 } 330 } 331 332 static uint32_t deserializeSize(const std::byte *Buff) { 333 return *reinterpret_cast<const uint32_t *>(Buff); 334 } 335 336 static void deserialize(const std::byte *Buff, IntegralAP<Signed> *Result) { 337 uint32_t BitWidth = Result->BitWidth; 338 assert(BitWidth != 0); 339 unsigned NumWords = llvm::APInt::getNumWords(BitWidth); 340 341 if (NumWords == 1) 342 std::memcpy(&Result->Val, Buff + sizeof(uint32_t), sizeof(uint64_t)); 343 else { 344 assert(Result->Memory); 345 std::memcpy(Result->Memory, Buff + sizeof(uint32_t), 346 NumWords * sizeof(uint64_t)); 347 } 348 } 349 350 private: 351 template <template <typename T> class Op> 352 static bool CheckAddSubMulUB(const IntegralAP &A, const IntegralAP &B, 353 unsigned BitWidth, IntegralAP *R) { 354 if constexpr (!Signed) { 355 R->copy(Op<APInt>{}(A.getValue(), B.getValue())); 356 return false; 357 } 358 359 const APSInt &LHS = A.toAPSInt(); 360 const APSInt &RHS = B.toAPSInt(); 361 APSInt Value = Op<APSInt>{}(LHS.extend(BitWidth), RHS.extend(BitWidth)); 362 APSInt Result = Value.trunc(LHS.getBitWidth()); 363 R->copy(Result); 364 365 return Result.extend(BitWidth) != Value; 366 } 367 }; 368 369 template <bool Signed> 370 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, 371 IntegralAP<Signed> I) { 372 I.print(OS); 373 return OS; 374 } 375 376 template <bool Signed> 377 IntegralAP<Signed> getSwappedBytes(IntegralAP<Signed> F) { 378 return F; 379 } 380 381 } // namespace interp 382 } // namespace clang 383 384 #endif 385