15f757f3fSDimitry Andric //===--- Integral.h - Wrapper for numeric types for the VM ------*- C++ -*-===// 25f757f3fSDimitry Andric // 35f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65f757f3fSDimitry Andric // 75f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 85f757f3fSDimitry Andric // 95f757f3fSDimitry Andric // Defines the VM types and helpers operating on types. 105f757f3fSDimitry Andric // 115f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 125f757f3fSDimitry Andric 135f757f3fSDimitry Andric #ifndef LLVM_CLANG_AST_INTERP_INTEGRAL_AP_H 145f757f3fSDimitry Andric #define LLVM_CLANG_AST_INTERP_INTEGRAL_AP_H 155f757f3fSDimitry Andric 165f757f3fSDimitry Andric #include "clang/AST/APValue.h" 175f757f3fSDimitry Andric #include "clang/AST/ComparisonCategories.h" 185f757f3fSDimitry Andric #include "llvm/ADT/APSInt.h" 195f757f3fSDimitry Andric #include "llvm/Support/MathExtras.h" 205f757f3fSDimitry Andric #include "llvm/Support/raw_ostream.h" 215f757f3fSDimitry Andric #include <cstddef> 225f757f3fSDimitry Andric #include <cstdint> 235f757f3fSDimitry Andric 245f757f3fSDimitry Andric #include "Primitives.h" 255f757f3fSDimitry Andric 265f757f3fSDimitry Andric namespace clang { 275f757f3fSDimitry Andric namespace interp { 285f757f3fSDimitry Andric 295f757f3fSDimitry Andric using APInt = llvm::APInt; 305f757f3fSDimitry Andric using APSInt = llvm::APSInt; 315f757f3fSDimitry Andric template <unsigned Bits, bool Signed> class Integral; 325f757f3fSDimitry Andric 335f757f3fSDimitry Andric template <bool Signed> class IntegralAP final { 345f757f3fSDimitry Andric private: 355f757f3fSDimitry Andric friend IntegralAP<!Signed>; 365f757f3fSDimitry Andric APInt V; 375f757f3fSDimitry Andric 385f757f3fSDimitry Andric template <typename T, bool InputSigned> 395f757f3fSDimitry Andric static T truncateCast(const APInt &V) { 405f757f3fSDimitry Andric constexpr unsigned BitSize = sizeof(T) * 8; 415f757f3fSDimitry Andric if (BitSize >= V.getBitWidth()) { 425f757f3fSDimitry Andric APInt Extended; 435f757f3fSDimitry Andric if constexpr (InputSigned) 445f757f3fSDimitry Andric Extended = V.sext(BitSize); 455f757f3fSDimitry Andric else 465f757f3fSDimitry Andric Extended = V.zext(BitSize); 475f757f3fSDimitry Andric return std::is_signed_v<T> ? Extended.getSExtValue() 485f757f3fSDimitry Andric : Extended.getZExtValue(); 495f757f3fSDimitry Andric } 505f757f3fSDimitry Andric 515f757f3fSDimitry Andric return std::is_signed_v<T> ? V.trunc(BitSize).getSExtValue() 525f757f3fSDimitry Andric : V.trunc(BitSize).getZExtValue(); 535f757f3fSDimitry Andric } 545f757f3fSDimitry Andric 555f757f3fSDimitry Andric public: 565f757f3fSDimitry Andric using AsUnsigned = IntegralAP<false>; 575f757f3fSDimitry Andric 585f757f3fSDimitry Andric template <typename T> 595f757f3fSDimitry Andric IntegralAP(T Value, unsigned BitWidth) 605f757f3fSDimitry Andric : V(APInt(BitWidth, static_cast<uint64_t>(Value), Signed)) {} 615f757f3fSDimitry Andric 625f757f3fSDimitry Andric IntegralAP(APInt V) : V(V) {} 635f757f3fSDimitry Andric /// Arbitrary value for uninitialized variables. 64*0fca6ea1SDimitry Andric IntegralAP() : IntegralAP(-1, 3) {} 655f757f3fSDimitry Andric 665f757f3fSDimitry Andric IntegralAP operator-() const { return IntegralAP(-V); } 675f757f3fSDimitry Andric IntegralAP operator-(const IntegralAP &Other) const { 685f757f3fSDimitry Andric return IntegralAP(V - Other.V); 695f757f3fSDimitry Andric } 705f757f3fSDimitry Andric bool operator>(const IntegralAP &RHS) const { 715f757f3fSDimitry Andric if constexpr (Signed) 725f757f3fSDimitry Andric return V.ugt(RHS.V); 735f757f3fSDimitry Andric return V.sgt(RHS.V); 745f757f3fSDimitry Andric } 755f757f3fSDimitry Andric bool operator>=(IntegralAP RHS) const { 765f757f3fSDimitry Andric if constexpr (Signed) 775f757f3fSDimitry Andric return V.uge(RHS.V); 785f757f3fSDimitry Andric return V.sge(RHS.V); 795f757f3fSDimitry Andric } 805f757f3fSDimitry Andric bool operator<(IntegralAP RHS) const { 815f757f3fSDimitry Andric if constexpr (Signed) 825f757f3fSDimitry Andric return V.slt(RHS.V); 835f757f3fSDimitry Andric return V.slt(RHS.V); 845f757f3fSDimitry Andric } 855f757f3fSDimitry Andric bool operator<=(IntegralAP RHS) const { 865f757f3fSDimitry Andric if constexpr (Signed) 875f757f3fSDimitry Andric return V.ult(RHS.V); 885f757f3fSDimitry Andric return V.ult(RHS.V); 895f757f3fSDimitry Andric } 905f757f3fSDimitry Andric 915f757f3fSDimitry Andric template <typename Ty, typename = std::enable_if_t<std::is_integral_v<Ty>>> 925f757f3fSDimitry Andric explicit operator Ty() const { 935f757f3fSDimitry Andric return truncateCast<Ty, Signed>(V); 945f757f3fSDimitry Andric } 955f757f3fSDimitry Andric 965f757f3fSDimitry Andric template <typename T> static IntegralAP from(T Value, unsigned NumBits = 0) { 975f757f3fSDimitry Andric assert(NumBits > 0); 985f757f3fSDimitry Andric APInt Copy = APInt(NumBits, static_cast<uint64_t>(Value), Signed); 995f757f3fSDimitry Andric 1005f757f3fSDimitry Andric return IntegralAP<Signed>(Copy); 1015f757f3fSDimitry Andric } 1025f757f3fSDimitry Andric 1035f757f3fSDimitry Andric template <bool InputSigned> 1045f757f3fSDimitry Andric static IntegralAP from(IntegralAP<InputSigned> V, unsigned NumBits = 0) { 1055f757f3fSDimitry Andric if (NumBits == 0) 1065f757f3fSDimitry Andric NumBits = V.bitWidth(); 1075f757f3fSDimitry Andric 1085f757f3fSDimitry Andric if constexpr (InputSigned) 1095f757f3fSDimitry Andric return IntegralAP<Signed>(V.V.sextOrTrunc(NumBits)); 1105f757f3fSDimitry Andric return IntegralAP<Signed>(V.V.zextOrTrunc(NumBits)); 1115f757f3fSDimitry Andric } 1125f757f3fSDimitry Andric 1135f757f3fSDimitry Andric template <unsigned Bits, bool InputSigned> 1145f757f3fSDimitry Andric static IntegralAP from(Integral<Bits, InputSigned> I, unsigned BitWidth) { 1155f757f3fSDimitry Andric APInt Copy = APInt(BitWidth, static_cast<uint64_t>(I), InputSigned); 1165f757f3fSDimitry Andric 1175f757f3fSDimitry Andric return IntegralAP<Signed>(Copy); 1185f757f3fSDimitry Andric } 1195f757f3fSDimitry Andric 1205f757f3fSDimitry Andric static IntegralAP zero(int32_t BitWidth) { 1215f757f3fSDimitry Andric APInt V = APInt(BitWidth, 0LL, Signed); 1225f757f3fSDimitry Andric return IntegralAP(V); 1235f757f3fSDimitry Andric } 1245f757f3fSDimitry Andric 1255f757f3fSDimitry Andric constexpr unsigned bitWidth() const { return V.getBitWidth(); } 1265f757f3fSDimitry Andric 1275f757f3fSDimitry Andric APSInt toAPSInt(unsigned Bits = 0) const { 1285f757f3fSDimitry Andric if (Bits == 0) 1295f757f3fSDimitry Andric Bits = bitWidth(); 1305f757f3fSDimitry Andric 1315f757f3fSDimitry Andric if constexpr (Signed) 1325f757f3fSDimitry Andric return APSInt(V.sext(Bits), !Signed); 1335f757f3fSDimitry Andric else 1345f757f3fSDimitry Andric return APSInt(V.zext(Bits), !Signed); 1355f757f3fSDimitry Andric } 136*0fca6ea1SDimitry Andric APValue toAPValue(const ASTContext &) const { return APValue(toAPSInt()); } 1375f757f3fSDimitry Andric 1385f757f3fSDimitry Andric bool isZero() const { return V.isZero(); } 1395f757f3fSDimitry Andric bool isPositive() const { return V.isNonNegative(); } 1405f757f3fSDimitry Andric bool isNegative() const { return !V.isNonNegative(); } 1415f757f3fSDimitry Andric bool isMin() const { return V.isMinValue(); } 1425f757f3fSDimitry Andric bool isMax() const { return V.isMaxValue(); } 1435f757f3fSDimitry Andric static constexpr bool isSigned() { return Signed; } 1445f757f3fSDimitry Andric bool isMinusOne() const { return Signed && V == -1; } 1455f757f3fSDimitry Andric 1465f757f3fSDimitry Andric unsigned countLeadingZeros() const { return V.countl_zero(); } 1475f757f3fSDimitry Andric 1485f757f3fSDimitry Andric void print(llvm::raw_ostream &OS) const { OS << V; } 1495f757f3fSDimitry Andric std::string toDiagnosticString(const ASTContext &Ctx) const { 1505f757f3fSDimitry Andric std::string NameStr; 1515f757f3fSDimitry Andric llvm::raw_string_ostream OS(NameStr); 1525f757f3fSDimitry Andric print(OS); 1535f757f3fSDimitry Andric return NameStr; 1545f757f3fSDimitry Andric } 1555f757f3fSDimitry Andric 1565f757f3fSDimitry Andric IntegralAP truncate(unsigned BitWidth) const { 157*0fca6ea1SDimitry Andric if constexpr (Signed) 158*0fca6ea1SDimitry Andric return IntegralAP(V.trunc(BitWidth).sextOrTrunc(this->bitWidth())); 159*0fca6ea1SDimitry Andric else 160*0fca6ea1SDimitry Andric return IntegralAP(V.trunc(BitWidth).zextOrTrunc(this->bitWidth())); 1615f757f3fSDimitry Andric } 1625f757f3fSDimitry Andric 1635f757f3fSDimitry Andric IntegralAP<false> toUnsigned() const { 1645f757f3fSDimitry Andric APInt Copy = V; 1655f757f3fSDimitry Andric return IntegralAP<false>(Copy); 1665f757f3fSDimitry Andric } 1675f757f3fSDimitry Andric 1685f757f3fSDimitry Andric ComparisonCategoryResult compare(const IntegralAP &RHS) const { 1695f757f3fSDimitry Andric assert(Signed == RHS.isSigned()); 1705f757f3fSDimitry Andric assert(bitWidth() == RHS.bitWidth()); 1715f757f3fSDimitry Andric if constexpr (Signed) { 1725f757f3fSDimitry Andric if (V.slt(RHS.V)) 1735f757f3fSDimitry Andric return ComparisonCategoryResult::Less; 1745f757f3fSDimitry Andric if (V.sgt(RHS.V)) 1755f757f3fSDimitry Andric return ComparisonCategoryResult::Greater; 1765f757f3fSDimitry Andric return ComparisonCategoryResult::Equal; 1775f757f3fSDimitry Andric } 1785f757f3fSDimitry Andric 1795f757f3fSDimitry Andric assert(!Signed); 1805f757f3fSDimitry Andric if (V.ult(RHS.V)) 1815f757f3fSDimitry Andric return ComparisonCategoryResult::Less; 1825f757f3fSDimitry Andric if (V.ugt(RHS.V)) 1835f757f3fSDimitry Andric return ComparisonCategoryResult::Greater; 1845f757f3fSDimitry Andric return ComparisonCategoryResult::Equal; 1855f757f3fSDimitry Andric } 1865f757f3fSDimitry Andric 1875f757f3fSDimitry Andric static bool increment(IntegralAP A, IntegralAP *R) { 1885f757f3fSDimitry Andric IntegralAP<Signed> One(1, A.bitWidth()); 1895f757f3fSDimitry Andric return add(A, One, A.bitWidth() + 1, R); 1905f757f3fSDimitry Andric } 1915f757f3fSDimitry Andric 1925f757f3fSDimitry Andric static bool decrement(IntegralAP A, IntegralAP *R) { 1935f757f3fSDimitry Andric IntegralAP<Signed> One(1, A.bitWidth()); 1945f757f3fSDimitry Andric return sub(A, One, A.bitWidth() + 1, R); 1955f757f3fSDimitry Andric } 1965f757f3fSDimitry Andric 1975f757f3fSDimitry Andric static bool add(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { 1985f757f3fSDimitry Andric return CheckAddSubMulUB<std::plus>(A, B, OpBits, R); 1995f757f3fSDimitry Andric } 2005f757f3fSDimitry Andric 2015f757f3fSDimitry Andric static bool sub(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { 2025f757f3fSDimitry Andric return CheckAddSubMulUB<std::minus>(A, B, OpBits, R); 2035f757f3fSDimitry Andric } 2045f757f3fSDimitry Andric 2055f757f3fSDimitry Andric static bool mul(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { 2065f757f3fSDimitry Andric return CheckAddSubMulUB<std::multiplies>(A, B, OpBits, R); 2075f757f3fSDimitry Andric } 2085f757f3fSDimitry Andric 2095f757f3fSDimitry Andric static bool rem(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { 2107a6dacacSDimitry Andric if constexpr (Signed) 2117a6dacacSDimitry Andric *R = IntegralAP(A.V.srem(B.V)); 2127a6dacacSDimitry Andric else 2137a6dacacSDimitry Andric *R = IntegralAP(A.V.urem(B.V)); 2145f757f3fSDimitry Andric return false; 2155f757f3fSDimitry Andric } 2165f757f3fSDimitry Andric 2175f757f3fSDimitry Andric static bool div(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) { 2187a6dacacSDimitry Andric if constexpr (Signed) 2197a6dacacSDimitry Andric *R = IntegralAP(A.V.sdiv(B.V)); 2207a6dacacSDimitry Andric else 2217a6dacacSDimitry Andric *R = IntegralAP(A.V.udiv(B.V)); 2225f757f3fSDimitry Andric return false; 2235f757f3fSDimitry Andric } 2245f757f3fSDimitry Andric 2255f757f3fSDimitry Andric static bool bitAnd(IntegralAP A, IntegralAP B, unsigned OpBits, 2265f757f3fSDimitry Andric IntegralAP *R) { 2275f757f3fSDimitry Andric *R = IntegralAP(A.V & B.V); 2285f757f3fSDimitry Andric return false; 2295f757f3fSDimitry Andric } 2305f757f3fSDimitry Andric 2315f757f3fSDimitry Andric static bool bitOr(IntegralAP A, IntegralAP B, unsigned OpBits, 2325f757f3fSDimitry Andric IntegralAP *R) { 2335f757f3fSDimitry Andric *R = IntegralAP(A.V | B.V); 2345f757f3fSDimitry Andric return false; 2355f757f3fSDimitry Andric } 2365f757f3fSDimitry Andric 2375f757f3fSDimitry Andric static bool bitXor(IntegralAP A, IntegralAP B, unsigned OpBits, 2385f757f3fSDimitry Andric IntegralAP *R) { 2395f757f3fSDimitry Andric *R = IntegralAP(A.V ^ B.V); 2405f757f3fSDimitry Andric return false; 2415f757f3fSDimitry Andric } 2425f757f3fSDimitry Andric 2435f757f3fSDimitry Andric static bool neg(const IntegralAP &A, IntegralAP *R) { 2445f757f3fSDimitry Andric APInt AI = A.V; 2455f757f3fSDimitry Andric AI.negate(); 2465f757f3fSDimitry Andric *R = IntegralAP(AI); 2475f757f3fSDimitry Andric return false; 2485f757f3fSDimitry Andric } 2495f757f3fSDimitry Andric 2505f757f3fSDimitry Andric static bool comp(IntegralAP A, IntegralAP *R) { 2515f757f3fSDimitry Andric *R = IntegralAP(~A.V); 2525f757f3fSDimitry Andric return false; 2535f757f3fSDimitry Andric } 2545f757f3fSDimitry Andric 2555f757f3fSDimitry Andric static void shiftLeft(const IntegralAP A, const IntegralAP B, unsigned OpBits, 2565f757f3fSDimitry Andric IntegralAP *R) { 2575f757f3fSDimitry Andric *R = IntegralAP(A.V.shl(B.V.getZExtValue())); 2585f757f3fSDimitry Andric } 2595f757f3fSDimitry Andric 2605f757f3fSDimitry Andric static void shiftRight(const IntegralAP A, const IntegralAP B, 2615f757f3fSDimitry Andric unsigned OpBits, IntegralAP *R) { 2625f757f3fSDimitry Andric unsigned ShiftAmount = B.V.getZExtValue(); 2635f757f3fSDimitry Andric if constexpr (Signed) 2645f757f3fSDimitry Andric *R = IntegralAP(A.V.ashr(ShiftAmount)); 2655f757f3fSDimitry Andric else 2665f757f3fSDimitry Andric *R = IntegralAP(A.V.lshr(ShiftAmount)); 2675f757f3fSDimitry Andric } 2685f757f3fSDimitry Andric 269*0fca6ea1SDimitry Andric // === Serialization support === 270*0fca6ea1SDimitry Andric size_t bytesToSerialize() const { 271*0fca6ea1SDimitry Andric // 4 bytes for the BitWidth followed by N bytes for the actual APInt. 272*0fca6ea1SDimitry Andric return sizeof(uint32_t) + (V.getBitWidth() / CHAR_BIT); 273*0fca6ea1SDimitry Andric } 274*0fca6ea1SDimitry Andric 275*0fca6ea1SDimitry Andric void serialize(std::byte *Buff) const { 276*0fca6ea1SDimitry Andric assert(V.getBitWidth() < std::numeric_limits<uint8_t>::max()); 277*0fca6ea1SDimitry Andric uint32_t BitWidth = V.getBitWidth(); 278*0fca6ea1SDimitry Andric 279*0fca6ea1SDimitry Andric std::memcpy(Buff, &BitWidth, sizeof(uint32_t)); 280*0fca6ea1SDimitry Andric llvm::StoreIntToMemory(V, (uint8_t *)(Buff + sizeof(uint32_t)), 281*0fca6ea1SDimitry Andric BitWidth / CHAR_BIT); 282*0fca6ea1SDimitry Andric } 283*0fca6ea1SDimitry Andric 284*0fca6ea1SDimitry Andric static IntegralAP<Signed> deserialize(const std::byte *Buff) { 285*0fca6ea1SDimitry Andric uint32_t BitWidth; 286*0fca6ea1SDimitry Andric std::memcpy(&BitWidth, Buff, sizeof(uint32_t)); 287*0fca6ea1SDimitry Andric IntegralAP<Signed> Val(APInt(BitWidth, 0ull, !Signed)); 288*0fca6ea1SDimitry Andric 289*0fca6ea1SDimitry Andric llvm::LoadIntFromMemory(Val.V, (const uint8_t *)Buff + sizeof(uint32_t), 290*0fca6ea1SDimitry Andric BitWidth / CHAR_BIT); 291*0fca6ea1SDimitry Andric return Val; 292*0fca6ea1SDimitry Andric } 293*0fca6ea1SDimitry Andric 2945f757f3fSDimitry Andric private: 2955f757f3fSDimitry Andric template <template <typename T> class Op> 2965f757f3fSDimitry Andric static bool CheckAddSubMulUB(const IntegralAP &A, const IntegralAP &B, 2975f757f3fSDimitry Andric unsigned BitWidth, IntegralAP *R) { 2985f757f3fSDimitry Andric if constexpr (!Signed) { 2995f757f3fSDimitry Andric R->V = Op<APInt>{}(A.V, B.V); 3005f757f3fSDimitry Andric return false; 3015f757f3fSDimitry Andric } 3025f757f3fSDimitry Andric 3035f757f3fSDimitry Andric const APSInt &LHS = A.toAPSInt(); 3045f757f3fSDimitry Andric const APSInt &RHS = B.toAPSInt(); 3055f757f3fSDimitry Andric APSInt Value = Op<APSInt>{}(LHS.extend(BitWidth), RHS.extend(BitWidth)); 3065f757f3fSDimitry Andric APSInt Result = Value.trunc(LHS.getBitWidth()); 3075f757f3fSDimitry Andric R->V = Result; 3085f757f3fSDimitry Andric 3095f757f3fSDimitry Andric return Result.extend(BitWidth) != Value; 3105f757f3fSDimitry Andric } 3115f757f3fSDimitry Andric }; 3125f757f3fSDimitry Andric 3135f757f3fSDimitry Andric template <bool Signed> 3145f757f3fSDimitry Andric inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, 3155f757f3fSDimitry Andric IntegralAP<Signed> I) { 3165f757f3fSDimitry Andric I.print(OS); 3175f757f3fSDimitry Andric return OS; 3185f757f3fSDimitry Andric } 3195f757f3fSDimitry Andric 320*0fca6ea1SDimitry Andric template <bool Signed> 321*0fca6ea1SDimitry Andric IntegralAP<Signed> getSwappedBytes(IntegralAP<Signed> F) { 322*0fca6ea1SDimitry Andric return F; 323*0fca6ea1SDimitry Andric } 324*0fca6ea1SDimitry Andric 3255f757f3fSDimitry Andric } // namespace interp 3265f757f3fSDimitry Andric } // namespace clang 3275f757f3fSDimitry Andric 3285f757f3fSDimitry Andric #endif 329