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, llvm::APFloat::rmTowardZero, &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(*Sem, RM, &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(&Other.F.getSemantics(), RM); 67 } 68 69 APSInt toAPSInt(unsigned NumBits = 0) const { 70 return APSInt(F.bitcastToAPInt()); 71 } 72 APValue toAPValue() 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(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 isPositive() const { return !F.isNegative(); } 91 bool isZero() const { return F.isZero(); } 92 bool isNonZero() const { return F.isNonZero(); } 93 bool isMin() const { return F.isSmallest(); } 94 bool isMinusOne() const { return F.isExactlyValue(-1.0); } 95 bool isNan() const { return F.isNaN(); } 96 bool isSignaling() const { return F.isSignaling(); } 97 bool isInf() const { return F.isInfinity(); } 98 bool isFinite() const { return F.isFinite(); } 99 bool isNormal() const { return F.isNormal(); } 100 bool isDenormal() const { return F.isDenormal(); } 101 llvm::FPClassTest classify() const { return F.classify(); } 102 APFloat::fltCategory getCategory() const { return F.getCategory(); } 103 104 ComparisonCategoryResult compare(const Floating &RHS) const { 105 llvm::APFloatBase::cmpResult CmpRes = F.compare(RHS.F); 106 switch (CmpRes) { 107 case llvm::APFloatBase::cmpLessThan: 108 return ComparisonCategoryResult::Less; 109 case llvm::APFloatBase::cmpEqual: 110 return ComparisonCategoryResult::Equal; 111 case llvm::APFloatBase::cmpGreaterThan: 112 return ComparisonCategoryResult::Greater; 113 case llvm::APFloatBase::cmpUnordered: 114 return ComparisonCategoryResult::Unordered; 115 } 116 llvm_unreachable("Inavlid cmpResult value"); 117 } 118 119 static APFloat::opStatus fromIntegral(APSInt Val, 120 const llvm::fltSemantics &Sem, 121 llvm::RoundingMode RM, 122 Floating &Result) { 123 APFloat F = APFloat(Sem); 124 APFloat::opStatus Status = F.convertFromAPInt(Val, Val.isSigned(), RM); 125 Result = Floating(F); 126 return Status; 127 } 128 129 static Floating bitcastFromMemory(const std::byte *Buff, 130 const llvm::fltSemantics &Sem) { 131 size_t Size = APFloat::semanticsSizeInBits(Sem); 132 llvm::APInt API(Size, true); 133 llvm::LoadIntFromMemory(API, (const uint8_t *)Buff, Size / 8); 134 135 return Floating(APFloat(Sem, API)); 136 } 137 138 // === Serialization support === 139 size_t bytesToSerialize() const { 140 return sizeof(llvm::fltSemantics *) + 141 (APFloat::semanticsSizeInBits(F.getSemantics()) / 8); 142 } 143 144 void serialize(std::byte *Buff) const { 145 // Semantics followed by an APInt. 146 *reinterpret_cast<const llvm::fltSemantics **>(Buff) = &F.getSemantics(); 147 148 llvm::APInt API = F.bitcastToAPInt(); 149 llvm::StoreIntToMemory(API, (uint8_t *)(Buff + sizeof(void *)), 150 bitWidth() / 8); 151 } 152 153 static Floating deserialize(const std::byte *Buff) { 154 const llvm::fltSemantics *Sem; 155 std::memcpy((void *)&Sem, Buff, sizeof(void *)); 156 return bitcastFromMemory(Buff + sizeof(void *), *Sem); 157 } 158 159 static Floating abs(const Floating &F) { 160 APFloat V = F.F; 161 if (V.isNegative()) 162 V.changeSign(); 163 return Floating(V); 164 } 165 166 // ------- 167 168 static APFloat::opStatus add(const Floating &A, const Floating &B, 169 llvm::RoundingMode RM, Floating *R) { 170 *R = Floating(A.F); 171 return R->F.add(B.F, RM); 172 } 173 174 static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM, 175 Floating *R) { 176 APFloat One(A.F.getSemantics(), 1); 177 *R = Floating(A.F); 178 return R->F.add(One, RM); 179 } 180 181 static APFloat::opStatus sub(const Floating &A, const Floating &B, 182 llvm::RoundingMode RM, Floating *R) { 183 *R = Floating(A.F); 184 return R->F.subtract(B.F, RM); 185 } 186 187 static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM, 188 Floating *R) { 189 APFloat One(A.F.getSemantics(), 1); 190 *R = Floating(A.F); 191 return R->F.subtract(One, RM); 192 } 193 194 static APFloat::opStatus mul(const Floating &A, const Floating &B, 195 llvm::RoundingMode RM, Floating *R) { 196 *R = Floating(A.F); 197 return R->F.multiply(B.F, RM); 198 } 199 200 static APFloat::opStatus div(const Floating &A, const Floating &B, 201 llvm::RoundingMode RM, Floating *R) { 202 *R = Floating(A.F); 203 return R->F.divide(B.F, RM); 204 } 205 206 static bool neg(const Floating &A, Floating *R) { 207 *R = -A; 208 return false; 209 } 210 }; 211 212 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Floating F); 213 Floating getSwappedBytes(Floating F); 214 215 } // namespace interp 216 } // namespace clang 217 218 #endif 219