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(Signed ? -1 : 7, 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 return IntegralAP<Signed>(I.toAPInt(BitWidth)); 116 } 117 118 static IntegralAP zero(int32_t BitWidth) { 119 APInt V = APInt(BitWidth, 0LL, Signed); 120 return IntegralAP(V); 121 } 122 123 constexpr unsigned bitWidth() const { return V.getBitWidth(); } 124 125 APSInt toAPSInt(unsigned Bits = 0) const { 126 if (Bits == 0) 127 Bits = bitWidth(); 128 129 if constexpr (Signed) 130 return APSInt(V.sext(Bits), !Signed); 131 else 132 return APSInt(V.zext(Bits), !Signed); 133 } 134 APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); } 135 136 bool isZero() const { return V.isZero(); } 137 bool isPositive() const { 138 if constexpr (Signed) 139 return V.isNonNegative(); 140 return true; 141 } 142 bool isNegative() const { 143 if constexpr (Signed) 144 return !V.isNonNegative(); 145 return false; 146 } 147 bool isMin() const { return V.isMinValue(); } 148 bool isMax() const { return V.isMaxValue(); } 149 static constexpr bool isSigned() { return Signed; } 150 bool isMinusOne() const { return Signed && V == -1; } 151 152 unsigned countLeadingZeros() const { return V.countl_zero(); } 153 154 void print(llvm::raw_ostream &OS) const { V.print(OS, Signed);} 155 std::string toDiagnosticString(const ASTContext &Ctx) const { 156 std::string NameStr; 157 llvm::raw_string_ostream OS(NameStr); 158 print(OS); 159 return NameStr; 160 } 161 162 IntegralAP truncate(unsigned BitWidth) const { 163 if constexpr (Signed) 164 return IntegralAP(V.trunc(BitWidth).sextOrTrunc(this->bitWidth())); 165 else 166 return IntegralAP(V.trunc(BitWidth).zextOrTrunc(this->bitWidth())); 167 } 168 169 IntegralAP<false> toUnsigned() const { 170 APInt Copy = V; 171 return IntegralAP<false>(Copy); 172 } 173 174 void bitcastToMemory(std::byte *Dest) const { 175 llvm::StoreIntToMemory(V, (uint8_t *)Dest, bitWidth() / 8); 176 } 177 178 static IntegralAP bitcastFromMemory(const std::byte *Src, unsigned BitWidth) { 179 APInt V(BitWidth, static_cast<uint64_t>(0), Signed); 180 llvm::LoadIntFromMemory(V, (const uint8_t *)Src, BitWidth / 8); 181 return IntegralAP(V); 182 } 183 184 ComparisonCategoryResult compare(const IntegralAP &RHS) const { 185 assert(Signed == RHS.isSigned()); 186 assert(bitWidth() == RHS.bitWidth()); 187 if constexpr (Signed) { 188 if (V.slt(RHS.V)) 189 return ComparisonCategoryResult::Less; 190 if (V.sgt(RHS.V)) 191 return ComparisonCategoryResult::Greater; 192 return ComparisonCategoryResult::Equal; 193 } 194 195 assert(!Signed); 196 if (V.ult(RHS.V)) 197 return ComparisonCategoryResult::Less; 198 if (V.ugt(RHS.V)) 199 return ComparisonCategoryResult::Greater; 200 return ComparisonCategoryResult::Equal; 201 } 202 203 static bool increment(IntegralAP A, IntegralAP *R) { 204 IntegralAP<Signed> One(1, A.bitWidth()); 205 return add(A, One, A.bitWidth() + 1, R); 206 } 207 208 static bool decrement(IntegralAP A, IntegralAP *R) { 209 IntegralAP<Signed> One(1, A.bitWidth()); 210 return sub(A, One, A.bitWidth() + 1, R); 211 } 212 213 static bool add(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { 214 return CheckAddSubMulUB<std::plus>(A, B, OpBits, R); 215 } 216 217 static bool sub(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { 218 return CheckAddSubMulUB<std::minus>(A, B, OpBits, R); 219 } 220 221 static bool mul(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { 222 return CheckAddSubMulUB<std::multiplies>(A, B, OpBits, R); 223 } 224 225 static bool rem(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { 226 if constexpr (Signed) 227 *R = IntegralAP(A.V.srem(B.V)); 228 else 229 *R = IntegralAP(A.V.urem(B.V)); 230 return false; 231 } 232 233 static bool div(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { 234 if constexpr (Signed) 235 *R = IntegralAP(A.V.sdiv(B.V)); 236 else 237 *R = IntegralAP(A.V.udiv(B.V)); 238 return false; 239 } 240 241 static bool bitAnd(IntegralAP A, IntegralAP B, unsigned OpBits, 242 IntegralAP *R) { 243 *R = IntegralAP(A.V & B.V); 244 return false; 245 } 246 247 static bool bitOr(IntegralAP A, IntegralAP B, unsigned OpBits, 248 IntegralAP *R) { 249 *R = IntegralAP(A.V | B.V); 250 return false; 251 } 252 253 static bool bitXor(IntegralAP A, IntegralAP B, unsigned OpBits, 254 IntegralAP *R) { 255 *R = IntegralAP(A.V ^ B.V); 256 return false; 257 } 258 259 static bool neg(const IntegralAP &A, IntegralAP *R) { 260 APInt AI = A.V; 261 AI.negate(); 262 *R = IntegralAP(AI); 263 return false; 264 } 265 266 static bool comp(IntegralAP A, IntegralAP *R) { 267 *R = IntegralAP(~A.V); 268 return false; 269 } 270 271 static void shiftLeft(const IntegralAP A, const IntegralAP B, unsigned OpBits, 272 IntegralAP *R) { 273 *R = IntegralAP(A.V.shl(B.V.getZExtValue())); 274 } 275 276 static void shiftRight(const IntegralAP A, const IntegralAP B, 277 unsigned OpBits, IntegralAP *R) { 278 unsigned ShiftAmount = B.V.getZExtValue(); 279 if constexpr (Signed) 280 *R = IntegralAP(A.V.ashr(ShiftAmount)); 281 else 282 *R = IntegralAP(A.V.lshr(ShiftAmount)); 283 } 284 285 // === Serialization support === 286 size_t bytesToSerialize() const { 287 // 4 bytes for the BitWidth followed by N bytes for the actual APInt. 288 return sizeof(uint32_t) + (V.getBitWidth() / CHAR_BIT); 289 } 290 291 void serialize(std::byte *Buff) const { 292 assert(V.getBitWidth() < std::numeric_limits<uint8_t>::max()); 293 uint32_t BitWidth = V.getBitWidth(); 294 295 std::memcpy(Buff, &BitWidth, sizeof(uint32_t)); 296 llvm::StoreIntToMemory(V, (uint8_t *)(Buff + sizeof(uint32_t)), 297 BitWidth / CHAR_BIT); 298 } 299 300 static IntegralAP<Signed> deserialize(const std::byte *Buff) { 301 uint32_t BitWidth; 302 std::memcpy(&BitWidth, Buff, sizeof(uint32_t)); 303 IntegralAP<Signed> Val(APInt(BitWidth, 0ull, !Signed)); 304 305 llvm::LoadIntFromMemory(Val.V, (const uint8_t *)Buff + sizeof(uint32_t), 306 BitWidth / CHAR_BIT); 307 return Val; 308 } 309 310 private: 311 template <template <typename T> class Op> 312 static bool CheckAddSubMulUB(const IntegralAP &A, const IntegralAP &B, 313 unsigned BitWidth, IntegralAP *R) { 314 if constexpr (!Signed) { 315 R->V = Op<APInt>{}(A.V, B.V); 316 return false; 317 } 318 319 const APSInt &LHS = A.toAPSInt(); 320 const APSInt &RHS = B.toAPSInt(); 321 APSInt Value = Op<APSInt>{}(LHS.extend(BitWidth), RHS.extend(BitWidth)); 322 APSInt Result = Value.trunc(LHS.getBitWidth()); 323 R->V = Result; 324 325 return Result.extend(BitWidth) != Value; 326 } 327 }; 328 329 template <bool Signed> 330 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, 331 IntegralAP<Signed> I) { 332 I.print(OS); 333 return OS; 334 } 335 336 template <bool Signed> 337 IntegralAP<Signed> getSwappedBytes(IntegralAP<Signed> F) { 338 return F; 339 } 340 341 } // namespace interp 342 } // namespace clang 343 344 #endif 345