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 // XXX This is just a debugging help. Setting this to 1 will heap-allocate ALL 21 // floating values. 22 #define ALLOCATE_ALL 0 23 24 namespace clang { 25 namespace interp { 26 27 using APFloat = llvm::APFloat; 28 using APSInt = llvm::APSInt; 29 using APInt = llvm::APInt; 30 31 /// If a Floating is constructed from Memory, it DOES NOT OWN THAT MEMORY. 32 /// It will NOT copy the memory (unless, of course, copy() is called) and it 33 /// won't alllocate anything. The allocation should happen via InterpState or 34 /// Program. 35 class Floating final { 36 private: 37 union { 38 uint64_t Val = 0; 39 uint64_t *Memory; 40 }; 41 llvm::APFloatBase::Semantics Semantics; 42 43 APFloat getValue() const { 44 unsigned BitWidth = bitWidth(); 45 if (singleWord()) 46 return APFloat(getSemantics(), APInt(BitWidth, Val)); 47 unsigned NumWords = numWords(); 48 return APFloat(getSemantics(), APInt(BitWidth, NumWords, Memory)); 49 } 50 51 public: 52 Floating() = default; 53 Floating(llvm::APFloatBase::Semantics Semantics) 54 : Val(0), Semantics(Semantics) {} 55 Floating(const APFloat &F) { 56 57 Semantics = llvm::APFloatBase::SemanticsToEnum(F.getSemantics()); 58 this->copy(F); 59 } 60 Floating(uint64_t *Memory, llvm::APFloatBase::Semantics Semantics) 61 : Memory(Memory), Semantics(Semantics) {} 62 63 APFloat getAPFloat() const { return getValue(); } 64 65 bool operator<(Floating RHS) const { return getValue() < RHS.getValue(); } 66 bool operator>(Floating RHS) const { return getValue() > RHS.getValue(); } 67 bool operator<=(Floating RHS) const { return getValue() <= RHS.getValue(); } 68 bool operator>=(Floating RHS) const { return getValue() >= RHS.getValue(); } 69 70 APFloat::opStatus convertToInteger(APSInt &Result) const { 71 bool IsExact; 72 return getValue().convertToInteger(Result, llvm::APFloat::rmTowardZero, 73 &IsExact); 74 } 75 76 void toSemantics(const llvm::fltSemantics *Sem, llvm::RoundingMode RM, 77 Floating *Result) const { 78 APFloat Copy = getValue(); 79 bool LosesInfo; 80 Copy.convert(*Sem, RM, &LosesInfo); 81 (void)LosesInfo; 82 Result->copy(Copy); 83 } 84 85 APSInt toAPSInt(unsigned NumBits = 0) const { 86 return APSInt(getValue().bitcastToAPInt()); 87 } 88 APValue toAPValue(const ASTContext &) const { return APValue(getValue()); } 89 void print(llvm::raw_ostream &OS) const { 90 // Can't use APFloat::print() since it appends a newline. 91 SmallVector<char, 16> Buffer; 92 getValue().toString(Buffer); 93 OS << Buffer; 94 } 95 std::string toDiagnosticString(const ASTContext &Ctx) const { 96 std::string NameStr; 97 llvm::raw_string_ostream OS(NameStr); 98 print(OS); 99 return NameStr; 100 } 101 102 unsigned bitWidth() const { 103 return llvm::APFloatBase::semanticsSizeInBits(getSemantics()); 104 } 105 unsigned numWords() const { return llvm::APInt::getNumWords(bitWidth()); } 106 bool singleWord() const { 107 #if ALLOCATE_ALL 108 return false; 109 #endif 110 return numWords() == 1; 111 } 112 static bool singleWord(const llvm::fltSemantics &Sem) { 113 #if ALLOCATE_ALL 114 return false; 115 #endif 116 return APInt::getNumWords(llvm::APFloatBase::getSizeInBits(Sem)) == 1; 117 } 118 const llvm::fltSemantics &getSemantics() const { 119 return llvm::APFloatBase::EnumToSemantics(Semantics); 120 } 121 122 void copy(const APFloat &F) { 123 if (singleWord()) { 124 Val = F.bitcastToAPInt().getZExtValue(); 125 } else { 126 assert(Memory); 127 std::memcpy(Memory, F.bitcastToAPInt().getRawData(), 128 numWords() * sizeof(uint64_t)); 129 } 130 } 131 132 void take(uint64_t *NewMemory) { 133 if (singleWord()) 134 return; 135 136 if (Memory) 137 std::memcpy(NewMemory, Memory, numWords() * sizeof(uint64_t)); 138 Memory = NewMemory; 139 } 140 141 bool isSigned() const { return true; } 142 bool isNegative() const { return getValue().isNegative(); } 143 bool isZero() const { return getValue().isZero(); } 144 bool isNonZero() const { return getValue().isNonZero(); } 145 bool isMin() const { return getValue().isSmallest(); } 146 bool isMinusOne() const { return getValue().isExactlyValue(-1.0); } 147 bool isNan() const { return getValue().isNaN(); } 148 bool isSignaling() const { return getValue().isSignaling(); } 149 bool isInf() const { return getValue().isInfinity(); } 150 bool isFinite() const { return getValue().isFinite(); } 151 bool isNormal() const { return getValue().isNormal(); } 152 bool isDenormal() const { return getValue().isDenormal(); } 153 llvm::FPClassTest classify() const { return getValue().classify(); } 154 APFloat::fltCategory getCategory() const { return getValue().getCategory(); } 155 156 ComparisonCategoryResult compare(const Floating &RHS) const { 157 llvm::APFloatBase::cmpResult CmpRes = getValue().compare(RHS.getValue()); 158 switch (CmpRes) { 159 case llvm::APFloatBase::cmpLessThan: 160 return ComparisonCategoryResult::Less; 161 case llvm::APFloatBase::cmpEqual: 162 return ComparisonCategoryResult::Equal; 163 case llvm::APFloatBase::cmpGreaterThan: 164 return ComparisonCategoryResult::Greater; 165 case llvm::APFloatBase::cmpUnordered: 166 return ComparisonCategoryResult::Unordered; 167 } 168 llvm_unreachable("Inavlid cmpResult value"); 169 } 170 171 static APFloat::opStatus fromIntegral(APSInt Val, 172 const llvm::fltSemantics &Sem, 173 llvm::RoundingMode RM, 174 Floating *Result) { 175 APFloat F = APFloat(Sem); 176 APFloat::opStatus Status = F.convertFromAPInt(Val, Val.isSigned(), RM); 177 Result->copy(F); 178 return Status; 179 } 180 181 static void bitcastFromMemory(const std::byte *Buff, 182 const llvm::fltSemantics &Sem, 183 Floating *Result) { 184 size_t Size = APFloat::semanticsSizeInBits(Sem); 185 llvm::APInt API(Size, true); 186 llvm::LoadIntFromMemory(API, (const uint8_t *)Buff, Size / 8); 187 Result->copy(APFloat(Sem, API)); 188 } 189 190 void bitcastToMemory(std::byte *Buff) const { 191 llvm::APInt API = getValue().bitcastToAPInt(); 192 llvm::StoreIntToMemory(API, (uint8_t *)Buff, bitWidth() / 8); 193 } 194 195 // === Serialization support === 196 size_t bytesToSerialize() const { 197 return sizeof(Semantics) + (numWords() * sizeof(uint64_t)); 198 } 199 200 void serialize(std::byte *Buff) const { 201 std::memcpy(Buff, &Semantics, sizeof(Semantics)); 202 if (singleWord()) { 203 std::memcpy(Buff + sizeof(Semantics), &Val, sizeof(uint64_t)); 204 } else { 205 std::memcpy(Buff + sizeof(Semantics), Memory, 206 numWords() * sizeof(uint64_t)); 207 } 208 } 209 210 static llvm::APFloatBase::Semantics 211 deserializeSemantics(const std::byte *Buff) { 212 return *reinterpret_cast<const llvm::APFloatBase::Semantics *>(Buff); 213 } 214 215 static void deserialize(const std::byte *Buff, Floating *Result) { 216 llvm::APFloatBase::Semantics Semantics; 217 std::memcpy(&Semantics, Buff, sizeof(Semantics)); 218 219 unsigned BitWidth = llvm::APFloat::semanticsSizeInBits( 220 llvm::APFloatBase::EnumToSemantics(Semantics)); 221 unsigned NumWords = llvm::APInt::getNumWords(BitWidth); 222 223 Result->Semantics = Semantics; 224 if (NumWords == 1 && !ALLOCATE_ALL) { 225 std::memcpy(&Result->Val, Buff + sizeof(Semantics), sizeof(uint64_t)); 226 } else { 227 assert(Result->Memory); 228 std::memcpy(Result->Memory, Buff + sizeof(Semantics), 229 NumWords * sizeof(uint64_t)); 230 } 231 } 232 233 // ------- 234 235 static APFloat::opStatus add(const Floating &A, const Floating &B, 236 llvm::RoundingMode RM, Floating *R) { 237 APFloat LHS = A.getValue(); 238 APFloat RHS = B.getValue(); 239 240 auto Status = LHS.add(RHS, RM); 241 R->copy(LHS); 242 return Status; 243 } 244 245 static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM, 246 Floating *R) { 247 APFloat One(A.getSemantics(), 1); 248 APFloat LHS = A.getValue(); 249 250 auto Status = LHS.add(One, RM); 251 R->copy(LHS); 252 return Status; 253 } 254 255 static APFloat::opStatus sub(const Floating &A, const Floating &B, 256 llvm::RoundingMode RM, Floating *R) { 257 APFloat LHS = A.getValue(); 258 APFloat RHS = B.getValue(); 259 260 auto Status = LHS.subtract(RHS, RM); 261 R->copy(LHS); 262 return Status; 263 } 264 265 static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM, 266 Floating *R) { 267 APFloat One(A.getSemantics(), 1); 268 APFloat LHS = A.getValue(); 269 270 auto Status = LHS.subtract(One, RM); 271 R->copy(LHS); 272 return Status; 273 } 274 275 static APFloat::opStatus mul(const Floating &A, const Floating &B, 276 llvm::RoundingMode RM, Floating *R) { 277 278 APFloat LHS = A.getValue(); 279 APFloat RHS = B.getValue(); 280 281 auto Status = LHS.multiply(RHS, RM); 282 R->copy(LHS); 283 return Status; 284 } 285 286 static APFloat::opStatus div(const Floating &A, const Floating &B, 287 llvm::RoundingMode RM, Floating *R) { 288 APFloat LHS = A.getValue(); 289 APFloat RHS = B.getValue(); 290 291 auto Status = LHS.divide(RHS, RM); 292 R->copy(LHS); 293 return Status; 294 } 295 296 static bool neg(const Floating &A, Floating *R) { 297 R->copy(-A.getValue()); 298 return false; 299 } 300 }; 301 302 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Floating F); 303 Floating getSwappedBytes(Floating F); 304 305 } // namespace interp 306 } // namespace clang 307 308 #endif 309