xref: /freebsd/contrib/llvm-project/clang/lib/AST/ByteCode/Floating.h (revision e64bea71c21eb42e97aa615188ba91f6cce0d36d)
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 // XXX This is just a debugging help. Setting this to 1 will heap-allocate ALL
21 // floating values.
22 #define ALLOCATE_ALL 0
23 
24 namespace clang {
25 namespace interp {
26 
27 using APFloat = llvm::APFloat;
28 using APSInt = llvm::APSInt;
29 using APInt = llvm::APInt;
30 
31 /// If a Floating is constructed from Memory, it DOES NOT OWN THAT MEMORY.
32 /// It will NOT copy the memory (unless, of course, copy() is called) and it
33 /// won't alllocate anything. The allocation should happen via InterpState or
34 /// Program.
35 class Floating final {
36 private:
37   union {
38     uint64_t Val = 0;
39     uint64_t *Memory;
40   };
41   llvm::APFloatBase::Semantics Semantics;
42 
43   APFloat getValue() const {
44     unsigned BitWidth = bitWidth();
45     if (singleWord())
46       return APFloat(getSemantics(), APInt(BitWidth, Val));
47     unsigned NumWords = numWords();
48     return APFloat(getSemantics(), APInt(BitWidth, NumWords, Memory));
49   }
50 
51 public:
52   Floating() = default;
53   Floating(llvm::APFloatBase::Semantics Semantics)
54       : Val(0), Semantics(Semantics) {}
55   Floating(const APFloat &F) {
56 
57     Semantics = llvm::APFloatBase::SemanticsToEnum(F.getSemantics());
58     this->copy(F);
59   }
60   Floating(uint64_t *Memory, llvm::APFloatBase::Semantics Semantics)
61       : Memory(Memory), Semantics(Semantics) {}
62 
63   APFloat getAPFloat() const { return getValue(); }
64 
65   bool operator<(Floating RHS) const { return getValue() < RHS.getValue(); }
66   bool operator>(Floating RHS) const { return getValue() > RHS.getValue(); }
67   bool operator<=(Floating RHS) const { return getValue() <= RHS.getValue(); }
68   bool operator>=(Floating RHS) const { return getValue() >= RHS.getValue(); }
69 
70   APFloat::opStatus convertToInteger(APSInt &Result) const {
71     bool IsExact;
72     return getValue().convertToInteger(Result, llvm::APFloat::rmTowardZero,
73                                        &IsExact);
74   }
75 
76   void toSemantics(const llvm::fltSemantics *Sem, llvm::RoundingMode RM,
77                    Floating *Result) const {
78     APFloat Copy = getValue();
79     bool LosesInfo;
80     Copy.convert(*Sem, RM, &LosesInfo);
81     (void)LosesInfo;
82     Result->copy(Copy);
83   }
84 
85   APSInt toAPSInt(unsigned NumBits = 0) const {
86     return APSInt(getValue().bitcastToAPInt());
87   }
88   APValue toAPValue(const ASTContext &) const { return APValue(getValue()); }
89   void print(llvm::raw_ostream &OS) const {
90     // Can't use APFloat::print() since it appends a newline.
91     SmallVector<char, 16> Buffer;
92     getValue().toString(Buffer);
93     OS << Buffer;
94   }
95   std::string toDiagnosticString(const ASTContext &Ctx) const {
96     std::string NameStr;
97     llvm::raw_string_ostream OS(NameStr);
98     print(OS);
99     return NameStr;
100   }
101 
102   unsigned bitWidth() const {
103     return llvm::APFloatBase::semanticsSizeInBits(getSemantics());
104   }
105   unsigned numWords() const { return llvm::APInt::getNumWords(bitWidth()); }
106   bool singleWord() const {
107 #if ALLOCATE_ALL
108     return false;
109 #endif
110     return numWords() == 1;
111   }
112   static bool singleWord(const llvm::fltSemantics &Sem) {
113 #if ALLOCATE_ALL
114     return false;
115 #endif
116     return APInt::getNumWords(llvm::APFloatBase::getSizeInBits(Sem)) == 1;
117   }
118   const llvm::fltSemantics &getSemantics() const {
119     return llvm::APFloatBase::EnumToSemantics(Semantics);
120   }
121 
122   void copy(const APFloat &F) {
123     if (singleWord()) {
124       Val = F.bitcastToAPInt().getZExtValue();
125     } else {
126       assert(Memory);
127       std::memcpy(Memory, F.bitcastToAPInt().getRawData(),
128                   numWords() * sizeof(uint64_t));
129     }
130   }
131 
132   void take(uint64_t *NewMemory) {
133     if (singleWord())
134       return;
135 
136     if (Memory)
137       std::memcpy(NewMemory, Memory, numWords() * sizeof(uint64_t));
138     Memory = NewMemory;
139   }
140 
141   bool isSigned() const { return true; }
142   bool isNegative() const { return getValue().isNegative(); }
143   bool isZero() const { return getValue().isZero(); }
144   bool isNonZero() const { return getValue().isNonZero(); }
145   bool isMin() const { return getValue().isSmallest(); }
146   bool isMinusOne() const { return getValue().isExactlyValue(-1.0); }
147   bool isNan() const { return getValue().isNaN(); }
148   bool isSignaling() const { return getValue().isSignaling(); }
149   bool isInf() const { return getValue().isInfinity(); }
150   bool isFinite() const { return getValue().isFinite(); }
151   bool isNormal() const { return getValue().isNormal(); }
152   bool isDenormal() const { return getValue().isDenormal(); }
153   llvm::FPClassTest classify() const { return getValue().classify(); }
154   APFloat::fltCategory getCategory() const { return getValue().getCategory(); }
155 
156   ComparisonCategoryResult compare(const Floating &RHS) const {
157     llvm::APFloatBase::cmpResult CmpRes = getValue().compare(RHS.getValue());
158     switch (CmpRes) {
159     case llvm::APFloatBase::cmpLessThan:
160       return ComparisonCategoryResult::Less;
161     case llvm::APFloatBase::cmpEqual:
162       return ComparisonCategoryResult::Equal;
163     case llvm::APFloatBase::cmpGreaterThan:
164       return ComparisonCategoryResult::Greater;
165     case llvm::APFloatBase::cmpUnordered:
166       return ComparisonCategoryResult::Unordered;
167     }
168     llvm_unreachable("Inavlid cmpResult value");
169   }
170 
171   static APFloat::opStatus fromIntegral(APSInt Val,
172                                         const llvm::fltSemantics &Sem,
173                                         llvm::RoundingMode RM,
174                                         Floating *Result) {
175     APFloat F = APFloat(Sem);
176     APFloat::opStatus Status = F.convertFromAPInt(Val, Val.isSigned(), RM);
177     Result->copy(F);
178     return Status;
179   }
180 
181   static void bitcastFromMemory(const std::byte *Buff,
182                                 const llvm::fltSemantics &Sem,
183                                 Floating *Result) {
184     size_t Size = APFloat::semanticsSizeInBits(Sem);
185     llvm::APInt API(Size, true);
186     llvm::LoadIntFromMemory(API, (const uint8_t *)Buff, Size / 8);
187     Result->copy(APFloat(Sem, API));
188   }
189 
190   void bitcastToMemory(std::byte *Buff) const {
191     llvm::APInt API = getValue().bitcastToAPInt();
192     llvm::StoreIntToMemory(API, (uint8_t *)Buff, bitWidth() / 8);
193   }
194 
195   // === Serialization support ===
196   size_t bytesToSerialize() const {
197     return sizeof(Semantics) + (numWords() * sizeof(uint64_t));
198   }
199 
200   void serialize(std::byte *Buff) const {
201     std::memcpy(Buff, &Semantics, sizeof(Semantics));
202     if (singleWord()) {
203       std::memcpy(Buff + sizeof(Semantics), &Val, sizeof(uint64_t));
204     } else {
205       std::memcpy(Buff + sizeof(Semantics), Memory,
206                   numWords() * sizeof(uint64_t));
207     }
208   }
209 
210   static llvm::APFloatBase::Semantics
211   deserializeSemantics(const std::byte *Buff) {
212     return *reinterpret_cast<const llvm::APFloatBase::Semantics *>(Buff);
213   }
214 
215   static void deserialize(const std::byte *Buff, Floating *Result) {
216     llvm::APFloatBase::Semantics Semantics;
217     std::memcpy(&Semantics, Buff, sizeof(Semantics));
218 
219     unsigned BitWidth = llvm::APFloat::semanticsSizeInBits(
220         llvm::APFloatBase::EnumToSemantics(Semantics));
221     unsigned NumWords = llvm::APInt::getNumWords(BitWidth);
222 
223     Result->Semantics = Semantics;
224     if (NumWords == 1 && !ALLOCATE_ALL) {
225       std::memcpy(&Result->Val, Buff + sizeof(Semantics), sizeof(uint64_t));
226     } else {
227       assert(Result->Memory);
228       std::memcpy(Result->Memory, Buff + sizeof(Semantics),
229                   NumWords * sizeof(uint64_t));
230     }
231   }
232 
233   // -------
234 
235   static APFloat::opStatus add(const Floating &A, const Floating &B,
236                                llvm::RoundingMode RM, Floating *R) {
237     APFloat LHS = A.getValue();
238     APFloat RHS = B.getValue();
239 
240     auto Status = LHS.add(RHS, RM);
241     R->copy(LHS);
242     return Status;
243   }
244 
245   static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM,
246                                      Floating *R) {
247     APFloat One(A.getSemantics(), 1);
248     APFloat LHS = A.getValue();
249 
250     auto Status = LHS.add(One, RM);
251     R->copy(LHS);
252     return Status;
253   }
254 
255   static APFloat::opStatus sub(const Floating &A, const Floating &B,
256                                llvm::RoundingMode RM, Floating *R) {
257     APFloat LHS = A.getValue();
258     APFloat RHS = B.getValue();
259 
260     auto Status = LHS.subtract(RHS, RM);
261     R->copy(LHS);
262     return Status;
263   }
264 
265   static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM,
266                                      Floating *R) {
267     APFloat One(A.getSemantics(), 1);
268     APFloat LHS = A.getValue();
269 
270     auto Status = LHS.subtract(One, RM);
271     R->copy(LHS);
272     return Status;
273   }
274 
275   static APFloat::opStatus mul(const Floating &A, const Floating &B,
276                                llvm::RoundingMode RM, Floating *R) {
277 
278     APFloat LHS = A.getValue();
279     APFloat RHS = B.getValue();
280 
281     auto Status = LHS.multiply(RHS, RM);
282     R->copy(LHS);
283     return Status;
284   }
285 
286   static APFloat::opStatus div(const Floating &A, const Floating &B,
287                                llvm::RoundingMode RM, Floating *R) {
288     APFloat LHS = A.getValue();
289     APFloat RHS = B.getValue();
290 
291     auto Status = LHS.divide(RHS, RM);
292     R->copy(LHS);
293     return Status;
294   }
295 
296   static bool neg(const Floating &A, Floating *R) {
297     R->copy(-A.getValue());
298     return false;
299   }
300 };
301 
302 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Floating F);
303 Floating getSwappedBytes(Floating F);
304 
305 } // namespace interp
306 } // namespace clang
307 
308 #endif
309