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