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