1353942Sdim//===--- Integral.h - Wrapper for numeric types for the VM ------*- C++ -*-===// 2353942Sdim// 3353942Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353942Sdim// See https://llvm.org/LICENSE.txt for license information. 5353942Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6353942Sdim// 7353942Sdim//===----------------------------------------------------------------------===// 8353942Sdim// 9353942Sdim// Defines the VM types and helpers operating on types. 10353942Sdim// 11353942Sdim//===----------------------------------------------------------------------===// 12353942Sdim 13353942Sdim#ifndef LLVM_CLANG_AST_INTERP_INTEGRAL_H 14353942Sdim#define LLVM_CLANG_AST_INTERP_INTEGRAL_H 15353942Sdim 16353942Sdim#include "clang/AST/ComparisonCategories.h" 17353942Sdim#include "clang/AST/APValue.h" 18353942Sdim#include "llvm/ADT/APSInt.h" 19353942Sdim#include "llvm/Support/MathExtras.h" 20353942Sdim#include "llvm/Support/raw_ostream.h" 21353942Sdim#include <cstddef> 22353942Sdim#include <cstdint> 23353942Sdim 24353942Sdimnamespace clang { 25353942Sdimnamespace interp { 26353942Sdim 27353942Sdimusing APInt = llvm::APInt; 28353942Sdimusing APSInt = llvm::APSInt; 29353942Sdim 30353942Sdim/// Helper to compare two comparable types. 31353942Sdimtemplate <typename T> 32353942SdimComparisonCategoryResult Compare(const T &X, const T &Y) { 33353942Sdim if (X < Y) 34353942Sdim return ComparisonCategoryResult::Less; 35353942Sdim if (X > Y) 36353942Sdim return ComparisonCategoryResult::Greater; 37353942Sdim return ComparisonCategoryResult::Equal; 38353942Sdim} 39353942Sdim 40353942Sdim// Helper structure to select the representation. 41353942Sdimtemplate <unsigned Bits, bool Signed> struct Repr; 42353942Sdimtemplate <> struct Repr<8, false> { using Type = uint8_t; }; 43353942Sdimtemplate <> struct Repr<16, false> { using Type = uint16_t; }; 44353942Sdimtemplate <> struct Repr<32, false> { using Type = uint32_t; }; 45353942Sdimtemplate <> struct Repr<64, false> { using Type = uint64_t; }; 46353942Sdimtemplate <> struct Repr<8, true> { using Type = int8_t; }; 47353942Sdimtemplate <> struct Repr<16, true> { using Type = int16_t; }; 48353942Sdimtemplate <> struct Repr<32, true> { using Type = int32_t; }; 49353942Sdimtemplate <> struct Repr<64, true> { using Type = int64_t; }; 50353942Sdim 51353942Sdim/// Wrapper around numeric types. 52353942Sdim/// 53353942Sdim/// These wrappers are required to shared an interface between APSint and 54353942Sdim/// builtin primitive numeral types, while optimising for storage and 55353942Sdim/// allowing methods operating on primitive type to compile to fast code. 56353942Sdimtemplate <unsigned Bits, bool Signed> class Integral { 57353942Sdimprivate: 58353942Sdim template <unsigned OtherBits, bool OtherSigned> friend class Integral; 59353942Sdim 60353942Sdim // The primitive representing the integral. 61353942Sdim using T = typename Repr<Bits, Signed>::Type; 62353942Sdim T V; 63353942Sdim 64353942Sdim /// Primitive representing limits. 65353942Sdim static const auto Min = std::numeric_limits<T>::min(); 66353942Sdim static const auto Max = std::numeric_limits<T>::max(); 67353942Sdim 68353942Sdim /// Construct an integral from anything that is convertible to storage. 69353942Sdim template <typename T> explicit Integral(T V) : V(V) {} 70353942Sdim 71353942Sdimpublic: 72353942Sdim /// Zero-initializes an integral. 73353942Sdim Integral() : V(0) {} 74353942Sdim 75353942Sdim /// Constructs an integral from another integral. 76353942Sdim template <unsigned SrcBits, bool SrcSign> 77353942Sdim explicit Integral(Integral<SrcBits, SrcSign> V) : V(V.V) {} 78353942Sdim 79353942Sdim /// Construct an integral from a value based on signedness. 80353942Sdim explicit Integral(const APSInt &V) 81353942Sdim : V(V.isSigned() ? V.getSExtValue() : V.getZExtValue()) {} 82353942Sdim 83353942Sdim bool operator<(Integral RHS) const { return V < RHS.V; } 84353942Sdim bool operator>(Integral RHS) const { return V > RHS.V; } 85353942Sdim bool operator<=(Integral RHS) const { return V <= RHS.V; } 86353942Sdim bool operator>=(Integral RHS) const { return V >= RHS.V; } 87353942Sdim bool operator==(Integral RHS) const { return V == RHS.V; } 88353942Sdim bool operator!=(Integral RHS) const { return V != RHS.V; } 89353942Sdim 90353942Sdim bool operator>(unsigned RHS) const { 91353942Sdim return V >= 0 && static_cast<unsigned>(V) > RHS; 92353942Sdim } 93353942Sdim 94353942Sdim Integral operator-() const { return Integral(-V); } 95353942Sdim Integral operator~() const { return Integral(~V); } 96353942Sdim 97353942Sdim template <unsigned DstBits, bool DstSign> 98353942Sdim explicit operator Integral<DstBits, DstSign>() const { 99353942Sdim return Integral<DstBits, DstSign>(V); 100353942Sdim } 101353942Sdim 102353942Sdim explicit operator unsigned() const { return V; } 103353942Sdim explicit operator int64_t() const { return V; } 104353942Sdim explicit operator uint64_t() const { return V; } 105353942Sdim 106353942Sdim APSInt toAPSInt() const { 107353942Sdim return APSInt(APInt(Bits, static_cast<uint64_t>(V), Signed), !Signed); 108353942Sdim } 109353942Sdim APSInt toAPSInt(unsigned NumBits) const { 110353942Sdim if (Signed) 111353942Sdim return APSInt(toAPSInt().sextOrTrunc(NumBits), !Signed); 112353942Sdim else 113353942Sdim return APSInt(toAPSInt().zextOrTrunc(NumBits), !Signed); 114353942Sdim } 115353942Sdim APValue toAPValue() const { return APValue(toAPSInt()); } 116353942Sdim 117353942Sdim Integral<Bits, false> toUnsigned() const { 118353942Sdim return Integral<Bits, false>(*this); 119353942Sdim } 120353942Sdim 121353942Sdim constexpr static unsigned bitWidth() { return Bits; } 122353942Sdim 123353942Sdim bool isZero() const { return !V; } 124353942Sdim 125353942Sdim bool isMin() const { return *this == min(bitWidth()); } 126353942Sdim 127353942Sdim bool isMinusOne() const { return Signed && V == T(-1); } 128353942Sdim 129353942Sdim constexpr static bool isSigned() { return Signed; } 130353942Sdim 131353942Sdim bool isNegative() const { return V < T(0); } 132353942Sdim bool isPositive() const { return !isNegative(); } 133353942Sdim 134353942Sdim ComparisonCategoryResult compare(const Integral &RHS) const { 135353942Sdim return Compare(V, RHS.V); 136353942Sdim } 137353942Sdim 138353942Sdim unsigned countLeadingZeros() const { return llvm::countLeadingZeros<T>(V); } 139353942Sdim 140353942Sdim Integral truncate(unsigned TruncBits) const { 141353942Sdim if (TruncBits >= Bits) 142353942Sdim return *this; 143353942Sdim const T BitMask = (T(1) << T(TruncBits)) - 1; 144353942Sdim const T SignBit = T(1) << (TruncBits - 1); 145353942Sdim const T ExtMask = ~BitMask; 146353942Sdim return Integral((V & BitMask) | (Signed && (V & SignBit) ? ExtMask : 0)); 147353942Sdim } 148353942Sdim 149353942Sdim void print(llvm::raw_ostream &OS) const { OS << V; } 150353942Sdim 151353942Sdim static Integral min(unsigned NumBits) { 152353942Sdim return Integral(Min); 153353942Sdim } 154353942Sdim static Integral max(unsigned NumBits) { 155353942Sdim return Integral(Max); 156353942Sdim } 157353942Sdim 158353942Sdim template <typename T> 159353942Sdim static typename std::enable_if<std::is_integral<T>::value, Integral>::type 160353942Sdim from(T Value) { 161353942Sdim return Integral(Value); 162353942Sdim } 163353942Sdim 164353942Sdim template <unsigned SrcBits, bool SrcSign> 165353942Sdim static typename std::enable_if<SrcBits != 0, Integral>::type 166353942Sdim from(Integral<SrcBits, SrcSign> Value) { 167353942Sdim return Integral(Value.V); 168353942Sdim } 169353942Sdim 170353942Sdim template <bool SrcSign> static Integral from(Integral<0, SrcSign> Value) { 171353942Sdim if (SrcSign) 172353942Sdim return Integral(Value.V.getSExtValue()); 173353942Sdim else 174353942Sdim return Integral(Value.V.getZExtValue()); 175353942Sdim } 176353942Sdim 177353942Sdim static Integral zero() { return from(0); } 178353942Sdim 179353942Sdim template <typename T> static Integral from(T Value, unsigned NumBits) { 180353942Sdim return Integral(Value); 181353942Sdim } 182353942Sdim 183353942Sdim static bool inRange(int64_t Value, unsigned NumBits) { 184353942Sdim return CheckRange<T, Min, Max>(Value); 185353942Sdim } 186353942Sdim 187353942Sdim static bool increment(Integral A, Integral *R) { 188353942Sdim return add(A, Integral(T(1)), A.bitWidth(), R); 189353942Sdim } 190353942Sdim 191353942Sdim static bool decrement(Integral A, Integral *R) { 192353942Sdim return sub(A, Integral(T(1)), A.bitWidth(), R); 193353942Sdim } 194353942Sdim 195353942Sdim static bool add(Integral A, Integral B, unsigned OpBits, Integral *R) { 196353942Sdim return CheckAddUB(A.V, B.V, R->V); 197353942Sdim } 198353942Sdim 199353942Sdim static bool sub(Integral A, Integral B, unsigned OpBits, Integral *R) { 200353942Sdim return CheckSubUB(A.V, B.V, R->V); 201353942Sdim } 202353942Sdim 203353942Sdim static bool mul(Integral A, Integral B, unsigned OpBits, Integral *R) { 204353942Sdim return CheckMulUB(A.V, B.V, R->V); 205353942Sdim } 206353942Sdim 207353942Sdimprivate: 208353942Sdim template <typename T> 209353942Sdim static typename std::enable_if<std::is_signed<T>::value, bool>::type 210353942Sdim CheckAddUB(T A, T B, T &R) { 211353942Sdim return llvm::AddOverflow<T>(A, B, R); 212353942Sdim } 213353942Sdim 214353942Sdim template <typename T> 215353942Sdim static typename std::enable_if<std::is_unsigned<T>::value, bool>::type 216353942Sdim CheckAddUB(T A, T B, T &R) { 217353942Sdim R = A + B; 218353942Sdim return false; 219353942Sdim } 220353942Sdim 221353942Sdim template <typename T> 222353942Sdim static typename std::enable_if<std::is_signed<T>::value, bool>::type 223353942Sdim CheckSubUB(T A, T B, T &R) { 224353942Sdim return llvm::SubOverflow<T>(A, B, R); 225353942Sdim } 226353942Sdim 227353942Sdim template <typename T> 228353942Sdim static typename std::enable_if<std::is_unsigned<T>::value, bool>::type 229353942Sdim CheckSubUB(T A, T B, T &R) { 230353942Sdim R = A - B; 231353942Sdim return false; 232353942Sdim } 233353942Sdim 234353942Sdim template <typename T> 235353942Sdim static typename std::enable_if<std::is_signed<T>::value, bool>::type 236353942Sdim CheckMulUB(T A, T B, T &R) { 237353942Sdim return llvm::MulOverflow<T>(A, B, R); 238353942Sdim } 239353942Sdim 240353942Sdim template <typename T> 241353942Sdim static typename std::enable_if<std::is_unsigned<T>::value, bool>::type 242353942Sdim CheckMulUB(T A, T B, T &R) { 243353942Sdim R = A * B; 244353942Sdim return false; 245353942Sdim } 246353942Sdim 247353942Sdim template <typename T, T Min, T Max> 248353942Sdim static typename std::enable_if<std::is_signed<T>::value, bool>::type 249353942Sdim CheckRange(int64_t V) { 250353942Sdim return Min <= V && V <= Max; 251353942Sdim } 252353942Sdim 253353942Sdim template <typename T, T Min, T Max> 254353942Sdim static typename std::enable_if<std::is_unsigned<T>::value, bool>::type 255353942Sdim CheckRange(int64_t V) { 256353942Sdim return V >= 0 && static_cast<uint64_t>(V) <= Max; 257353942Sdim } 258353942Sdim}; 259353942Sdim 260353942Sdimtemplate <unsigned Bits, bool Signed> 261353942Sdimllvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Integral<Bits, Signed> I) { 262353942Sdim I.print(OS); 263353942Sdim return OS; 264353942Sdim} 265353942Sdim 266353942Sdim} // namespace interp 267353942Sdim} // namespace clang 268353942Sdim 269353942Sdim#endif 270