Path: blob/main/contrib/llvm-project/clang/lib/AST/Interp/IntegralAP.h
35292 views
//===--- Integral.h - Wrapper for numeric types for the VM ------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Defines the VM types and helpers operating on types.9//10//===----------------------------------------------------------------------===//1112#ifndef LLVM_CLANG_AST_INTERP_INTEGRAL_AP_H13#define LLVM_CLANG_AST_INTERP_INTEGRAL_AP_H1415#include "clang/AST/APValue.h"16#include "clang/AST/ComparisonCategories.h"17#include "llvm/ADT/APSInt.h"18#include "llvm/Support/MathExtras.h"19#include "llvm/Support/raw_ostream.h"20#include <cstddef>21#include <cstdint>2223#include "Primitives.h"2425namespace clang {26namespace interp {2728using APInt = llvm::APInt;29using APSInt = llvm::APSInt;30template <unsigned Bits, bool Signed> class Integral;3132template <bool Signed> class IntegralAP final {33private:34friend IntegralAP<!Signed>;35APInt V;3637template <typename T, bool InputSigned>38static T truncateCast(const APInt &V) {39constexpr unsigned BitSize = sizeof(T) * 8;40if (BitSize >= V.getBitWidth()) {41APInt Extended;42if constexpr (InputSigned)43Extended = V.sext(BitSize);44else45Extended = V.zext(BitSize);46return std::is_signed_v<T> ? Extended.getSExtValue()47: Extended.getZExtValue();48}4950return std::is_signed_v<T> ? V.trunc(BitSize).getSExtValue()51: V.trunc(BitSize).getZExtValue();52}5354public:55using AsUnsigned = IntegralAP<false>;5657template <typename T>58IntegralAP(T Value, unsigned BitWidth)59: V(APInt(BitWidth, static_cast<uint64_t>(Value), Signed)) {}6061IntegralAP(APInt V) : V(V) {}62/// Arbitrary value for uninitialized variables.63IntegralAP() : IntegralAP(-1, 3) {}6465IntegralAP operator-() const { return IntegralAP(-V); }66IntegralAP operator-(const IntegralAP &Other) const {67return IntegralAP(V - Other.V);68}69bool operator>(const IntegralAP &RHS) const {70if constexpr (Signed)71return V.ugt(RHS.V);72return V.sgt(RHS.V);73}74bool operator>=(IntegralAP RHS) const {75if constexpr (Signed)76return V.uge(RHS.V);77return V.sge(RHS.V);78}79bool operator<(IntegralAP RHS) const {80if constexpr (Signed)81return V.slt(RHS.V);82return V.slt(RHS.V);83}84bool operator<=(IntegralAP RHS) const {85if constexpr (Signed)86return V.ult(RHS.V);87return V.ult(RHS.V);88}8990template <typename Ty, typename = std::enable_if_t<std::is_integral_v<Ty>>>91explicit operator Ty() const {92return truncateCast<Ty, Signed>(V);93}9495template <typename T> static IntegralAP from(T Value, unsigned NumBits = 0) {96assert(NumBits > 0);97APInt Copy = APInt(NumBits, static_cast<uint64_t>(Value), Signed);9899return IntegralAP<Signed>(Copy);100}101102template <bool InputSigned>103static IntegralAP from(IntegralAP<InputSigned> V, unsigned NumBits = 0) {104if (NumBits == 0)105NumBits = V.bitWidth();106107if constexpr (InputSigned)108return IntegralAP<Signed>(V.V.sextOrTrunc(NumBits));109return IntegralAP<Signed>(V.V.zextOrTrunc(NumBits));110}111112template <unsigned Bits, bool InputSigned>113static IntegralAP from(Integral<Bits, InputSigned> I, unsigned BitWidth) {114APInt Copy = APInt(BitWidth, static_cast<uint64_t>(I), InputSigned);115116return IntegralAP<Signed>(Copy);117}118119static IntegralAP zero(int32_t BitWidth) {120APInt V = APInt(BitWidth, 0LL, Signed);121return IntegralAP(V);122}123124constexpr unsigned bitWidth() const { return V.getBitWidth(); }125126APSInt toAPSInt(unsigned Bits = 0) const {127if (Bits == 0)128Bits = bitWidth();129130if constexpr (Signed)131return APSInt(V.sext(Bits), !Signed);132else133return APSInt(V.zext(Bits), !Signed);134}135APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); }136137bool isZero() const { return V.isZero(); }138bool isPositive() const { return V.isNonNegative(); }139bool isNegative() const { return !V.isNonNegative(); }140bool isMin() const { return V.isMinValue(); }141bool isMax() const { return V.isMaxValue(); }142static constexpr bool isSigned() { return Signed; }143bool isMinusOne() const { return Signed && V == -1; }144145unsigned countLeadingZeros() const { return V.countl_zero(); }146147void print(llvm::raw_ostream &OS) const { OS << V; }148std::string toDiagnosticString(const ASTContext &Ctx) const {149std::string NameStr;150llvm::raw_string_ostream OS(NameStr);151print(OS);152return NameStr;153}154155IntegralAP truncate(unsigned BitWidth) const {156if constexpr (Signed)157return IntegralAP(V.trunc(BitWidth).sextOrTrunc(this->bitWidth()));158else159return IntegralAP(V.trunc(BitWidth).zextOrTrunc(this->bitWidth()));160}161162IntegralAP<false> toUnsigned() const {163APInt Copy = V;164return IntegralAP<false>(Copy);165}166167ComparisonCategoryResult compare(const IntegralAP &RHS) const {168assert(Signed == RHS.isSigned());169assert(bitWidth() == RHS.bitWidth());170if constexpr (Signed) {171if (V.slt(RHS.V))172return ComparisonCategoryResult::Less;173if (V.sgt(RHS.V))174return ComparisonCategoryResult::Greater;175return ComparisonCategoryResult::Equal;176}177178assert(!Signed);179if (V.ult(RHS.V))180return ComparisonCategoryResult::Less;181if (V.ugt(RHS.V))182return ComparisonCategoryResult::Greater;183return ComparisonCategoryResult::Equal;184}185186static bool increment(IntegralAP A, IntegralAP *R) {187IntegralAP<Signed> One(1, A.bitWidth());188return add(A, One, A.bitWidth() + 1, R);189}190191static bool decrement(IntegralAP A, IntegralAP *R) {192IntegralAP<Signed> One(1, A.bitWidth());193return sub(A, One, A.bitWidth() + 1, R);194}195196static bool add(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {197return CheckAddSubMulUB<std::plus>(A, B, OpBits, R);198}199200static bool sub(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {201return CheckAddSubMulUB<std::minus>(A, B, OpBits, R);202}203204static bool mul(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {205return CheckAddSubMulUB<std::multiplies>(A, B, OpBits, R);206}207208static bool rem(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {209if constexpr (Signed)210*R = IntegralAP(A.V.srem(B.V));211else212*R = IntegralAP(A.V.urem(B.V));213return false;214}215216static bool div(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {217if constexpr (Signed)218*R = IntegralAP(A.V.sdiv(B.V));219else220*R = IntegralAP(A.V.udiv(B.V));221return false;222}223224static bool bitAnd(IntegralAP A, IntegralAP B, unsigned OpBits,225IntegralAP *R) {226*R = IntegralAP(A.V & B.V);227return false;228}229230static bool bitOr(IntegralAP A, IntegralAP B, unsigned OpBits,231IntegralAP *R) {232*R = IntegralAP(A.V | B.V);233return false;234}235236static bool bitXor(IntegralAP A, IntegralAP B, unsigned OpBits,237IntegralAP *R) {238*R = IntegralAP(A.V ^ B.V);239return false;240}241242static bool neg(const IntegralAP &A, IntegralAP *R) {243APInt AI = A.V;244AI.negate();245*R = IntegralAP(AI);246return false;247}248249static bool comp(IntegralAP A, IntegralAP *R) {250*R = IntegralAP(~A.V);251return false;252}253254static void shiftLeft(const IntegralAP A, const IntegralAP B, unsigned OpBits,255IntegralAP *R) {256*R = IntegralAP(A.V.shl(B.V.getZExtValue()));257}258259static void shiftRight(const IntegralAP A, const IntegralAP B,260unsigned OpBits, IntegralAP *R) {261unsigned ShiftAmount = B.V.getZExtValue();262if constexpr (Signed)263*R = IntegralAP(A.V.ashr(ShiftAmount));264else265*R = IntegralAP(A.V.lshr(ShiftAmount));266}267268// === Serialization support ===269size_t bytesToSerialize() const {270// 4 bytes for the BitWidth followed by N bytes for the actual APInt.271return sizeof(uint32_t) + (V.getBitWidth() / CHAR_BIT);272}273274void serialize(std::byte *Buff) const {275assert(V.getBitWidth() < std::numeric_limits<uint8_t>::max());276uint32_t BitWidth = V.getBitWidth();277278std::memcpy(Buff, &BitWidth, sizeof(uint32_t));279llvm::StoreIntToMemory(V, (uint8_t *)(Buff + sizeof(uint32_t)),280BitWidth / CHAR_BIT);281}282283static IntegralAP<Signed> deserialize(const std::byte *Buff) {284uint32_t BitWidth;285std::memcpy(&BitWidth, Buff, sizeof(uint32_t));286IntegralAP<Signed> Val(APInt(BitWidth, 0ull, !Signed));287288llvm::LoadIntFromMemory(Val.V, (const uint8_t *)Buff + sizeof(uint32_t),289BitWidth / CHAR_BIT);290return Val;291}292293private:294template <template <typename T> class Op>295static bool CheckAddSubMulUB(const IntegralAP &A, const IntegralAP &B,296unsigned BitWidth, IntegralAP *R) {297if constexpr (!Signed) {298R->V = Op<APInt>{}(A.V, B.V);299return false;300}301302const APSInt &LHS = A.toAPSInt();303const APSInt &RHS = B.toAPSInt();304APSInt Value = Op<APSInt>{}(LHS.extend(BitWidth), RHS.extend(BitWidth));305APSInt Result = Value.trunc(LHS.getBitWidth());306R->V = Result;307308return Result.extend(BitWidth) != Value;309}310};311312template <bool Signed>313inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,314IntegralAP<Signed> I) {315I.print(OS);316return OS;317}318319template <bool Signed>320IntegralAP<Signed> getSwappedBytes(IntegralAP<Signed> F) {321return F;322}323324} // namespace interp325} // namespace clang326327#endif328329330