106c3fb27SDimitry Andric //===--- Floating.h - Types for the constexpr VM ----------------*- C++ -*-===// 206c3fb27SDimitry Andric // 306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 606c3fb27SDimitry Andric // 706c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 806c3fb27SDimitry Andric // 906c3fb27SDimitry Andric // Defines the VM types and helpers operating on types. 1006c3fb27SDimitry Andric // 1106c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 1206c3fb27SDimitry Andric 1306c3fb27SDimitry Andric #ifndef LLVM_CLANG_AST_INTERP_FLOATING_H 1406c3fb27SDimitry Andric #define LLVM_CLANG_AST_INTERP_FLOATING_H 1506c3fb27SDimitry Andric 1606c3fb27SDimitry Andric #include "Primitives.h" 1706c3fb27SDimitry Andric #include "clang/AST/APValue.h" 1806c3fb27SDimitry Andric #include "llvm/ADT/APFloat.h" 1906c3fb27SDimitry Andric 2006c3fb27SDimitry Andric namespace clang { 2106c3fb27SDimitry Andric namespace interp { 2206c3fb27SDimitry Andric 2306c3fb27SDimitry Andric using APFloat = llvm::APFloat; 2406c3fb27SDimitry Andric using APSInt = llvm::APSInt; 2506c3fb27SDimitry Andric 2606c3fb27SDimitry Andric class Floating final { 2706c3fb27SDimitry Andric private: 2806c3fb27SDimitry Andric // The underlying value storage. 2906c3fb27SDimitry Andric APFloat F; 3006c3fb27SDimitry Andric 3106c3fb27SDimitry Andric public: 3206c3fb27SDimitry Andric /// Zero-initializes a Floating. 3306c3fb27SDimitry Andric Floating() : F(0.0f) {} 3406c3fb27SDimitry Andric Floating(const APFloat &F) : F(F) {} 3506c3fb27SDimitry Andric 3606c3fb27SDimitry Andric // Static constructors for special floating point values. 3706c3fb27SDimitry Andric static Floating getInf(const llvm::fltSemantics &Sem) { 3806c3fb27SDimitry Andric return Floating(APFloat::getInf(Sem)); 3906c3fb27SDimitry Andric } 4006c3fb27SDimitry Andric const APFloat &getAPFloat() const { return F; } 4106c3fb27SDimitry Andric 4206c3fb27SDimitry Andric bool operator<(Floating RHS) const { return F < RHS.F; } 4306c3fb27SDimitry Andric bool operator>(Floating RHS) const { return F > RHS.F; } 4406c3fb27SDimitry Andric bool operator<=(Floating RHS) const { return F <= RHS.F; } 4506c3fb27SDimitry Andric bool operator>=(Floating RHS) const { return F >= RHS.F; } 4606c3fb27SDimitry Andric bool operator==(Floating RHS) const { return F == RHS.F; } 4706c3fb27SDimitry Andric bool operator!=(Floating RHS) const { return F != RHS.F; } 4806c3fb27SDimitry Andric Floating operator-() const { return Floating(-F); } 4906c3fb27SDimitry Andric 5006c3fb27SDimitry Andric APFloat::opStatus convertToInteger(APSInt &Result) const { 5106c3fb27SDimitry Andric bool IsExact; 5206c3fb27SDimitry Andric return F.convertToInteger(Result, llvm::APFloat::rmTowardZero, &IsExact); 5306c3fb27SDimitry Andric } 5406c3fb27SDimitry Andric 5506c3fb27SDimitry Andric Floating toSemantics(const llvm::fltSemantics *Sem, 5606c3fb27SDimitry Andric llvm::RoundingMode RM) const { 5706c3fb27SDimitry Andric APFloat Copy = F; 5806c3fb27SDimitry Andric bool LosesInfo; 5906c3fb27SDimitry Andric Copy.convert(*Sem, RM, &LosesInfo); 6006c3fb27SDimitry Andric (void)LosesInfo; 6106c3fb27SDimitry Andric return Floating(Copy); 6206c3fb27SDimitry Andric } 6306c3fb27SDimitry Andric 6406c3fb27SDimitry Andric /// Convert this Floating to one with the same semantics as \Other. 6506c3fb27SDimitry Andric Floating toSemantics(const Floating &Other, llvm::RoundingMode RM) const { 6606c3fb27SDimitry Andric return toSemantics(&Other.F.getSemantics(), RM); 6706c3fb27SDimitry Andric } 6806c3fb27SDimitry Andric 6906c3fb27SDimitry Andric APSInt toAPSInt(unsigned NumBits = 0) const { 7006c3fb27SDimitry Andric return APSInt(F.bitcastToAPInt()); 7106c3fb27SDimitry Andric } 7206c3fb27SDimitry Andric APValue toAPValue() const { return APValue(F); } 7306c3fb27SDimitry Andric void print(llvm::raw_ostream &OS) const { 7406c3fb27SDimitry Andric // Can't use APFloat::print() since it appends a newline. 7506c3fb27SDimitry Andric SmallVector<char, 16> Buffer; 7606c3fb27SDimitry Andric F.toString(Buffer); 7706c3fb27SDimitry Andric OS << Buffer; 7806c3fb27SDimitry Andric } 79*5f757f3fSDimitry Andric std::string toDiagnosticString(const ASTContext &Ctx) const { 80*5f757f3fSDimitry Andric std::string NameStr; 81*5f757f3fSDimitry Andric llvm::raw_string_ostream OS(NameStr); 82*5f757f3fSDimitry Andric print(OS); 83*5f757f3fSDimitry Andric return NameStr; 84*5f757f3fSDimitry Andric } 8506c3fb27SDimitry Andric 8606c3fb27SDimitry Andric unsigned bitWidth() const { return F.semanticsSizeInBits(F.getSemantics()); } 8706c3fb27SDimitry Andric 8806c3fb27SDimitry Andric bool isSigned() const { return true; } 8906c3fb27SDimitry Andric bool isNegative() const { return F.isNegative(); } 9006c3fb27SDimitry Andric bool isPositive() const { return !F.isNegative(); } 9106c3fb27SDimitry Andric bool isZero() const { return F.isZero(); } 9206c3fb27SDimitry Andric bool isNonZero() const { return F.isNonZero(); } 9306c3fb27SDimitry Andric bool isMin() const { return F.isSmallest(); } 9406c3fb27SDimitry Andric bool isMinusOne() const { return F.isExactlyValue(-1.0); } 9506c3fb27SDimitry Andric bool isNan() const { return F.isNaN(); } 96*5f757f3fSDimitry Andric bool isSignaling() const { return F.isSignaling(); } 97*5f757f3fSDimitry Andric bool isInf() const { return F.isInfinity(); } 9806c3fb27SDimitry Andric bool isFinite() const { return F.isFinite(); } 99*5f757f3fSDimitry Andric bool isNormal() const { return F.isNormal(); } 100*5f757f3fSDimitry Andric bool isDenormal() const { return F.isDenormal(); } 101*5f757f3fSDimitry Andric llvm::FPClassTest classify() const { return F.classify(); } 102*5f757f3fSDimitry Andric APFloat::fltCategory getCategory() const { return F.getCategory(); } 10306c3fb27SDimitry Andric 10406c3fb27SDimitry Andric ComparisonCategoryResult compare(const Floating &RHS) const { 105*5f757f3fSDimitry Andric llvm::APFloatBase::cmpResult CmpRes = F.compare(RHS.F); 106*5f757f3fSDimitry Andric switch (CmpRes) { 107*5f757f3fSDimitry Andric case llvm::APFloatBase::cmpLessThan: 108*5f757f3fSDimitry Andric return ComparisonCategoryResult::Less; 109*5f757f3fSDimitry Andric case llvm::APFloatBase::cmpEqual: 110*5f757f3fSDimitry Andric return ComparisonCategoryResult::Equal; 111*5f757f3fSDimitry Andric case llvm::APFloatBase::cmpGreaterThan: 112*5f757f3fSDimitry Andric return ComparisonCategoryResult::Greater; 113*5f757f3fSDimitry Andric case llvm::APFloatBase::cmpUnordered: 114*5f757f3fSDimitry Andric return ComparisonCategoryResult::Unordered; 115*5f757f3fSDimitry Andric } 116*5f757f3fSDimitry Andric llvm_unreachable("Inavlid cmpResult value"); 11706c3fb27SDimitry Andric } 11806c3fb27SDimitry Andric 11906c3fb27SDimitry Andric static APFloat::opStatus fromIntegral(APSInt Val, 12006c3fb27SDimitry Andric const llvm::fltSemantics &Sem, 12106c3fb27SDimitry Andric llvm::RoundingMode RM, 12206c3fb27SDimitry Andric Floating &Result) { 12306c3fb27SDimitry Andric APFloat F = APFloat(Sem); 12406c3fb27SDimitry Andric APFloat::opStatus Status = F.convertFromAPInt(Val, Val.isSigned(), RM); 12506c3fb27SDimitry Andric Result = Floating(F); 12606c3fb27SDimitry Andric return Status; 12706c3fb27SDimitry Andric } 12806c3fb27SDimitry Andric 129*5f757f3fSDimitry Andric static Floating bitcastFromMemory(const std::byte *Buff, 130*5f757f3fSDimitry Andric const llvm::fltSemantics &Sem) { 131*5f757f3fSDimitry Andric size_t Size = APFloat::semanticsSizeInBits(Sem); 132*5f757f3fSDimitry Andric llvm::APInt API(Size, true); 133*5f757f3fSDimitry Andric llvm::LoadIntFromMemory(API, (const uint8_t *)Buff, Size / 8); 134*5f757f3fSDimitry Andric 135*5f757f3fSDimitry Andric return Floating(APFloat(Sem, API)); 136*5f757f3fSDimitry Andric } 137*5f757f3fSDimitry Andric 138*5f757f3fSDimitry Andric // === Serialization support === 139*5f757f3fSDimitry Andric size_t bytesToSerialize() const { 140*5f757f3fSDimitry Andric return sizeof(llvm::fltSemantics *) + 141*5f757f3fSDimitry Andric (APFloat::semanticsSizeInBits(F.getSemantics()) / 8); 142*5f757f3fSDimitry Andric } 143*5f757f3fSDimitry Andric 144*5f757f3fSDimitry Andric void serialize(std::byte *Buff) const { 145*5f757f3fSDimitry Andric // Semantics followed by an APInt. 146*5f757f3fSDimitry Andric *reinterpret_cast<const llvm::fltSemantics **>(Buff) = &F.getSemantics(); 147*5f757f3fSDimitry Andric 148*5f757f3fSDimitry Andric llvm::APInt API = F.bitcastToAPInt(); 149*5f757f3fSDimitry Andric llvm::StoreIntToMemory(API, (uint8_t *)(Buff + sizeof(void *)), 150*5f757f3fSDimitry Andric bitWidth() / 8); 151*5f757f3fSDimitry Andric } 152*5f757f3fSDimitry Andric 153*5f757f3fSDimitry Andric static Floating deserialize(const std::byte *Buff) { 154*5f757f3fSDimitry Andric const llvm::fltSemantics *Sem; 155*5f757f3fSDimitry Andric std::memcpy((void *)&Sem, Buff, sizeof(void *)); 156*5f757f3fSDimitry Andric return bitcastFromMemory(Buff + sizeof(void *), *Sem); 157*5f757f3fSDimitry Andric } 158*5f757f3fSDimitry Andric 159*5f757f3fSDimitry Andric static Floating abs(const Floating &F) { 160*5f757f3fSDimitry Andric APFloat V = F.F; 161*5f757f3fSDimitry Andric if (V.isNegative()) 162*5f757f3fSDimitry Andric V.changeSign(); 163*5f757f3fSDimitry Andric return Floating(V); 164*5f757f3fSDimitry Andric } 165*5f757f3fSDimitry Andric 16606c3fb27SDimitry Andric // ------- 16706c3fb27SDimitry Andric 16806c3fb27SDimitry Andric static APFloat::opStatus add(const Floating &A, const Floating &B, 16906c3fb27SDimitry Andric llvm::RoundingMode RM, Floating *R) { 17006c3fb27SDimitry Andric *R = Floating(A.F); 17106c3fb27SDimitry Andric return R->F.add(B.F, RM); 17206c3fb27SDimitry Andric } 17306c3fb27SDimitry Andric 17406c3fb27SDimitry Andric static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM, 17506c3fb27SDimitry Andric Floating *R) { 17606c3fb27SDimitry Andric APFloat One(A.F.getSemantics(), 1); 17706c3fb27SDimitry Andric *R = Floating(A.F); 17806c3fb27SDimitry Andric return R->F.add(One, RM); 17906c3fb27SDimitry Andric } 18006c3fb27SDimitry Andric 18106c3fb27SDimitry Andric static APFloat::opStatus sub(const Floating &A, const Floating &B, 18206c3fb27SDimitry Andric llvm::RoundingMode RM, Floating *R) { 18306c3fb27SDimitry Andric *R = Floating(A.F); 18406c3fb27SDimitry Andric return R->F.subtract(B.F, RM); 18506c3fb27SDimitry Andric } 18606c3fb27SDimitry Andric 18706c3fb27SDimitry Andric static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM, 18806c3fb27SDimitry Andric Floating *R) { 18906c3fb27SDimitry Andric APFloat One(A.F.getSemantics(), 1); 19006c3fb27SDimitry Andric *R = Floating(A.F); 19106c3fb27SDimitry Andric return R->F.subtract(One, RM); 19206c3fb27SDimitry Andric } 19306c3fb27SDimitry Andric 19406c3fb27SDimitry Andric static APFloat::opStatus mul(const Floating &A, const Floating &B, 19506c3fb27SDimitry Andric llvm::RoundingMode RM, Floating *R) { 19606c3fb27SDimitry Andric *R = Floating(A.F); 19706c3fb27SDimitry Andric return R->F.multiply(B.F, RM); 19806c3fb27SDimitry Andric } 19906c3fb27SDimitry Andric 20006c3fb27SDimitry Andric static APFloat::opStatus div(const Floating &A, const Floating &B, 20106c3fb27SDimitry Andric llvm::RoundingMode RM, Floating *R) { 20206c3fb27SDimitry Andric *R = Floating(A.F); 20306c3fb27SDimitry Andric return R->F.divide(B.F, RM); 20406c3fb27SDimitry Andric } 20506c3fb27SDimitry Andric 20606c3fb27SDimitry Andric static bool neg(const Floating &A, Floating *R) { 20706c3fb27SDimitry Andric *R = -A; 20806c3fb27SDimitry Andric return false; 20906c3fb27SDimitry Andric } 21006c3fb27SDimitry Andric }; 21106c3fb27SDimitry Andric 21206c3fb27SDimitry Andric llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Floating F); 21306c3fb27SDimitry Andric Floating getSwappedBytes(Floating F); 21406c3fb27SDimitry Andric 21506c3fb27SDimitry Andric } // namespace interp 21606c3fb27SDimitry Andric } // namespace clang 21706c3fb27SDimitry Andric 21806c3fb27SDimitry Andric #endif 219