xref: /llvm-project/clang/lib/AST/ByteCode/Floating.h (revision fb30208d1e4c2c1ba34c331f6f90a99552d2df97)
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   void bitcastToMemory(std::byte *Buff) const {
139     llvm::APInt API = F.bitcastToAPInt();
140     llvm::StoreIntToMemory(API, (uint8_t *)Buff, bitWidth() / 8);
141   }
142 
143   // === Serialization support ===
144   size_t bytesToSerialize() const {
145     return sizeof(llvm::fltSemantics *) +
146            (APFloat::semanticsSizeInBits(F.getSemantics()) / 8);
147   }
148 
149   void serialize(std::byte *Buff) const {
150     // Semantics followed by an APInt.
151     *reinterpret_cast<const llvm::fltSemantics **>(Buff) = &F.getSemantics();
152 
153     llvm::APInt API = F.bitcastToAPInt();
154     llvm::StoreIntToMemory(API, (uint8_t *)(Buff + sizeof(void *)),
155                            bitWidth() / 8);
156   }
157 
158   static Floating deserialize(const std::byte *Buff) {
159     const llvm::fltSemantics *Sem;
160     std::memcpy((void *)&Sem, Buff, sizeof(void *));
161     return bitcastFromMemory(Buff + sizeof(void *), *Sem);
162   }
163 
164   static Floating abs(const Floating &F) {
165     APFloat V = F.F;
166     if (V.isNegative())
167       V.changeSign();
168     return Floating(V);
169   }
170 
171   // -------
172 
173   static APFloat::opStatus add(const Floating &A, const Floating &B,
174                                llvm::RoundingMode RM, Floating *R) {
175     *R = Floating(A.F);
176     return R->F.add(B.F, RM);
177   }
178 
179   static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM,
180                                      Floating *R) {
181     APFloat One(A.F.getSemantics(), 1);
182     *R = Floating(A.F);
183     return R->F.add(One, RM);
184   }
185 
186   static APFloat::opStatus sub(const Floating &A, const Floating &B,
187                                llvm::RoundingMode RM, Floating *R) {
188     *R = Floating(A.F);
189     return R->F.subtract(B.F, RM);
190   }
191 
192   static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM,
193                                      Floating *R) {
194     APFloat One(A.F.getSemantics(), 1);
195     *R = Floating(A.F);
196     return R->F.subtract(One, RM);
197   }
198 
199   static APFloat::opStatus mul(const Floating &A, const Floating &B,
200                                llvm::RoundingMode RM, Floating *R) {
201     *R = Floating(A.F);
202     return R->F.multiply(B.F, RM);
203   }
204 
205   static APFloat::opStatus div(const Floating &A, const Floating &B,
206                                llvm::RoundingMode RM, Floating *R) {
207     *R = Floating(A.F);
208     return R->F.divide(B.F, RM);
209   }
210 
211   static bool neg(const Floating &A, Floating *R) {
212     *R = -A;
213     return false;
214   }
215 };
216 
217 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Floating F);
218 Floating getSwappedBytes(Floating F);
219 
220 } // namespace interp
221 } // namespace clang
222 
223 #endif
224