xref: /freebsd/contrib/llvm-project/clang/lib/AST/Interp/Floating.h (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1*06c3fb27SDimitry Andric //===--- Floating.h - Types for the constexpr VM ----------------*- C++ -*-===//
2*06c3fb27SDimitry Andric //
3*06c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*06c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*06c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*06c3fb27SDimitry Andric //
7*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
8*06c3fb27SDimitry Andric //
9*06c3fb27SDimitry Andric // Defines the VM types and helpers operating on types.
10*06c3fb27SDimitry Andric //
11*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
12*06c3fb27SDimitry Andric 
13*06c3fb27SDimitry Andric #ifndef LLVM_CLANG_AST_INTERP_FLOATING_H
14*06c3fb27SDimitry Andric #define LLVM_CLANG_AST_INTERP_FLOATING_H
15*06c3fb27SDimitry Andric 
16*06c3fb27SDimitry Andric #include "Primitives.h"
17*06c3fb27SDimitry Andric #include "clang/AST/APValue.h"
18*06c3fb27SDimitry Andric #include "llvm/ADT/APFloat.h"
19*06c3fb27SDimitry Andric 
20*06c3fb27SDimitry Andric namespace clang {
21*06c3fb27SDimitry Andric namespace interp {
22*06c3fb27SDimitry Andric 
23*06c3fb27SDimitry Andric using APFloat = llvm::APFloat;
24*06c3fb27SDimitry Andric using APSInt = llvm::APSInt;
25*06c3fb27SDimitry Andric 
26*06c3fb27SDimitry Andric class Floating final {
27*06c3fb27SDimitry Andric private:
28*06c3fb27SDimitry Andric   // The underlying value storage.
29*06c3fb27SDimitry Andric   APFloat F;
30*06c3fb27SDimitry Andric 
31*06c3fb27SDimitry Andric public:
32*06c3fb27SDimitry Andric   /// Zero-initializes a Floating.
33*06c3fb27SDimitry Andric   Floating() : F(0.0f) {}
34*06c3fb27SDimitry Andric   Floating(const APFloat &F) : F(F) {}
35*06c3fb27SDimitry Andric 
36*06c3fb27SDimitry Andric   // Static constructors for special floating point values.
37*06c3fb27SDimitry Andric   static Floating getInf(const llvm::fltSemantics &Sem) {
38*06c3fb27SDimitry Andric     return Floating(APFloat::getInf(Sem));
39*06c3fb27SDimitry Andric   }
40*06c3fb27SDimitry Andric   const APFloat &getAPFloat() const { return F; }
41*06c3fb27SDimitry Andric 
42*06c3fb27SDimitry Andric   bool operator<(Floating RHS) const { return F < RHS.F; }
43*06c3fb27SDimitry Andric   bool operator>(Floating RHS) const { return F > RHS.F; }
44*06c3fb27SDimitry Andric   bool operator<=(Floating RHS) const { return F <= RHS.F; }
45*06c3fb27SDimitry Andric   bool operator>=(Floating RHS) const { return F >= RHS.F; }
46*06c3fb27SDimitry Andric   bool operator==(Floating RHS) const { return F == RHS.F; }
47*06c3fb27SDimitry Andric   bool operator!=(Floating RHS) const { return F != RHS.F; }
48*06c3fb27SDimitry Andric   Floating operator-() const { return Floating(-F); }
49*06c3fb27SDimitry Andric 
50*06c3fb27SDimitry Andric   APFloat::opStatus convertToInteger(APSInt &Result) const {
51*06c3fb27SDimitry Andric     bool IsExact;
52*06c3fb27SDimitry Andric     return F.convertToInteger(Result, llvm::APFloat::rmTowardZero, &IsExact);
53*06c3fb27SDimitry Andric   }
54*06c3fb27SDimitry Andric 
55*06c3fb27SDimitry Andric   Floating toSemantics(const llvm::fltSemantics *Sem,
56*06c3fb27SDimitry Andric                        llvm::RoundingMode RM) const {
57*06c3fb27SDimitry Andric     APFloat Copy = F;
58*06c3fb27SDimitry Andric     bool LosesInfo;
59*06c3fb27SDimitry Andric     Copy.convert(*Sem, RM, &LosesInfo);
60*06c3fb27SDimitry Andric     (void)LosesInfo;
61*06c3fb27SDimitry Andric     return Floating(Copy);
62*06c3fb27SDimitry Andric   }
63*06c3fb27SDimitry Andric 
64*06c3fb27SDimitry Andric   /// Convert this Floating to one with the same semantics as \Other.
65*06c3fb27SDimitry Andric   Floating toSemantics(const Floating &Other, llvm::RoundingMode RM) const {
66*06c3fb27SDimitry Andric     return toSemantics(&Other.F.getSemantics(), RM);
67*06c3fb27SDimitry Andric   }
68*06c3fb27SDimitry Andric 
69*06c3fb27SDimitry Andric   APSInt toAPSInt(unsigned NumBits = 0) const {
70*06c3fb27SDimitry Andric     return APSInt(F.bitcastToAPInt());
71*06c3fb27SDimitry Andric   }
72*06c3fb27SDimitry Andric   APValue toAPValue() const { return APValue(F); }
73*06c3fb27SDimitry Andric   void print(llvm::raw_ostream &OS) const {
74*06c3fb27SDimitry Andric     // Can't use APFloat::print() since it appends a newline.
75*06c3fb27SDimitry Andric     SmallVector<char, 16> Buffer;
76*06c3fb27SDimitry Andric     F.toString(Buffer);
77*06c3fb27SDimitry Andric     OS << Buffer;
78*06c3fb27SDimitry Andric   }
79*06c3fb27SDimitry Andric 
80*06c3fb27SDimitry Andric   unsigned bitWidth() const { return F.semanticsSizeInBits(F.getSemantics()); }
81*06c3fb27SDimitry Andric 
82*06c3fb27SDimitry Andric   bool isSigned() const { return true; }
83*06c3fb27SDimitry Andric   bool isNegative() const { return F.isNegative(); }
84*06c3fb27SDimitry Andric   bool isPositive() const { return !F.isNegative(); }
85*06c3fb27SDimitry Andric   bool isZero() const { return F.isZero(); }
86*06c3fb27SDimitry Andric   bool isNonZero() const { return F.isNonZero(); }
87*06c3fb27SDimitry Andric   bool isMin() const { return F.isSmallest(); }
88*06c3fb27SDimitry Andric   bool isMinusOne() const { return F.isExactlyValue(-1.0); }
89*06c3fb27SDimitry Andric   bool isNan() const { return F.isNaN(); }
90*06c3fb27SDimitry Andric   bool isFinite() const { return F.isFinite(); }
91*06c3fb27SDimitry Andric 
92*06c3fb27SDimitry Andric   ComparisonCategoryResult compare(const Floating &RHS) const {
93*06c3fb27SDimitry Andric     return Compare(F, RHS.F);
94*06c3fb27SDimitry Andric   }
95*06c3fb27SDimitry Andric 
96*06c3fb27SDimitry Andric   static APFloat::opStatus fromIntegral(APSInt Val,
97*06c3fb27SDimitry Andric                                         const llvm::fltSemantics &Sem,
98*06c3fb27SDimitry Andric                                         llvm::RoundingMode RM,
99*06c3fb27SDimitry Andric                                         Floating &Result) {
100*06c3fb27SDimitry Andric     APFloat F = APFloat(Sem);
101*06c3fb27SDimitry Andric     APFloat::opStatus Status = F.convertFromAPInt(Val, Val.isSigned(), RM);
102*06c3fb27SDimitry Andric     Result = Floating(F);
103*06c3fb27SDimitry Andric     return Status;
104*06c3fb27SDimitry Andric   }
105*06c3fb27SDimitry Andric 
106*06c3fb27SDimitry Andric   // -------
107*06c3fb27SDimitry Andric 
108*06c3fb27SDimitry Andric   static APFloat::opStatus add(const Floating &A, const Floating &B,
109*06c3fb27SDimitry Andric                                llvm::RoundingMode RM, Floating *R) {
110*06c3fb27SDimitry Andric     *R = Floating(A.F);
111*06c3fb27SDimitry Andric     return R->F.add(B.F, RM);
112*06c3fb27SDimitry Andric   }
113*06c3fb27SDimitry Andric 
114*06c3fb27SDimitry Andric   static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM,
115*06c3fb27SDimitry Andric                                      Floating *R) {
116*06c3fb27SDimitry Andric     APFloat One(A.F.getSemantics(), 1);
117*06c3fb27SDimitry Andric     *R = Floating(A.F);
118*06c3fb27SDimitry Andric     return R->F.add(One, RM);
119*06c3fb27SDimitry Andric   }
120*06c3fb27SDimitry Andric 
121*06c3fb27SDimitry Andric   static APFloat::opStatus sub(const Floating &A, const Floating &B,
122*06c3fb27SDimitry Andric                                llvm::RoundingMode RM, Floating *R) {
123*06c3fb27SDimitry Andric     *R = Floating(A.F);
124*06c3fb27SDimitry Andric     return R->F.subtract(B.F, RM);
125*06c3fb27SDimitry Andric   }
126*06c3fb27SDimitry Andric 
127*06c3fb27SDimitry Andric   static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM,
128*06c3fb27SDimitry Andric                                      Floating *R) {
129*06c3fb27SDimitry Andric     APFloat One(A.F.getSemantics(), 1);
130*06c3fb27SDimitry Andric     *R = Floating(A.F);
131*06c3fb27SDimitry Andric     return R->F.subtract(One, RM);
132*06c3fb27SDimitry Andric   }
133*06c3fb27SDimitry Andric 
134*06c3fb27SDimitry Andric   static APFloat::opStatus mul(const Floating &A, const Floating &B,
135*06c3fb27SDimitry Andric                                llvm::RoundingMode RM, Floating *R) {
136*06c3fb27SDimitry Andric     *R = Floating(A.F);
137*06c3fb27SDimitry Andric     return R->F.multiply(B.F, RM);
138*06c3fb27SDimitry Andric   }
139*06c3fb27SDimitry Andric 
140*06c3fb27SDimitry Andric   static APFloat::opStatus div(const Floating &A, const Floating &B,
141*06c3fb27SDimitry Andric                                llvm::RoundingMode RM, Floating *R) {
142*06c3fb27SDimitry Andric     *R = Floating(A.F);
143*06c3fb27SDimitry Andric     return R->F.divide(B.F, RM);
144*06c3fb27SDimitry Andric   }
145*06c3fb27SDimitry Andric 
146*06c3fb27SDimitry Andric   static bool neg(const Floating &A, Floating *R) {
147*06c3fb27SDimitry Andric     *R = -A;
148*06c3fb27SDimitry Andric     return false;
149*06c3fb27SDimitry Andric   }
150*06c3fb27SDimitry Andric };
151*06c3fb27SDimitry Andric 
152*06c3fb27SDimitry Andric llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Floating F);
153*06c3fb27SDimitry Andric Floating getSwappedBytes(Floating F);
154*06c3fb27SDimitry Andric 
155*06c3fb27SDimitry Andric } // namespace interp
156*06c3fb27SDimitry Andric } // namespace clang
157*06c3fb27SDimitry Andric 
158*06c3fb27SDimitry Andric #endif
159