brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.6 KiB · e90f1a9 Raw
334 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8//9// Defines the VM types and helpers operating on types.10//11//===----------------------------------------------------------------------===//12 13#ifndef LLVM_CLANG_AST_INTERP_INTEGRAL_H14#define LLVM_CLANG_AST_INTERP_INTEGRAL_H15 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 26namespace clang {27namespace interp {28 29using APInt = llvm::APInt;30using APSInt = llvm::APSInt;31 32template <bool Signed> class IntegralAP;33 34// Helper structure to select the representation.35template <unsigned Bits, bool Signed> struct Repr;36template <> struct Repr<8, false> {37  using Type = uint8_t;38};39template <> struct Repr<16, false> {40  using Type = uint16_t;41};42template <> struct Repr<32, false> {43  using Type = uint32_t;44};45template <> struct Repr<64, false> {46  using Type = uint64_t;47};48template <> struct Repr<8, true> {49  using Type = int8_t;50};51template <> struct Repr<16, true> {52  using Type = int16_t;53};54template <> struct Repr<32, true> {55  using Type = int32_t;56};57template <> 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 and64/// builtin primitive numeral types, while optimising for storage and65/// allowing methods operating on primitive type to compile to fast code.66template <unsigned Bits, bool Signed> class Integral final {67private: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 82public: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    else137      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  static Integral zero(unsigned BitWidth = 0) { return from(0); }206 207  template <typename ValT>208  static Integral from(ValT Value, unsigned NumBits = 0) {209    if constexpr (std::is_integral_v<ValT>)210      return Integral(Value);211    else212      return Integral(static_cast<Integral::ReprT>(Value));213  }214 215  template <unsigned SrcBits, bool SrcSign>216  static Integral from(Integral<SrcBits, SrcSign> Value) {217    return Integral(Value.V);218  }219 220  static bool increment(Integral A, Integral *R) {221    return add(A, Integral(ReprT(1)), A.bitWidth(), R);222  }223 224  static bool decrement(Integral A, Integral *R) {225    return sub(A, Integral(ReprT(1)), A.bitWidth(), R);226  }227 228  static bool add(Integral A, Integral B, unsigned OpBits, Integral *R) {229    return CheckAddUB(A.V, B.V, R->V);230  }231 232  static bool sub(Integral A, Integral B, unsigned OpBits, Integral *R) {233    return CheckSubUB(A.V, B.V, R->V);234  }235 236  static bool mul(Integral A, Integral B, unsigned OpBits, Integral *R) {237    return CheckMulUB(A.V, B.V, R->V);238  }239 240  static bool rem(Integral A, Integral B, unsigned OpBits, Integral *R) {241    *R = Integral(A.V % B.V);242    return false;243  }244 245  static bool div(Integral A, Integral B, unsigned OpBits, Integral *R) {246    *R = Integral(A.V / B.V);247    return false;248  }249 250  static bool bitAnd(Integral A, Integral B, unsigned OpBits, Integral *R) {251    *R = Integral(A.V & B.V);252    return false;253  }254 255  static bool bitOr(Integral A, Integral B, unsigned OpBits, Integral *R) {256    *R = Integral(A.V | B.V);257    return false;258  }259 260  static bool bitXor(Integral A, Integral B, unsigned OpBits, Integral *R) {261    *R = Integral(A.V ^ B.V);262    return false;263  }264 265  static bool neg(Integral A, Integral *R) {266    if (Signed && A.isMin())267      return true;268 269    *R = -A;270    return false;271  }272 273  static bool comp(Integral A, Integral *R) {274    *R = Integral(~A.V);275    return false;276  }277 278  template <unsigned RHSBits, bool RHSSign>279  static void shiftLeft(const Integral A, const Integral<RHSBits, RHSSign> B,280                        unsigned OpBits, Integral *R) {281    *R = Integral::from(A.V << B.V, OpBits);282  }283 284  template <unsigned RHSBits, bool RHSSign>285  static void shiftRight(const Integral A, const Integral<RHSBits, RHSSign> B,286                         unsigned OpBits, Integral *R) {287    *R = Integral::from(A.V >> B.V, OpBits);288  }289 290private:291  template <typename T> static bool CheckAddUB(T A, T B, T &R) {292    if constexpr (std::is_signed_v<T>) {293      return llvm::AddOverflow<T>(A, B, R);294    } else {295      R = A + B;296      return false;297    }298  }299 300  template <typename T> static bool CheckSubUB(T A, T B, T &R) {301    if constexpr (std::is_signed_v<T>) {302      return llvm::SubOverflow<T>(A, B, R);303    } else {304      R = A - B;305      return false;306    }307  }308 309  template <typename T> static bool CheckMulUB(T A, T B, T &R) {310    if constexpr (std::is_signed_v<T>) {311      return llvm::MulOverflow<T>(A, B, R);312    } else if constexpr (sizeof(T) < sizeof(int)) {313      // Silly integer promotion rules will convert both A and B to int,314      // even it T is unsigned. Prevent that by manually casting to uint first.315      R = static_cast<T>(static_cast<unsigned>(A) * static_cast<unsigned>(B));316      return false;317    } else {318      R = A * B;319      return false;320    }321  }322};323 324template <unsigned Bits, bool Signed>325llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Integral<Bits, Signed> I) {326  I.print(OS);327  return OS;328}329 330} // namespace interp331} // namespace clang332 333#endif334