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 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(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 void bitcastToMemory(std::byte *Buff) const { 139 llvm::APInt API = F.bitcastToAPInt(); 140 llvm::StoreIntToMemory(API, (uint8_t *)Buff, bitWidth() / 8); 141 } 142 143 // === Serialization support === 144 size_t bytesToSerialize() const { 145 return sizeof(llvm::fltSemantics *) + 146 (APFloat::semanticsSizeInBits(F.getSemantics()) / 8); 147 } 148 149 void serialize(std::byte *Buff) const { 150 // Semantics followed by an APInt. 151 *reinterpret_cast<const llvm::fltSemantics **>(Buff) = &F.getSemantics(); 152 153 llvm::APInt API = F.bitcastToAPInt(); 154 llvm::StoreIntToMemory(API, (uint8_t *)(Buff + sizeof(void *)), 155 bitWidth() / 8); 156 } 157 158 static Floating deserialize(const std::byte *Buff) { 159 const llvm::fltSemantics *Sem; 160 std::memcpy((void *)&Sem, Buff, sizeof(void *)); 161 return bitcastFromMemory(Buff + sizeof(void *), *Sem); 162 } 163 164 static Floating abs(const Floating &F) { 165 APFloat V = F.F; 166 if (V.isNegative()) 167 V.changeSign(); 168 return Floating(V); 169 } 170 171 // ------- 172 173 static APFloat::opStatus add(const Floating &A, const Floating &B, 174 llvm::RoundingMode RM, Floating *R) { 175 *R = Floating(A.F); 176 return R->F.add(B.F, RM); 177 } 178 179 static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM, 180 Floating *R) { 181 APFloat One(A.F.getSemantics(), 1); 182 *R = Floating(A.F); 183 return R->F.add(One, RM); 184 } 185 186 static APFloat::opStatus sub(const Floating &A, const Floating &B, 187 llvm::RoundingMode RM, Floating *R) { 188 *R = Floating(A.F); 189 return R->F.subtract(B.F, RM); 190 } 191 192 static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM, 193 Floating *R) { 194 APFloat One(A.F.getSemantics(), 1); 195 *R = Floating(A.F); 196 return R->F.subtract(One, RM); 197 } 198 199 static APFloat::opStatus mul(const Floating &A, const Floating &B, 200 llvm::RoundingMode RM, Floating *R) { 201 *R = Floating(A.F); 202 return R->F.multiply(B.F, RM); 203 } 204 205 static APFloat::opStatus div(const Floating &A, const Floating &B, 206 llvm::RoundingMode RM, Floating *R) { 207 *R = Floating(A.F); 208 return R->F.divide(B.F, RM); 209 } 210 211 static bool neg(const Floating &A, Floating *R) { 212 *R = -A; 213 return false; 214 } 215 }; 216 217 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Floating F); 218 Floating getSwappedBytes(Floating F); 219 220 } // namespace interp 221 } // namespace clang 222 223 #endif 224