1 //===------- FixedPoint.h - Fixedd point 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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLVM_CLANG_AST_INTERP_FIXED_POINT_H 10 #define LLVM_CLANG_AST_INTERP_FIXED_POINT_H 11 12 #include "clang/AST/APValue.h" 13 #include "clang/AST/ComparisonCategories.h" 14 #include "llvm/ADT/APFixedPoint.h" 15 16 namespace clang { 17 namespace interp { 18 19 using APInt = llvm::APInt; 20 using APSInt = llvm::APSInt; 21 22 /// Wrapper around fixed point types. 23 class FixedPoint final { 24 private: 25 llvm::APFixedPoint V; 26 27 public: 28 FixedPoint(llvm::APFixedPoint &&V) : V(std::move(V)) {} 29 FixedPoint(llvm::APFixedPoint &V) : V(V) {} 30 FixedPoint(APInt V, llvm::FixedPointSemantics Sem) : V(V, Sem) {} 31 // This needs to be default-constructible so llvm::endian::read works. 32 FixedPoint() 33 : V(APInt(0, 0ULL, false), 34 llvm::FixedPointSemantics(0, 0, false, false, false)) {} 35 36 static FixedPoint zero(llvm::FixedPointSemantics Sem) { 37 return FixedPoint(APInt(Sem.getWidth(), 0ULL, Sem.isSigned()), Sem); 38 } 39 40 static FixedPoint from(const APSInt &I, llvm::FixedPointSemantics Sem, 41 bool *Overflow) { 42 return FixedPoint(llvm::APFixedPoint::getFromIntValue(I, Sem, Overflow)); 43 } 44 static FixedPoint from(const llvm::APFloat &I, llvm::FixedPointSemantics Sem, 45 bool *Overflow) { 46 return FixedPoint(llvm::APFixedPoint::getFromFloatValue(I, Sem, Overflow)); 47 } 48 49 operator bool() const { return V.getBoolValue(); } 50 void print(llvm::raw_ostream &OS) const { OS << V; } 51 52 APValue toAPValue(const ASTContext &) const { return APValue(V); } 53 APSInt toAPSInt(unsigned BitWidth = 0) const { return V.getValue(); } 54 55 unsigned bitWidth() const { return V.getWidth(); } 56 bool isSigned() const { return V.isSigned(); } 57 bool isZero() const { return V.getValue().isZero(); } 58 bool isNegative() const { return V.getValue().isNegative(); } 59 bool isPositive() const { return V.getValue().isNonNegative(); } 60 bool isMin() const { 61 return V == llvm::APFixedPoint::getMin(V.getSemantics()); 62 } 63 bool isMinusOne() const { return V.isSigned() && V.getValue() == -1; } 64 65 FixedPoint truncate(unsigned BitWidth) const { return *this; } 66 67 FixedPoint toSemantics(const llvm::FixedPointSemantics &Sem, 68 bool *Overflow) const { 69 return FixedPoint(V.convert(Sem, Overflow)); 70 } 71 llvm::FixedPointSemantics getSemantics() const { return V.getSemantics(); } 72 73 llvm::APFloat toFloat(const llvm::fltSemantics *Sem) const { 74 return V.convertToFloat(*Sem); 75 } 76 77 llvm::APSInt toInt(unsigned BitWidth, bool Signed, bool *Overflow) const { 78 return V.convertToInt(BitWidth, Signed, Overflow); 79 } 80 81 std::string toDiagnosticString(const ASTContext &Ctx) const { 82 return V.toString(); 83 } 84 85 ComparisonCategoryResult compare(const FixedPoint &Other) const { 86 int c = V.compare(Other.V); 87 if (c == 0) 88 return ComparisonCategoryResult::Equal; 89 else if (c < 0) 90 return ComparisonCategoryResult::Less; 91 return ComparisonCategoryResult::Greater; 92 } 93 94 size_t bytesToSerialize() const { 95 return sizeof(uint32_t) + (V.getValue().getBitWidth() / CHAR_BIT); 96 } 97 98 void serialize(std::byte *Buff) const { 99 // Semantics followed by APInt. 100 uint32_t SemI = V.getSemantics().toOpaqueInt(); 101 std::memcpy(Buff, &SemI, sizeof(SemI)); 102 103 llvm::APInt API = V.getValue(); 104 llvm::StoreIntToMemory(API, (uint8_t *)(Buff + sizeof(SemI)), 105 bitWidth() / 8); 106 } 107 108 static FixedPoint deserialize(const std::byte *Buff) { 109 auto Sem = llvm::FixedPointSemantics::getFromOpaqueInt( 110 *reinterpret_cast<const uint32_t *>(Buff)); 111 unsigned BitWidth = Sem.getWidth(); 112 APInt I(BitWidth, 0ull, !Sem.isSigned()); 113 llvm::LoadIntFromMemory( 114 I, reinterpret_cast<const uint8_t *>(Buff + sizeof(uint32_t)), 115 BitWidth / CHAR_BIT); 116 117 return FixedPoint(I, Sem); 118 } 119 120 static bool neg(const FixedPoint &A, FixedPoint *R) { 121 bool Overflow = false; 122 *R = FixedPoint(A.V.negate(&Overflow)); 123 return Overflow; 124 } 125 126 static bool add(const FixedPoint A, const FixedPoint B, unsigned Bits, 127 FixedPoint *R) { 128 bool Overflow = false; 129 *R = FixedPoint(A.V.add(B.V, &Overflow)); 130 return Overflow; 131 } 132 static bool sub(const FixedPoint A, const FixedPoint B, unsigned Bits, 133 FixedPoint *R) { 134 bool Overflow = false; 135 *R = FixedPoint(A.V.sub(B.V, &Overflow)); 136 return Overflow; 137 } 138 static bool mul(const FixedPoint A, const FixedPoint B, unsigned Bits, 139 FixedPoint *R) { 140 bool Overflow = false; 141 *R = FixedPoint(A.V.mul(B.V, &Overflow)); 142 return Overflow; 143 } 144 static bool div(const FixedPoint A, const FixedPoint B, unsigned Bits, 145 FixedPoint *R) { 146 bool Overflow = false; 147 *R = FixedPoint(A.V.div(B.V, &Overflow)); 148 return Overflow; 149 } 150 151 static bool shiftLeft(const FixedPoint A, const FixedPoint B, unsigned OpBits, 152 FixedPoint *R) { 153 unsigned Amt = B.V.getValue().getLimitedValue(OpBits); 154 bool Overflow; 155 *R = FixedPoint(A.V.shl(Amt, &Overflow)); 156 return Overflow; 157 } 158 static bool shiftRight(const FixedPoint A, const FixedPoint B, 159 unsigned OpBits, FixedPoint *R) { 160 unsigned Amt = B.V.getValue().getLimitedValue(OpBits); 161 bool Overflow; 162 *R = FixedPoint(A.V.shr(Amt, &Overflow)); 163 return Overflow; 164 } 165 166 static bool rem(const FixedPoint A, const FixedPoint B, unsigned Bits, 167 FixedPoint *R) { 168 llvm_unreachable("Rem doesn't exist for fixed point values"); 169 return true; 170 } 171 static bool bitAnd(const FixedPoint A, const FixedPoint B, unsigned Bits, 172 FixedPoint *R) { 173 return true; 174 } 175 static bool bitOr(const FixedPoint A, const FixedPoint B, unsigned Bits, 176 FixedPoint *R) { 177 return true; 178 } 179 static bool bitXor(const FixedPoint A, const FixedPoint B, unsigned Bits, 180 FixedPoint *R) { 181 return true; 182 } 183 184 static bool increment(const FixedPoint &A, FixedPoint *R) { return true; } 185 static bool decrement(const FixedPoint &A, FixedPoint *R) { return true; } 186 }; 187 188 inline FixedPoint getSwappedBytes(FixedPoint F) { return F; } 189 190 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, FixedPoint F) { 191 F.print(OS); 192 return OS; 193 } 194 195 } // namespace interp 196 } // namespace clang 197 198 #endif 199