xref: /freebsd-src/contrib/llvm-project/clang/lib/AST/Interp/Floating.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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