brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.4 KiB · b11e6ee Raw
385 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_AP_H14#define LLVM_CLANG_AST_INTERP_INTEGRAL_AP_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 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 it34/// won't alllocate anything. The allocation should happen via InterpState or35/// Program.36template <bool Signed> class IntegralAP final {37public: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      else53        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, llvm::ArrayRef(Memory, NumWords));67  }68 69public: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      else86        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    else151      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    else194      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    else260      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    else268      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    else313      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 350private: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 369template <bool Signed>370inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,371                                     IntegralAP<Signed> I) {372  I.print(OS);373  return OS;374}375 376template <bool Signed>377IntegralAP<Signed> getSwappedBytes(IntegralAP<Signed> F) {378  return F;379}380 381} // namespace interp382} // namespace clang383 384#endif385