xref: /freebsd/contrib/llvm-project/clang/lib/AST/Interp/Floating.h (revision 7fdf597e96a02165cfe22ff357b857d5fa15ed8a)
1 //===--- Floating.h - Types for the constexpr VM ----------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Defines the VM types and helpers operating on types.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_CLANG_AST_INTERP_FLOATING_H
14 #define LLVM_CLANG_AST_INTERP_FLOATING_H
15 
16 #include "Primitives.h"
17 #include "clang/AST/APValue.h"
18 #include "llvm/ADT/APFloat.h"
19 
20 namespace clang {
21 namespace interp {
22 
23 using APFloat = llvm::APFloat;
24 using APSInt = llvm::APSInt;
25 
26 class Floating final {
27 private:
28   // The underlying value storage.
29   APFloat F;
30 
31 public:
32   /// Zero-initializes a Floating.
33   Floating() : F(0.0f) {}
34   Floating(const APFloat &F) : F(F) {}
35 
36   // Static constructors for special floating point values.
37   static Floating getInf(const llvm::fltSemantics &Sem) {
38     return Floating(APFloat::getInf(Sem));
39   }
40   const APFloat &getAPFloat() const { return F; }
41 
42   bool operator<(Floating RHS) const { return F < RHS.F; }
43   bool operator>(Floating RHS) const { return F > RHS.F; }
44   bool operator<=(Floating RHS) const { return F <= RHS.F; }
45   bool operator>=(Floating RHS) const { return F >= RHS.F; }
46   bool operator==(Floating RHS) const { return F == RHS.F; }
47   bool operator!=(Floating RHS) const { return F != RHS.F; }
48   Floating operator-() const { return Floating(-F); }
49 
50   APFloat::opStatus convertToInteger(APSInt &Result) const {
51     bool IsExact;
52     return F.convertToInteger(Result, llvm::APFloat::rmTowardZero, &IsExact);
53   }
54 
55   Floating toSemantics(const llvm::fltSemantics *Sem,
56                        llvm::RoundingMode RM) const {
57     APFloat Copy = F;
58     bool LosesInfo;
59     Copy.convert(*Sem, RM, &LosesInfo);
60     (void)LosesInfo;
61     return Floating(Copy);
62   }
63 
64   /// Convert this Floating to one with the same semantics as \Other.
65   Floating toSemantics(const Floating &Other, llvm::RoundingMode RM) const {
66     return toSemantics(&Other.F.getSemantics(), RM);
67   }
68 
69   APSInt toAPSInt(unsigned NumBits = 0) const {
70     return APSInt(F.bitcastToAPInt());
71   }
72   APValue toAPValue(const ASTContext &) const { return APValue(F); }
73   void print(llvm::raw_ostream &OS) const {
74     // Can't use APFloat::print() since it appends a newline.
75     SmallVector<char, 16> Buffer;
76     F.toString(Buffer);
77     OS << Buffer;
78   }
79   std::string toDiagnosticString(const ASTContext &Ctx) const {
80     std::string NameStr;
81     llvm::raw_string_ostream OS(NameStr);
82     print(OS);
83     return NameStr;
84   }
85 
86   unsigned bitWidth() const { return F.semanticsSizeInBits(F.getSemantics()); }
87 
88   bool isSigned() const { return true; }
89   bool isNegative() const { return F.isNegative(); }
90   bool isPositive() const { return !F.isNegative(); }
91   bool isZero() const { return F.isZero(); }
92   bool isNonZero() const { return F.isNonZero(); }
93   bool isMin() const { return F.isSmallest(); }
94   bool isMinusOne() const { return F.isExactlyValue(-1.0); }
95   bool isNan() const { return F.isNaN(); }
96   bool isSignaling() const { return F.isSignaling(); }
97   bool isInf() const { return F.isInfinity(); }
98   bool isFinite() const { return F.isFinite(); }
99   bool isNormal() const { return F.isNormal(); }
100   bool isDenormal() const { return F.isDenormal(); }
101   llvm::FPClassTest classify() const { return F.classify(); }
102   APFloat::fltCategory getCategory() const { return F.getCategory(); }
103 
104   ComparisonCategoryResult compare(const Floating &RHS) const {
105     llvm::APFloatBase::cmpResult CmpRes = F.compare(RHS.F);
106     switch (CmpRes) {
107     case llvm::APFloatBase::cmpLessThan:
108       return ComparisonCategoryResult::Less;
109     case llvm::APFloatBase::cmpEqual:
110       return ComparisonCategoryResult::Equal;
111     case llvm::APFloatBase::cmpGreaterThan:
112       return ComparisonCategoryResult::Greater;
113     case llvm::APFloatBase::cmpUnordered:
114       return ComparisonCategoryResult::Unordered;
115     }
116     llvm_unreachable("Inavlid cmpResult value");
117   }
118 
119   static APFloat::opStatus fromIntegral(APSInt Val,
120                                         const llvm::fltSemantics &Sem,
121                                         llvm::RoundingMode RM,
122                                         Floating &Result) {
123     APFloat F = APFloat(Sem);
124     APFloat::opStatus Status = F.convertFromAPInt(Val, Val.isSigned(), RM);
125     Result = Floating(F);
126     return Status;
127   }
128 
129   static Floating bitcastFromMemory(const std::byte *Buff,
130                                     const llvm::fltSemantics &Sem) {
131     size_t Size = APFloat::semanticsSizeInBits(Sem);
132     llvm::APInt API(Size, true);
133     llvm::LoadIntFromMemory(API, (const uint8_t *)Buff, Size / 8);
134 
135     return Floating(APFloat(Sem, API));
136   }
137 
138   // === Serialization support ===
139   size_t bytesToSerialize() const {
140     return sizeof(llvm::fltSemantics *) +
141            (APFloat::semanticsSizeInBits(F.getSemantics()) / 8);
142   }
143 
144   void serialize(std::byte *Buff) const {
145     // Semantics followed by an APInt.
146     *reinterpret_cast<const llvm::fltSemantics **>(Buff) = &F.getSemantics();
147 
148     llvm::APInt API = F.bitcastToAPInt();
149     llvm::StoreIntToMemory(API, (uint8_t *)(Buff + sizeof(void *)),
150                            bitWidth() / 8);
151   }
152 
153   static Floating deserialize(const std::byte *Buff) {
154     const llvm::fltSemantics *Sem;
155     std::memcpy((void *)&Sem, Buff, sizeof(void *));
156     return bitcastFromMemory(Buff + sizeof(void *), *Sem);
157   }
158 
159   static Floating abs(const Floating &F) {
160     APFloat V = F.F;
161     if (V.isNegative())
162       V.changeSign();
163     return Floating(V);
164   }
165 
166   // -------
167 
168   static APFloat::opStatus add(const Floating &A, const Floating &B,
169                                llvm::RoundingMode RM, Floating *R) {
170     *R = Floating(A.F);
171     return R->F.add(B.F, RM);
172   }
173 
174   static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM,
175                                      Floating *R) {
176     APFloat One(A.F.getSemantics(), 1);
177     *R = Floating(A.F);
178     return R->F.add(One, RM);
179   }
180 
181   static APFloat::opStatus sub(const Floating &A, const Floating &B,
182                                llvm::RoundingMode RM, Floating *R) {
183     *R = Floating(A.F);
184     return R->F.subtract(B.F, RM);
185   }
186 
187   static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM,
188                                      Floating *R) {
189     APFloat One(A.F.getSemantics(), 1);
190     *R = Floating(A.F);
191     return R->F.subtract(One, RM);
192   }
193 
194   static APFloat::opStatus mul(const Floating &A, const Floating &B,
195                                llvm::RoundingMode RM, Floating *R) {
196     *R = Floating(A.F);
197     return R->F.multiply(B.F, RM);
198   }
199 
200   static APFloat::opStatus div(const Floating &A, const Floating &B,
201                                llvm::RoundingMode RM, Floating *R) {
202     *R = Floating(A.F);
203     return R->F.divide(B.F, RM);
204   }
205 
206   static bool neg(const Floating &A, Floating *R) {
207     *R = -A;
208     return false;
209   }
210 };
211 
212 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Floating F);
213 Floating getSwappedBytes(Floating F);
214 
215 } // namespace interp
216 } // namespace clang
217 
218 #endif
219