| 1 | //===--- Floating.h - Types for the constexpr 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 | // Defines the VM types and helpers operating on types. |
| 10 | // |
| 11 | //===----------------------------------------------------------------------===// |
| 12 | |
| 13 | #ifndef LLVM_CLANG_AST_INTERP_FLOATING_H |
| 14 | #define LLVM_CLANG_AST_INTERP_FLOATING_H |
| 15 | |
| 16 | #include "Primitives.h" |
| 17 | #include "clang/AST/APValue.h" |
| 18 | #include "llvm/ADT/APFloat.h" |
| 19 | |
| 20 | namespace clang { |
| 21 | namespace interp { |
| 22 | |
| 23 | using APFloat = llvm::APFloat; |
| 24 | using APSInt = llvm::APSInt; |
| 25 | |
| 26 | class Floating final { |
| 27 | private: |
| 28 | // The underlying value storage. |
| 29 | APFloat F; |
| 30 | |
| 31 | public: |
| 32 | /// Zero-initializes a Floating. |
| 33 | Floating() : F(0.0f) {} |
| 34 | Floating(const APFloat &F) : F(F) {} |
| 35 | |
| 36 | // Static constructors for special floating point values. |
| 37 | static Floating getInf(const llvm::fltSemantics &Sem) { |
| 38 | return Floating(APFloat::getInf(Sem)); |
| 39 | } |
| 40 | const APFloat &getAPFloat() const { return F; } |
| 41 | |
| 42 | bool operator<(Floating RHS) const { return F < RHS.F; } |
| 43 | bool operator>(Floating RHS) const { return F > RHS.F; } |
| 44 | bool operator<=(Floating RHS) const { return F <= RHS.F; } |
| 45 | bool operator>=(Floating RHS) const { return F >= RHS.F; } |
| 46 | bool operator==(Floating RHS) const { return F == RHS.F; } |
| 47 | bool operator!=(Floating RHS) const { return F != RHS.F; } |
| 48 | Floating operator-() const { return Floating(-F); } |
| 49 | |
| 50 | APFloat::opStatus convertToInteger(APSInt &Result) const { |
| 51 | bool IsExact; |
| 52 | return F.convertToInteger(Result, RM: llvm::APFloat::rmTowardZero, IsExact: &IsExact); |
| 53 | } |
| 54 | |
| 55 | Floating toSemantics(const llvm::fltSemantics *Sem, |
| 56 | llvm::RoundingMode RM) const { |
| 57 | APFloat Copy = F; |
| 58 | bool LosesInfo; |
| 59 | Copy.convert(ToSemantics: *Sem, RM, losesInfo: &LosesInfo); |
| 60 | (void)LosesInfo; |
| 61 | return Floating(Copy); |
| 62 | } |
| 63 | |
| 64 | /// Convert this Floating to one with the same semantics as \Other. |
| 65 | Floating toSemantics(const Floating &Other, llvm::RoundingMode RM) const { |
| 66 | return toSemantics(Sem: &Other.F.getSemantics(), RM); |
| 67 | } |
| 68 | |
| 69 | APSInt toAPSInt(unsigned NumBits = 0) const { |
| 70 | return APSInt(F.bitcastToAPInt()); |
| 71 | } |
| 72 | APValue toAPValue(const ASTContext &) const { return APValue(F); } |
| 73 | void print(llvm::raw_ostream &OS) const { |
| 74 | // Can't use APFloat::print() since it appends a newline. |
| 75 | SmallVector<char, 16> Buffer; |
| 76 | F.toString(Str&: Buffer); |
| 77 | OS << Buffer; |
| 78 | } |
| 79 | std::string toDiagnosticString(const ASTContext &Ctx) const { |
| 80 | std::string NameStr; |
| 81 | llvm::raw_string_ostream OS(NameStr); |
| 82 | print(OS); |
| 83 | return NameStr; |
| 84 | } |
| 85 | |
| 86 | unsigned bitWidth() const { return F.semanticsSizeInBits(F.getSemantics()); } |
| 87 | |
| 88 | bool isSigned() const { return true; } |
| 89 | bool isNegative() const { return F.isNegative(); } |
| 90 | bool isZero() const { return F.isZero(); } |
| 91 | bool isNonZero() const { return F.isNonZero(); } |
| 92 | bool isMin() const { return F.isSmallest(); } |
| 93 | bool isMinusOne() const { return F.isExactlyValue(V: -1.0); } |
| 94 | bool isNan() const { return F.isNaN(); } |
| 95 | bool isSignaling() const { return F.isSignaling(); } |
| 96 | bool isInf() const { return F.isInfinity(); } |
| 97 | bool isFinite() const { return F.isFinite(); } |
| 98 | bool isNormal() const { return F.isNormal(); } |
| 99 | bool isDenormal() const { return F.isDenormal(); } |
| 100 | llvm::FPClassTest classify() const { return F.classify(); } |
| 101 | APFloat::fltCategory getCategory() const { return F.getCategory(); } |
| 102 | |
| 103 | ComparisonCategoryResult compare(const Floating &RHS) const { |
| 104 | llvm::APFloatBase::cmpResult CmpRes = F.compare(RHS: RHS.F); |
| 105 | switch (CmpRes) { |
| 106 | case llvm::APFloatBase::cmpLessThan: |
| 107 | return ComparisonCategoryResult::Less; |
| 108 | case llvm::APFloatBase::cmpEqual: |
| 109 | return ComparisonCategoryResult::Equal; |
| 110 | case llvm::APFloatBase::cmpGreaterThan: |
| 111 | return ComparisonCategoryResult::Greater; |
| 112 | case llvm::APFloatBase::cmpUnordered: |
| 113 | return ComparisonCategoryResult::Unordered; |
| 114 | } |
| 115 | llvm_unreachable("Inavlid cmpResult value" ); |
| 116 | } |
| 117 | |
| 118 | static APFloat::opStatus fromIntegral(APSInt Val, |
| 119 | const llvm::fltSemantics &Sem, |
| 120 | llvm::RoundingMode RM, |
| 121 | Floating &Result) { |
| 122 | APFloat F = APFloat(Sem); |
| 123 | APFloat::opStatus Status = F.convertFromAPInt(Input: Val, IsSigned: Val.isSigned(), RM); |
| 124 | Result = Floating(F); |
| 125 | return Status; |
| 126 | } |
| 127 | |
| 128 | static Floating bitcastFromMemory(const std::byte *Buff, |
| 129 | const llvm::fltSemantics &Sem) { |
| 130 | size_t Size = APFloat::semanticsSizeInBits(Sem); |
| 131 | llvm::APInt API(Size, true); |
| 132 | llvm::LoadIntFromMemory(IntVal&: API, Src: (const uint8_t *)Buff, LoadBytes: Size / 8); |
| 133 | |
| 134 | return Floating(APFloat(Sem, API)); |
| 135 | } |
| 136 | |
| 137 | void bitcastToMemory(std::byte *Buff) const { |
| 138 | llvm::APInt API = F.bitcastToAPInt(); |
| 139 | llvm::StoreIntToMemory(IntVal: API, Dst: (uint8_t *)Buff, StoreBytes: bitWidth() / 8); |
| 140 | } |
| 141 | |
| 142 | // === Serialization support === |
| 143 | size_t bytesToSerialize() const { |
| 144 | return sizeof(llvm::fltSemantics *) + |
| 145 | (APFloat::semanticsSizeInBits(F.getSemantics()) / 8); |
| 146 | } |
| 147 | |
| 148 | void serialize(std::byte *Buff) const { |
| 149 | // Semantics followed by an APInt. |
| 150 | *reinterpret_cast<const llvm::fltSemantics **>(Buff) = &F.getSemantics(); |
| 151 | |
| 152 | llvm::APInt API = F.bitcastToAPInt(); |
| 153 | llvm::StoreIntToMemory(IntVal: API, Dst: (uint8_t *)(Buff + sizeof(void *)), |
| 154 | StoreBytes: bitWidth() / 8); |
| 155 | } |
| 156 | |
| 157 | static Floating deserialize(const std::byte *Buff) { |
| 158 | const llvm::fltSemantics *Sem; |
| 159 | std::memcpy(dest: (void *)&Sem, src: Buff, n: sizeof(void *)); |
| 160 | return bitcastFromMemory(Buff: Buff + sizeof(void *), Sem: *Sem); |
| 161 | } |
| 162 | |
| 163 | static Floating abs(const Floating &F) { |
| 164 | APFloat V = F.F; |
| 165 | if (V.isNegative()) |
| 166 | V.changeSign(); |
| 167 | return Floating(V); |
| 168 | } |
| 169 | |
| 170 | // ------- |
| 171 | |
| 172 | static APFloat::opStatus add(const Floating &A, const Floating &B, |
| 173 | llvm::RoundingMode RM, Floating *R) { |
| 174 | *R = Floating(A.F); |
| 175 | return R->F.add(RHS: B.F, RM); |
| 176 | } |
| 177 | |
| 178 | static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM, |
| 179 | Floating *R) { |
| 180 | APFloat One(A.F.getSemantics(), 1); |
| 181 | *R = Floating(A.F); |
| 182 | return R->F.add(RHS: One, RM); |
| 183 | } |
| 184 | |
| 185 | static APFloat::opStatus sub(const Floating &A, const Floating &B, |
| 186 | llvm::RoundingMode RM, Floating *R) { |
| 187 | *R = Floating(A.F); |
| 188 | return R->F.subtract(RHS: B.F, RM); |
| 189 | } |
| 190 | |
| 191 | static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM, |
| 192 | Floating *R) { |
| 193 | APFloat One(A.F.getSemantics(), 1); |
| 194 | *R = Floating(A.F); |
| 195 | return R->F.subtract(RHS: One, RM); |
| 196 | } |
| 197 | |
| 198 | static APFloat::opStatus mul(const Floating &A, const Floating &B, |
| 199 | llvm::RoundingMode RM, Floating *R) { |
| 200 | *R = Floating(A.F); |
| 201 | return R->F.multiply(RHS: B.F, RM); |
| 202 | } |
| 203 | |
| 204 | static APFloat::opStatus div(const Floating &A, const Floating &B, |
| 205 | llvm::RoundingMode RM, Floating *R) { |
| 206 | *R = Floating(A.F); |
| 207 | return R->F.divide(RHS: B.F, RM); |
| 208 | } |
| 209 | |
| 210 | static bool neg(const Floating &A, Floating *R) { |
| 211 | *R = -A; |
| 212 | return false; |
| 213 | } |
| 214 | }; |
| 215 | |
| 216 | llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Floating F); |
| 217 | Floating getSwappedBytes(Floating F); |
| 218 | |
| 219 | } // namespace interp |
| 220 | } // namespace clang |
| 221 | |
| 222 | #endif |
| 223 | |