1048bc672STimm Baeder //===------- FixedPoint.h - Fixedd point types for the VM -------*- C++ -*-===// 2048bc672STimm Baeder // 3048bc672STimm Baeder // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4048bc672STimm Baeder // See https://llvm.org/LICENSE.txt for license information. 5048bc672STimm Baeder // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6048bc672STimm Baeder // 7048bc672STimm Baeder //===----------------------------------------------------------------------===// 8048bc672STimm Baeder 9048bc672STimm Baeder #ifndef LLVM_CLANG_AST_INTERP_FIXED_POINT_H 10048bc672STimm Baeder #define LLVM_CLANG_AST_INTERP_FIXED_POINT_H 11048bc672STimm Baeder 12048bc672STimm Baeder #include "clang/AST/APValue.h" 13048bc672STimm Baeder #include "clang/AST/ComparisonCategories.h" 14048bc672STimm Baeder #include "llvm/ADT/APFixedPoint.h" 15048bc672STimm Baeder 16048bc672STimm Baeder namespace clang { 17048bc672STimm Baeder namespace interp { 18048bc672STimm Baeder 19048bc672STimm Baeder using APInt = llvm::APInt; 20581c015eSTimm Baeder using APSInt = llvm::APSInt; 21048bc672STimm Baeder 22048bc672STimm Baeder /// Wrapper around fixed point types. 23048bc672STimm Baeder class FixedPoint final { 24048bc672STimm Baeder private: 25048bc672STimm Baeder llvm::APFixedPoint V; 26048bc672STimm Baeder 27048bc672STimm Baeder public: 28641b4d53STimm Baeder FixedPoint(llvm::APFixedPoint &&V) : V(std::move(V)) {} 29641b4d53STimm Baeder FixedPoint(llvm::APFixedPoint &V) : V(V) {} 30581c015eSTimm Baeder FixedPoint(APInt V, llvm::FixedPointSemantics Sem) : V(V, Sem) {} 31048bc672STimm Baeder // This needs to be default-constructible so llvm::endian::read works. 32048bc672STimm Baeder FixedPoint() 33048bc672STimm Baeder : V(APInt(0, 0ULL, false), 34048bc672STimm Baeder llvm::FixedPointSemantics(0, 0, false, false, false)) {} 35048bc672STimm Baeder 3695ce78b7STimm Baeder static FixedPoint zero(llvm::FixedPointSemantics Sem) { 376fd870bfSTimm Baeder return FixedPoint(APInt(Sem.getWidth(), 0ULL, Sem.isSigned()), Sem); 386fd870bfSTimm Baeder } 396fd870bfSTimm Baeder 4095ce78b7STimm Baeder static FixedPoint from(const APSInt &I, llvm::FixedPointSemantics Sem, 4195ce78b7STimm Baeder bool *Overflow) { 4295ce78b7STimm Baeder return FixedPoint(llvm::APFixedPoint::getFromIntValue(I, Sem, Overflow)); 4395ce78b7STimm Baeder } 4495ce78b7STimm Baeder static FixedPoint from(const llvm::APFloat &I, llvm::FixedPointSemantics Sem, 4595ce78b7STimm Baeder bool *Overflow) { 4695ce78b7STimm Baeder return FixedPoint(llvm::APFixedPoint::getFromFloatValue(I, Sem, Overflow)); 47048bc672STimm Baeder } 48048bc672STimm Baeder 4995ce78b7STimm Baeder operator bool() const { return V.getBoolValue(); } 50048bc672STimm Baeder void print(llvm::raw_ostream &OS) const { OS << V; } 51048bc672STimm Baeder 52048bc672STimm Baeder APValue toAPValue(const ASTContext &) const { return APValue(V); } 53defead4dSTimm Baeder APSInt toAPSInt(unsigned BitWidth = 0) const { return V.getValue(); } 54581c015eSTimm Baeder 55581c015eSTimm Baeder unsigned bitWidth() const { return V.getWidth(); } 56581c015eSTimm Baeder bool isSigned() const { return V.isSigned(); } 57defead4dSTimm Baeder bool isZero() const { return V.getValue().isZero(); } 58defead4dSTimm Baeder bool isNegative() const { return V.getValue().isNegative(); } 59defead4dSTimm Baeder bool isPositive() const { return V.getValue().isNonNegative(); } 60defead4dSTimm Baeder bool isMin() const { 615c811cccSTimm Baeder return V == llvm::APFixedPoint::getMin(V.getSemantics()); 62defead4dSTimm Baeder } 635c811cccSTimm Baeder bool isMinusOne() const { return V.isSigned() && V.getValue() == -1; } 64defead4dSTimm Baeder 65defead4dSTimm Baeder FixedPoint truncate(unsigned BitWidth) const { return *this; } 66048bc672STimm Baeder 67c2a37e41STimm Baeder FixedPoint toSemantics(const llvm::FixedPointSemantics &Sem, 68c2a37e41STimm Baeder bool *Overflow) const { 69c2a37e41STimm Baeder return FixedPoint(V.convert(Sem, Overflow)); 70c2a37e41STimm Baeder } 716f04e65cSTimm Baeder llvm::FixedPointSemantics getSemantics() const { return V.getSemantics(); } 72c2a37e41STimm Baeder 733a5b9da1STimm Baeder llvm::APFloat toFloat(const llvm::fltSemantics *Sem) const { 743a5b9da1STimm Baeder return V.convertToFloat(*Sem); 753a5b9da1STimm Baeder } 763a5b9da1STimm Baeder 7795ce78b7STimm Baeder llvm::APSInt toInt(unsigned BitWidth, bool Signed, bool *Overflow) const { 7895ce78b7STimm Baeder return V.convertToInt(BitWidth, Signed, Overflow); 7995ce78b7STimm Baeder } 8095ce78b7STimm Baeder 81defead4dSTimm Baeder std::string toDiagnosticString(const ASTContext &Ctx) const { 82defead4dSTimm Baeder return V.toString(); 83defead4dSTimm Baeder } 84defead4dSTimm Baeder 85048bc672STimm Baeder ComparisonCategoryResult compare(const FixedPoint &Other) const { 865c811cccSTimm Baeder int c = V.compare(Other.V); 875c811cccSTimm Baeder if (c == 0) 88048bc672STimm Baeder return ComparisonCategoryResult::Equal; 895c811cccSTimm Baeder else if (c < 0) 905c811cccSTimm Baeder return ComparisonCategoryResult::Less; 915c811cccSTimm Baeder return ComparisonCategoryResult::Greater; 92048bc672STimm Baeder } 93581c015eSTimm Baeder 94*b5c9cba3STimm Baeder size_t bytesToSerialize() const { 95*b5c9cba3STimm Baeder return sizeof(uint32_t) + (V.getValue().getBitWidth() / CHAR_BIT); 96*b5c9cba3STimm Baeder } 97*b5c9cba3STimm Baeder 98*b5c9cba3STimm Baeder void serialize(std::byte *Buff) const { 99*b5c9cba3STimm Baeder // Semantics followed by APInt. 100*b5c9cba3STimm Baeder uint32_t SemI = V.getSemantics().toOpaqueInt(); 101*b5c9cba3STimm Baeder std::memcpy(Buff, &SemI, sizeof(SemI)); 102*b5c9cba3STimm Baeder 103*b5c9cba3STimm Baeder llvm::APInt API = V.getValue(); 104*b5c9cba3STimm Baeder llvm::StoreIntToMemory(API, (uint8_t *)(Buff + sizeof(SemI)), 105*b5c9cba3STimm Baeder bitWidth() / 8); 106*b5c9cba3STimm Baeder } 107*b5c9cba3STimm Baeder 108*b5c9cba3STimm Baeder static FixedPoint deserialize(const std::byte *Buff) { 109*b5c9cba3STimm Baeder auto Sem = llvm::FixedPointSemantics::getFromOpaqueInt( 110*b5c9cba3STimm Baeder *reinterpret_cast<const uint32_t *>(Buff)); 111*b5c9cba3STimm Baeder unsigned BitWidth = Sem.getWidth(); 112*b5c9cba3STimm Baeder APInt I(BitWidth, 0ull, !Sem.isSigned()); 113*b5c9cba3STimm Baeder llvm::LoadIntFromMemory( 114*b5c9cba3STimm Baeder I, reinterpret_cast<const uint8_t *>(Buff + sizeof(uint32_t)), 115*b5c9cba3STimm Baeder BitWidth / CHAR_BIT); 116*b5c9cba3STimm Baeder 117*b5c9cba3STimm Baeder return FixedPoint(I, Sem); 118*b5c9cba3STimm Baeder } 119*b5c9cba3STimm Baeder 120581c015eSTimm Baeder static bool neg(const FixedPoint &A, FixedPoint *R) { 121581c015eSTimm Baeder bool Overflow = false; 122581c015eSTimm Baeder *R = FixedPoint(A.V.negate(&Overflow)); 123581c015eSTimm Baeder return Overflow; 124581c015eSTimm Baeder } 125defead4dSTimm Baeder 126defead4dSTimm Baeder static bool add(const FixedPoint A, const FixedPoint B, unsigned Bits, 127defead4dSTimm Baeder FixedPoint *R) { 128defead4dSTimm Baeder bool Overflow = false; 129defead4dSTimm Baeder *R = FixedPoint(A.V.add(B.V, &Overflow)); 130defead4dSTimm Baeder return Overflow; 131defead4dSTimm Baeder } 132defead4dSTimm Baeder static bool sub(const FixedPoint A, const FixedPoint B, unsigned Bits, 133defead4dSTimm Baeder FixedPoint *R) { 1345c811cccSTimm Baeder bool Overflow = false; 1355c811cccSTimm Baeder *R = FixedPoint(A.V.sub(B.V, &Overflow)); 1365c811cccSTimm Baeder return Overflow; 137defead4dSTimm Baeder } 138defead4dSTimm Baeder static bool mul(const FixedPoint A, const FixedPoint B, unsigned Bits, 139defead4dSTimm Baeder FixedPoint *R) { 1405c811cccSTimm Baeder bool Overflow = false; 1415c811cccSTimm Baeder *R = FixedPoint(A.V.mul(B.V, &Overflow)); 1425c811cccSTimm Baeder return Overflow; 143defead4dSTimm Baeder } 144defead4dSTimm Baeder static bool div(const FixedPoint A, const FixedPoint B, unsigned Bits, 145defead4dSTimm Baeder FixedPoint *R) { 1465c811cccSTimm Baeder bool Overflow = false; 1475c811cccSTimm Baeder *R = FixedPoint(A.V.div(B.V, &Overflow)); 1485c811cccSTimm Baeder return Overflow; 1495c811cccSTimm Baeder } 1506f04e65cSTimm Baeder 1516f04e65cSTimm Baeder static bool shiftLeft(const FixedPoint A, const FixedPoint B, unsigned OpBits, 1526f04e65cSTimm Baeder FixedPoint *R) { 1536f04e65cSTimm Baeder unsigned Amt = B.V.getValue().getLimitedValue(OpBits); 1546f04e65cSTimm Baeder bool Overflow; 1556f04e65cSTimm Baeder *R = FixedPoint(A.V.shl(Amt, &Overflow)); 1566f04e65cSTimm Baeder return Overflow; 1576f04e65cSTimm Baeder } 1586f04e65cSTimm Baeder static bool shiftRight(const FixedPoint A, const FixedPoint B, 1596f04e65cSTimm Baeder unsigned OpBits, FixedPoint *R) { 1606f04e65cSTimm Baeder unsigned Amt = B.V.getValue().getLimitedValue(OpBits); 1616f04e65cSTimm Baeder bool Overflow; 1626f04e65cSTimm Baeder *R = FixedPoint(A.V.shr(Amt, &Overflow)); 1636f04e65cSTimm Baeder return Overflow; 1646f04e65cSTimm Baeder } 1656f04e65cSTimm Baeder 1665c811cccSTimm Baeder static bool rem(const FixedPoint A, const FixedPoint B, unsigned Bits, 1675c811cccSTimm Baeder FixedPoint *R) { 1685c811cccSTimm Baeder llvm_unreachable("Rem doesn't exist for fixed point values"); 169defead4dSTimm Baeder return true; 170defead4dSTimm Baeder } 1715c811cccSTimm Baeder static bool bitAnd(const FixedPoint A, const FixedPoint B, unsigned Bits, 1725c811cccSTimm Baeder FixedPoint *R) { 1735c811cccSTimm Baeder return true; 1745c811cccSTimm Baeder } 1755c811cccSTimm Baeder static bool bitOr(const FixedPoint A, const FixedPoint B, unsigned Bits, 1765c811cccSTimm Baeder FixedPoint *R) { 1775c811cccSTimm Baeder return true; 1785c811cccSTimm Baeder } 1795c811cccSTimm Baeder static bool bitXor(const FixedPoint A, const FixedPoint B, unsigned Bits, 1805c811cccSTimm Baeder FixedPoint *R) { 1815c811cccSTimm Baeder return true; 1825c811cccSTimm Baeder } 1835c811cccSTimm Baeder 184defead4dSTimm Baeder static bool increment(const FixedPoint &A, FixedPoint *R) { return true; } 185defead4dSTimm Baeder static bool decrement(const FixedPoint &A, FixedPoint *R) { return true; } 186048bc672STimm Baeder }; 187048bc672STimm Baeder 188048bc672STimm Baeder inline FixedPoint getSwappedBytes(FixedPoint F) { return F; } 189048bc672STimm Baeder 190048bc672STimm Baeder inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, FixedPoint F) { 191048bc672STimm Baeder F.print(OS); 192048bc672STimm Baeder return OS; 193048bc672STimm Baeder } 194048bc672STimm Baeder 195048bc672STimm Baeder } // namespace interp 196048bc672STimm Baeder } // namespace clang 197048bc672STimm Baeder 198048bc672STimm Baeder #endif 199