xref: /freebsd/contrib/llvm-project/clang/lib/AST/ByteCode/Floating.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 
getValue()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;
Floating(llvm::APFloatBase::Semantics Semantics)53   Floating(llvm::APFloatBase::Semantics Semantics)
54       : Val(0), Semantics(Semantics) {}
Floating(const APFloat & F)55   Floating(const APFloat &F) {
56 
57     Semantics = llvm::APFloatBase::SemanticsToEnum(F.getSemantics());
58     this->copy(F);
59   }
Floating(uint64_t * Memory,llvm::APFloatBase::Semantics Semantics)60   Floating(uint64_t *Memory, llvm::APFloatBase::Semantics Semantics)
61       : Memory(Memory), Semantics(Semantics) {}
62 
getAPFloat()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 
convertToInteger(APSInt & Result)70   APFloat::opStatus convertToInteger(APSInt &Result) const {
71     bool IsExact;
72     return getValue().convertToInteger(Result, llvm::APFloat::rmTowardZero,
73                                        &IsExact);
74   }
75 
toSemantics(const llvm::fltSemantics * Sem,llvm::RoundingMode RM,Floating * Result)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   }
toAPValue(const ASTContext &)88   APValue toAPValue(const ASTContext &) const { return APValue(getValue()); }
print(llvm::raw_ostream & OS)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   }
toDiagnosticString(const ASTContext & Ctx)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 
bitWidth()102   unsigned bitWidth() const {
103     return llvm::APFloatBase::semanticsSizeInBits(getSemantics());
104   }
numWords()105   unsigned numWords() const { return llvm::APInt::getNumWords(bitWidth()); }
singleWord()106   bool singleWord() const {
107 #if ALLOCATE_ALL
108     return false;
109 #endif
110     return numWords() == 1;
111   }
singleWord(const llvm::fltSemantics & Sem)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   }
getSemantics()118   const llvm::fltSemantics &getSemantics() const {
119     return llvm::APFloatBase::EnumToSemantics(Semantics);
120   }
121 
copy(const APFloat & F)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 
take(uint64_t * NewMemory)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 
isSigned()141   bool isSigned() const { return true; }
isNegative()142   bool isNegative() const { return getValue().isNegative(); }
isZero()143   bool isZero() const { return getValue().isZero(); }
isNonZero()144   bool isNonZero() const { return getValue().isNonZero(); }
isMin()145   bool isMin() const { return getValue().isSmallest(); }
isMinusOne()146   bool isMinusOne() const { return getValue().isExactlyValue(-1.0); }
isNan()147   bool isNan() const { return getValue().isNaN(); }
isSignaling()148   bool isSignaling() const { return getValue().isSignaling(); }
isInf()149   bool isInf() const { return getValue().isInfinity(); }
isFinite()150   bool isFinite() const { return getValue().isFinite(); }
isNormal()151   bool isNormal() const { return getValue().isNormal(); }
isDenormal()152   bool isDenormal() const { return getValue().isDenormal(); }
classify()153   llvm::FPClassTest classify() const { return getValue().classify(); }
getCategory()154   APFloat::fltCategory getCategory() const { return getValue().getCategory(); }
155 
compare(const Floating & RHS)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 
fromIntegral(APSInt Val,const llvm::fltSemantics & Sem,llvm::RoundingMode RM,Floating * Result)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 
bitcastFromMemory(const std::byte * Buff,const llvm::fltSemantics & Sem,Floating * Result)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 
bitcastToMemory(std::byte * Buff)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 ===
bytesToSerialize()196   size_t bytesToSerialize() const {
197     return sizeof(Semantics) + (numWords() * sizeof(uint64_t));
198   }
199 
serialize(std::byte * Buff)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
deserializeSemantics(const std::byte * Buff)211   deserializeSemantics(const std::byte *Buff) {
212     return *reinterpret_cast<const llvm::APFloatBase::Semantics *>(Buff);
213   }
214 
deserialize(const std::byte * Buff,Floating * Result)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 
add(const Floating & A,const Floating & B,llvm::RoundingMode RM,Floating * R)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 
increment(const Floating & A,llvm::RoundingMode RM,Floating * R)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 
sub(const Floating & A,const Floating & B,llvm::RoundingMode RM,Floating * R)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 
decrement(const Floating & A,llvm::RoundingMode RM,Floating * R)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 
mul(const Floating & A,const Floating & B,llvm::RoundingMode RM,Floating * R)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 
div(const Floating & A,const Floating & B,llvm::RoundingMode RM,Floating * R)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 
neg(const Floating & A,Floating * R)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