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 } 72*0fca6ea1SDimitry Andric APValue toAPValue(const ASTContext &) 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 } 795f757f3fSDimitry Andric std::string toDiagnosticString(const ASTContext &Ctx) const { 805f757f3fSDimitry Andric std::string NameStr; 815f757f3fSDimitry Andric llvm::raw_string_ostream OS(NameStr); 825f757f3fSDimitry Andric print(OS); 835f757f3fSDimitry Andric return NameStr; 845f757f3fSDimitry 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(); } 965f757f3fSDimitry Andric bool isSignaling() const { return F.isSignaling(); } 975f757f3fSDimitry Andric bool isInf() const { return F.isInfinity(); } 9806c3fb27SDimitry Andric bool isFinite() const { return F.isFinite(); } 995f757f3fSDimitry Andric bool isNormal() const { return F.isNormal(); } 1005f757f3fSDimitry Andric bool isDenormal() const { return F.isDenormal(); } 1015f757f3fSDimitry Andric llvm::FPClassTest classify() const { return F.classify(); } 1025f757f3fSDimitry Andric APFloat::fltCategory getCategory() const { return F.getCategory(); } 10306c3fb27SDimitry Andric 10406c3fb27SDimitry Andric ComparisonCategoryResult compare(const Floating &RHS) const { 1055f757f3fSDimitry Andric llvm::APFloatBase::cmpResult CmpRes = F.compare(RHS.F); 1065f757f3fSDimitry Andric switch (CmpRes) { 1075f757f3fSDimitry Andric case llvm::APFloatBase::cmpLessThan: 1085f757f3fSDimitry Andric return ComparisonCategoryResult::Less; 1095f757f3fSDimitry Andric case llvm::APFloatBase::cmpEqual: 1105f757f3fSDimitry Andric return ComparisonCategoryResult::Equal; 1115f757f3fSDimitry Andric case llvm::APFloatBase::cmpGreaterThan: 1125f757f3fSDimitry Andric return ComparisonCategoryResult::Greater; 1135f757f3fSDimitry Andric case llvm::APFloatBase::cmpUnordered: 1145f757f3fSDimitry Andric return ComparisonCategoryResult::Unordered; 1155f757f3fSDimitry Andric } 1165f757f3fSDimitry 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 1295f757f3fSDimitry Andric static Floating bitcastFromMemory(const std::byte *Buff, 1305f757f3fSDimitry Andric const llvm::fltSemantics &Sem) { 1315f757f3fSDimitry Andric size_t Size = APFloat::semanticsSizeInBits(Sem); 1325f757f3fSDimitry Andric llvm::APInt API(Size, true); 1335f757f3fSDimitry Andric llvm::LoadIntFromMemory(API, (const uint8_t *)Buff, Size / 8); 1345f757f3fSDimitry Andric 1355f757f3fSDimitry Andric return Floating(APFloat(Sem, API)); 1365f757f3fSDimitry Andric } 1375f757f3fSDimitry Andric 1385f757f3fSDimitry Andric // === Serialization support === 1395f757f3fSDimitry Andric size_t bytesToSerialize() const { 1405f757f3fSDimitry Andric return sizeof(llvm::fltSemantics *) + 1415f757f3fSDimitry Andric (APFloat::semanticsSizeInBits(F.getSemantics()) / 8); 1425f757f3fSDimitry Andric } 1435f757f3fSDimitry Andric 1445f757f3fSDimitry Andric void serialize(std::byte *Buff) const { 1455f757f3fSDimitry Andric // Semantics followed by an APInt. 1465f757f3fSDimitry Andric *reinterpret_cast<const llvm::fltSemantics **>(Buff) = &F.getSemantics(); 1475f757f3fSDimitry Andric 1485f757f3fSDimitry Andric llvm::APInt API = F.bitcastToAPInt(); 1495f757f3fSDimitry Andric llvm::StoreIntToMemory(API, (uint8_t *)(Buff + sizeof(void *)), 1505f757f3fSDimitry Andric bitWidth() / 8); 1515f757f3fSDimitry Andric } 1525f757f3fSDimitry Andric 1535f757f3fSDimitry Andric static Floating deserialize(const std::byte *Buff) { 1545f757f3fSDimitry Andric const llvm::fltSemantics *Sem; 1555f757f3fSDimitry Andric std::memcpy((void *)&Sem, Buff, sizeof(void *)); 1565f757f3fSDimitry Andric return bitcastFromMemory(Buff + sizeof(void *), *Sem); 1575f757f3fSDimitry Andric } 1585f757f3fSDimitry Andric 1595f757f3fSDimitry Andric static Floating abs(const Floating &F) { 1605f757f3fSDimitry Andric APFloat V = F.F; 1615f757f3fSDimitry Andric if (V.isNegative()) 1625f757f3fSDimitry Andric V.changeSign(); 1635f757f3fSDimitry Andric return Floating(V); 1645f757f3fSDimitry Andric } 1655f757f3fSDimitry 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