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 getValue()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; Floating(llvm::APFloatBase::Semantics Semantics)53 Floating(llvm::APFloatBase::Semantics Semantics) 54 : Val(0), Semantics(Semantics) {} Floating(const APFloat & F)55 Floating(const APFloat &F) { 56 57 Semantics = llvm::APFloatBase::SemanticsToEnum(F.getSemantics()); 58 this->copy(F); 59 } Floating(uint64_t * Memory,llvm::APFloatBase::Semantics Semantics)60 Floating(uint64_t *Memory, llvm::APFloatBase::Semantics Semantics) 61 : Memory(Memory), Semantics(Semantics) {} 62 getAPFloat()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 convertToInteger(APSInt & Result)70 APFloat::opStatus convertToInteger(APSInt &Result) const { 71 bool IsExact; 72 return getValue().convertToInteger(Result, llvm::APFloat::rmTowardZero, 73 &IsExact); 74 } 75 toSemantics(const llvm::fltSemantics * Sem,llvm::RoundingMode RM,Floating * Result)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 } toAPValue(const ASTContext &)88 APValue toAPValue(const ASTContext &) const { return APValue(getValue()); } print(llvm::raw_ostream & OS)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 } toDiagnosticString(const ASTContext & Ctx)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 bitWidth()102 unsigned bitWidth() const { 103 return llvm::APFloatBase::semanticsSizeInBits(getSemantics()); 104 } numWords()105 unsigned numWords() const { return llvm::APInt::getNumWords(bitWidth()); } singleWord()106 bool singleWord() const { 107 #if ALLOCATE_ALL 108 return false; 109 #endif 110 return numWords() == 1; 111 } singleWord(const llvm::fltSemantics & Sem)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 } getSemantics()118 const llvm::fltSemantics &getSemantics() const { 119 return llvm::APFloatBase::EnumToSemantics(Semantics); 120 } 121 copy(const APFloat & F)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 take(uint64_t * NewMemory)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 isSigned()141 bool isSigned() const { return true; } isNegative()142 bool isNegative() const { return getValue().isNegative(); } isZero()143 bool isZero() const { return getValue().isZero(); } isNonZero()144 bool isNonZero() const { return getValue().isNonZero(); } isMin()145 bool isMin() const { return getValue().isSmallest(); } isMinusOne()146 bool isMinusOne() const { return getValue().isExactlyValue(-1.0); } isNan()147 bool isNan() const { return getValue().isNaN(); } isSignaling()148 bool isSignaling() const { return getValue().isSignaling(); } isInf()149 bool isInf() const { return getValue().isInfinity(); } isFinite()150 bool isFinite() const { return getValue().isFinite(); } isNormal()151 bool isNormal() const { return getValue().isNormal(); } isDenormal()152 bool isDenormal() const { return getValue().isDenormal(); } classify()153 llvm::FPClassTest classify() const { return getValue().classify(); } getCategory()154 APFloat::fltCategory getCategory() const { return getValue().getCategory(); } 155 compare(const Floating & RHS)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 fromIntegral(APSInt Val,const llvm::fltSemantics & Sem,llvm::RoundingMode RM,Floating * Result)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 bitcastFromMemory(const std::byte * Buff,const llvm::fltSemantics & Sem,Floating * Result)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 bitcastToMemory(std::byte * Buff)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 === bytesToSerialize()196 size_t bytesToSerialize() const { 197 return sizeof(Semantics) + (numWords() * sizeof(uint64_t)); 198 } 199 serialize(std::byte * Buff)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 deserializeSemantics(const std::byte * Buff)211 deserializeSemantics(const std::byte *Buff) { 212 return *reinterpret_cast<const llvm::APFloatBase::Semantics *>(Buff); 213 } 214 deserialize(const std::byte * Buff,Floating * Result)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 add(const Floating & A,const Floating & B,llvm::RoundingMode RM,Floating * R)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 increment(const Floating & A,llvm::RoundingMode RM,Floating * R)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 sub(const Floating & A,const Floating & B,llvm::RoundingMode RM,Floating * R)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 decrement(const Floating & A,llvm::RoundingMode RM,Floating * R)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 mul(const Floating & A,const Floating & B,llvm::RoundingMode RM,Floating * R)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 div(const Floating & A,const Floating & B,llvm::RoundingMode RM,Floating * R)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 neg(const Floating & A,Floating * R)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