| //===--- Floating.h - Types for the constexpr VM ----------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // Defines the VM types and helpers operating on types. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_CLANG_AST_INTERP_FLOATING_H |
| #define LLVM_CLANG_AST_INTERP_FLOATING_H |
| |
| #include "Primitives.h" |
| #include "clang/AST/APValue.h" |
| #include "llvm/ADT/APFloat.h" |
| |
| namespace clang { |
| namespace interp { |
| |
| using APFloat = llvm::APFloat; |
| using APSInt = llvm::APSInt; |
| |
| class Floating final { |
| private: |
| // The underlying value storage. |
| APFloat F; |
| |
| public: |
| /// Zero-initializes a Floating. |
| Floating() : F(0.0f) {} |
| Floating(const APFloat &F) : F(F) {} |
| |
| // Static constructors for special floating point values. |
| static Floating getInf(const llvm::fltSemantics &Sem) { |
| return Floating(APFloat::getInf(Sem)); |
| } |
| const APFloat &getAPFloat() const { return F; } |
| |
| bool operator<(Floating RHS) const { return F < RHS.F; } |
| bool operator>(Floating RHS) const { return F > RHS.F; } |
| bool operator<=(Floating RHS) const { return F <= RHS.F; } |
| bool operator>=(Floating RHS) const { return F >= RHS.F; } |
| bool operator==(Floating RHS) const { return F == RHS.F; } |
| bool operator!=(Floating RHS) const { return F != RHS.F; } |
| Floating operator-() const { return Floating(-F); } |
| |
| APFloat::opStatus convertToInteger(APSInt &Result) const { |
| bool IsExact; |
| return F.convertToInteger(Result, llvm::APFloat::rmTowardZero, &IsExact); |
| } |
| |
| Floating toSemantics(const llvm::fltSemantics *Sem, |
| llvm::RoundingMode RM) const { |
| APFloat Copy = F; |
| bool LosesInfo; |
| Copy.convert(*Sem, RM, &LosesInfo); |
| (void)LosesInfo; |
| return Floating(Copy); |
| } |
| |
| /// Convert this Floating to one with the same semantics as \Other. |
| Floating toSemantics(const Floating &Other, llvm::RoundingMode RM) const { |
| return toSemantics(&Other.F.getSemantics(), RM); |
| } |
| |
| APSInt toAPSInt(unsigned NumBits = 0) const { |
| return APSInt(F.bitcastToAPInt()); |
| } |
| APValue toAPValue() const { return APValue(F); } |
| void print(llvm::raw_ostream &OS) const { |
| // Can't use APFloat::print() since it appends a newline. |
| SmallVector<char, 16> Buffer; |
| F.toString(Buffer); |
| OS << Buffer; |
| } |
| std::string toDiagnosticString(const ASTContext &Ctx) const { |
| std::string NameStr; |
| llvm::raw_string_ostream OS(NameStr); |
| print(OS); |
| return NameStr; |
| } |
| |
| unsigned bitWidth() const { return F.semanticsSizeInBits(F.getSemantics()); } |
| |
| bool isSigned() const { return true; } |
| bool isNegative() const { return F.isNegative(); } |
| bool isPositive() const { return !F.isNegative(); } |
| bool isZero() const { return F.isZero(); } |
| bool isNonZero() const { return F.isNonZero(); } |
| bool isMin() const { return F.isSmallest(); } |
| bool isMinusOne() const { return F.isExactlyValue(-1.0); } |
| bool isNan() const { return F.isNaN(); } |
| bool isSignaling() const { return F.isSignaling(); } |
| bool isInf() const { return F.isInfinity(); } |
| bool isFinite() const { return F.isFinite(); } |
| bool isNormal() const { return F.isNormal(); } |
| bool isDenormal() const { return F.isDenormal(); } |
| llvm::FPClassTest classify() const { return F.classify(); } |
| APFloat::fltCategory getCategory() const { return F.getCategory(); } |
| |
| ComparisonCategoryResult compare(const Floating &RHS) const { |
| llvm::APFloatBase::cmpResult CmpRes = F.compare(RHS.F); |
| switch (CmpRes) { |
| case llvm::APFloatBase::cmpLessThan: |
| return ComparisonCategoryResult::Less; |
| case llvm::APFloatBase::cmpEqual: |
| return ComparisonCategoryResult::Equal; |
| case llvm::APFloatBase::cmpGreaterThan: |
| return ComparisonCategoryResult::Greater; |
| case llvm::APFloatBase::cmpUnordered: |
| return ComparisonCategoryResult::Unordered; |
| } |
| llvm_unreachable("Inavlid cmpResult value"); |
| } |
| |
| static APFloat::opStatus fromIntegral(APSInt Val, |
| const llvm::fltSemantics &Sem, |
| llvm::RoundingMode RM, |
| Floating &Result) { |
| APFloat F = APFloat(Sem); |
| APFloat::opStatus Status = F.convertFromAPInt(Val, Val.isSigned(), RM); |
| Result = Floating(F); |
| return Status; |
| } |
| |
| static Floating bitcastFromMemory(const std::byte *Buff, |
| const llvm::fltSemantics &Sem) { |
| size_t Size = APFloat::semanticsSizeInBits(Sem); |
| llvm::APInt API(Size, true); |
| llvm::LoadIntFromMemory(API, (const uint8_t *)Buff, Size / 8); |
| |
| return Floating(APFloat(Sem, API)); |
| } |
| |
| // === Serialization support === |
| size_t bytesToSerialize() const { |
| return sizeof(llvm::fltSemantics *) + |
| (APFloat::semanticsSizeInBits(F.getSemantics()) / 8); |
| } |
| |
| void serialize(std::byte *Buff) const { |
| // Semantics followed by an APInt. |
| *reinterpret_cast<const llvm::fltSemantics **>(Buff) = &F.getSemantics(); |
| |
| llvm::APInt API = F.bitcastToAPInt(); |
| llvm::StoreIntToMemory(API, (uint8_t *)(Buff + sizeof(void *)), |
| bitWidth() / 8); |
| } |
| |
| static Floating deserialize(const std::byte *Buff) { |
| const llvm::fltSemantics *Sem; |
| std::memcpy((void *)&Sem, Buff, sizeof(void *)); |
| return bitcastFromMemory(Buff + sizeof(void *), *Sem); |
| } |
| |
| static Floating abs(const Floating &F) { |
| APFloat V = F.F; |
| if (V.isNegative()) |
| V.changeSign(); |
| return Floating(V); |
| } |
| |
| // ------- |
| |
| static APFloat::opStatus add(const Floating &A, const Floating &B, |
| llvm::RoundingMode RM, Floating *R) { |
| *R = Floating(A.F); |
| return R->F.add(B.F, RM); |
| } |
| |
| static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM, |
| Floating *R) { |
| APFloat One(A.F.getSemantics(), 1); |
| *R = Floating(A.F); |
| return R->F.add(One, RM); |
| } |
| |
| static APFloat::opStatus sub(const Floating &A, const Floating &B, |
| llvm::RoundingMode RM, Floating *R) { |
| *R = Floating(A.F); |
| return R->F.subtract(B.F, RM); |
| } |
| |
| static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM, |
| Floating *R) { |
| APFloat One(A.F.getSemantics(), 1); |
| *R = Floating(A.F); |
| return R->F.subtract(One, RM); |
| } |
| |
| static APFloat::opStatus mul(const Floating &A, const Floating &B, |
| llvm::RoundingMode RM, Floating *R) { |
| *R = Floating(A.F); |
| return R->F.multiply(B.F, RM); |
| } |
| |
| static APFloat::opStatus div(const Floating &A, const Floating &B, |
| llvm::RoundingMode RM, Floating *R) { |
| *R = Floating(A.F); |
| return R->F.divide(B.F, RM); |
| } |
| |
| static bool neg(const Floating &A, Floating *R) { |
| *R = -A; |
| return false; |
| } |
| }; |
| |
| llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Floating F); |
| Floating getSwappedBytes(Floating F); |
| |
| } // namespace interp |
| } // namespace clang |
| |
| #endif |