diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/AST/Interp/Floating.h')
-rw-r--r-- | contrib/llvm-project/clang/lib/AST/Interp/Floating.h | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/Floating.h b/contrib/llvm-project/clang/lib/AST/Interp/Floating.h new file mode 100644 index 000000000000..114487821880 --- /dev/null +++ b/contrib/llvm-project/clang/lib/AST/Interp/Floating.h @@ -0,0 +1,218 @@ +//===--- 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 ASTContext &) 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 |