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_H 14 #define LLVM_CLANG_AST_INTERP_INTEGRAL_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 template <bool Signed> class IntegralAP; 33 34 // Helper structure to select the representation. 35 template <unsigned Bits, bool Signed> struct Repr; 36 template <> struct Repr<8, false> { 37 using Type = uint8_t; 38 }; 39 template <> struct Repr<16, false> { 40 using Type = uint16_t; 41 }; 42 template <> struct Repr<32, false> { 43 using Type = uint32_t; 44 }; 45 template <> struct Repr<64, false> { 46 using Type = uint64_t; 47 }; 48 template <> struct Repr<8, true> { 49 using Type = int8_t; 50 }; 51 template <> struct Repr<16, true> { 52 using Type = int16_t; 53 }; 54 template <> struct Repr<32, true> { 55 using Type = int32_t; 56 }; 57 template <> struct Repr<64, true> { 58 using Type = int64_t; 59 }; 60 61 /// Wrapper around numeric types. 62 /// 63 /// These wrappers are required to shared an interface between APSint and 64 /// builtin primitive numeral types, while optimising for storage and 65 /// allowing methods operating on primitive type to compile to fast code. 66 template <unsigned Bits, bool Signed> class Integral final { 67 private: 68 template <unsigned OtherBits, bool OtherSigned> friend class Integral; 69 70 // The primitive representing the integral. 71 using ReprT = typename Repr<Bits, Signed>::Type; 72 ReprT V; 73 static_assert(std::is_trivially_copyable_v<ReprT>); 74 75 /// Primitive representing limits. 76 static const auto Min = std::numeric_limits<ReprT>::min(); 77 static const auto Max = std::numeric_limits<ReprT>::max(); 78 79 /// Construct an integral from anything that is convertible to storage. 80 template <typename T> explicit Integral(T V) : V(V) {} 81 82 public: 83 using AsUnsigned = Integral<Bits, false>; 84 85 /// Zero-initializes an integral. 86 Integral() : V(0) {} 87 88 /// Constructs an integral from another integral. 89 template <unsigned SrcBits, bool SrcSign> 90 explicit Integral(Integral<SrcBits, SrcSign> V) : V(V.V) {} 91 92 /// Construct an integral from a value based on signedness. 93 explicit Integral(const APSInt &V) 94 : V(V.isSigned() ? V.getSExtValue() : V.getZExtValue()) {} 95 96 bool operator<(Integral RHS) const { return V < RHS.V; } 97 bool operator>(Integral RHS) const { return V > RHS.V; } 98 bool operator<=(Integral RHS) const { return V <= RHS.V; } 99 bool operator>=(Integral RHS) const { return V >= RHS.V; } 100 bool operator==(Integral RHS) const { return V == RHS.V; } 101 bool operator!=(Integral RHS) const { return V != RHS.V; } 102 bool operator>=(unsigned RHS) const { 103 return static_cast<unsigned>(V) >= RHS; 104 } 105 106 bool operator>(unsigned RHS) const { 107 return V >= 0 && static_cast<unsigned>(V) > RHS; 108 } 109 110 Integral operator-() const { return Integral(-V); } 111 Integral operator-(const Integral &Other) const { 112 return Integral(V - Other.V); 113 } 114 Integral operator~() const { return Integral(~V); } 115 116 template <unsigned DstBits, bool DstSign> 117 explicit operator Integral<DstBits, DstSign>() const { 118 return Integral<DstBits, DstSign>(V); 119 } 120 121 template <typename Ty, typename = std::enable_if_t<std::is_integral_v<Ty>>> 122 explicit operator Ty() const { 123 return V; 124 } 125 126 APSInt toAPSInt() const { 127 return APSInt(APInt(Bits, static_cast<uint64_t>(V), Signed), !Signed); 128 } 129 APSInt toAPSInt(unsigned BitWidth) const { 130 return APSInt(toAPInt(BitWidth), !Signed); 131 } 132 APInt toAPInt(unsigned BitWidth) const { 133 if constexpr (Signed) 134 return APInt(Bits, static_cast<uint64_t>(V), Signed) 135 .sextOrTrunc(BitWidth); 136 else 137 return APInt(Bits, static_cast<uint64_t>(V), Signed) 138 .zextOrTrunc(BitWidth); 139 } 140 APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); } 141 142 Integral<Bits, false> toUnsigned() const { 143 return Integral<Bits, false>(*this); 144 } 145 146 constexpr static unsigned bitWidth() { return Bits; } 147 148 bool isZero() const { return !V; } 149 150 bool isMin() const { return *this == min(bitWidth()); } 151 152 bool isMinusOne() const { return Signed && V == ReprT(-1); } 153 154 constexpr static bool isSigned() { return Signed; } 155 156 bool isNegative() const { return V < ReprT(0); } 157 bool isPositive() const { return !isNegative(); } 158 159 ComparisonCategoryResult compare(const Integral &RHS) const { 160 return Compare(V, RHS.V); 161 } 162 163 void bitcastToMemory(std::byte *Dest) const { 164 std::memcpy(Dest, &V, sizeof(V)); 165 } 166 167 static Integral bitcastFromMemory(const std::byte *Src, unsigned BitWidth) { 168 assert(BitWidth == sizeof(ReprT) * 8); 169 ReprT V; 170 171 std::memcpy(&V, Src, sizeof(ReprT)); 172 return Integral(V); 173 } 174 175 std::string toDiagnosticString(const ASTContext &Ctx) const { 176 std::string NameStr; 177 llvm::raw_string_ostream OS(NameStr); 178 OS << V; 179 return NameStr; 180 } 181 182 unsigned countLeadingZeros() const { 183 if constexpr (!Signed) 184 return llvm::countl_zero<ReprT>(V); 185 if (isPositive()) 186 return llvm::countl_zero<typename AsUnsigned::ReprT>( 187 static_cast<typename AsUnsigned::ReprT>(V)); 188 llvm_unreachable("Don't call countLeadingZeros() on negative values."); 189 } 190 191 Integral truncate(unsigned TruncBits) const { 192 assert(TruncBits >= 1); 193 if (TruncBits >= Bits) 194 return *this; 195 const ReprT BitMask = (ReprT(1) << ReprT(TruncBits)) - 1; 196 const ReprT SignBit = ReprT(1) << (TruncBits - 1); 197 const ReprT ExtMask = ~BitMask; 198 return Integral((V & BitMask) | (Signed && (V & SignBit) ? ExtMask : 0)); 199 } 200 201 void print(llvm::raw_ostream &OS) const { OS << V; } 202 203 static Integral min(unsigned NumBits) { return Integral(Min); } 204 static Integral max(unsigned NumBits) { return Integral(Max); } 205 206 template <typename ValT> static Integral from(ValT Value) { 207 if constexpr (std::is_integral<ValT>::value) 208 return Integral(Value); 209 else 210 return Integral::from(static_cast<Integral::ReprT>(Value)); 211 } 212 213 template <unsigned SrcBits, bool SrcSign> 214 static std::enable_if_t<SrcBits != 0, Integral> 215 from(Integral<SrcBits, SrcSign> Value) { 216 return Integral(Value.V); 217 } 218 219 static Integral zero(unsigned BitWidth = 0) { return from(0); } 220 221 template <typename T> static Integral from(T Value, unsigned NumBits) { 222 return Integral(Value); 223 } 224 225 static bool inRange(int64_t Value, unsigned NumBits) { 226 return CheckRange<ReprT, Min, Max>(Value); 227 } 228 229 static bool increment(Integral A, Integral *R) { 230 return add(A, Integral(ReprT(1)), A.bitWidth(), R); 231 } 232 233 static bool decrement(Integral A, Integral *R) { 234 return sub(A, Integral(ReprT(1)), A.bitWidth(), R); 235 } 236 237 static bool add(Integral A, Integral B, unsigned OpBits, Integral *R) { 238 return CheckAddUB(A.V, B.V, R->V); 239 } 240 241 static bool sub(Integral A, Integral B, unsigned OpBits, Integral *R) { 242 return CheckSubUB(A.V, B.V, R->V); 243 } 244 245 static bool mul(Integral A, Integral B, unsigned OpBits, Integral *R) { 246 return CheckMulUB(A.V, B.V, R->V); 247 } 248 249 static bool rem(Integral A, Integral B, unsigned OpBits, Integral *R) { 250 *R = Integral(A.V % B.V); 251 return false; 252 } 253 254 static bool div(Integral A, Integral B, unsigned OpBits, Integral *R) { 255 *R = Integral(A.V / B.V); 256 return false; 257 } 258 259 static bool bitAnd(Integral A, Integral B, unsigned OpBits, Integral *R) { 260 *R = Integral(A.V & B.V); 261 return false; 262 } 263 264 static bool bitOr(Integral A, Integral B, unsigned OpBits, Integral *R) { 265 *R = Integral(A.V | B.V); 266 return false; 267 } 268 269 static bool bitXor(Integral A, Integral B, unsigned OpBits, Integral *R) { 270 *R = Integral(A.V ^ B.V); 271 return false; 272 } 273 274 static bool neg(Integral A, Integral *R) { 275 if (Signed && A.isMin()) 276 return true; 277 278 *R = -A; 279 return false; 280 } 281 282 static bool comp(Integral A, Integral *R) { 283 *R = Integral(~A.V); 284 return false; 285 } 286 287 template <unsigned RHSBits, bool RHSSign> 288 static void shiftLeft(const Integral A, const Integral<RHSBits, RHSSign> B, 289 unsigned OpBits, Integral *R) { 290 *R = Integral::from(A.V << B.V, OpBits); 291 } 292 293 template <unsigned RHSBits, bool RHSSign> 294 static void shiftRight(const Integral A, const Integral<RHSBits, RHSSign> B, 295 unsigned OpBits, Integral *R) { 296 *R = Integral::from(A.V >> B.V, OpBits); 297 } 298 299 private: 300 template <typename T> static bool CheckAddUB(T A, T B, T &R) { 301 if constexpr (std::is_signed_v<T>) { 302 return llvm::AddOverflow<T>(A, B, R); 303 } else { 304 R = A + B; 305 return false; 306 } 307 } 308 309 template <typename T> static bool CheckSubUB(T A, T B, T &R) { 310 if constexpr (std::is_signed_v<T>) { 311 return llvm::SubOverflow<T>(A, B, R); 312 } else { 313 R = A - B; 314 return false; 315 } 316 } 317 318 template <typename T> static bool CheckMulUB(T A, T B, T &R) { 319 if constexpr (std::is_signed_v<T>) { 320 return llvm::MulOverflow<T>(A, B, R); 321 } else { 322 R = A * B; 323 return false; 324 } 325 } 326 template <typename T, T Min, T Max> static bool CheckRange(int64_t V) { 327 if constexpr (std::is_signed_v<T>) { 328 return Min <= V && V <= Max; 329 } else { 330 return V >= 0 && static_cast<uint64_t>(V) <= Max; 331 } 332 } 333 }; 334 335 template <unsigned Bits, bool Signed> 336 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Integral<Bits, Signed> I) { 337 I.print(OS); 338 return OS; 339 } 340 341 } // namespace interp 342 } // namespace clang 343 344 #endif 345