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 { 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 
80   unsigned bitWidth() const { return F.semanticsSizeInBits(F.getSemantics()); }
81 
82   bool isSigned() const { return true; }
83   bool isNegative() const { return F.isNegative(); }
84   bool isPositive() const { return !F.isNegative(); }
85   bool isZero() const { return F.isZero(); }
86   bool isNonZero() const { return F.isNonZero(); }
87   bool isMin() const { return F.isSmallest(); }
88   bool isMinusOne() const { return F.isExactlyValue(-1.0); }
89   bool isNan() const { return F.isNaN(); }
90   bool isFinite() const { return F.isFinite(); }
91 
92   ComparisonCategoryResult compare(const Floating &RHS) const {
93     return Compare(F, RHS.F);
94   }
95 
96   static APFloat::opStatus fromIntegral(APSInt Val,
97                                         const llvm::fltSemantics &Sem,
98                                         llvm::RoundingMode RM,
99                                         Floating &Result) {
100     APFloat F = APFloat(Sem);
101     APFloat::opStatus Status = F.convertFromAPInt(Val, Val.isSigned(), RM);
102     Result = Floating(F);
103     return Status;
104   }
105 
106   // -------
107 
108   static APFloat::opStatus add(const Floating &A, const Floating &B,
109                                llvm::RoundingMode RM, Floating *R) {
110     *R = Floating(A.F);
111     return R->F.add(B.F, RM);
112   }
113 
114   static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM,
115                                      Floating *R) {
116     APFloat One(A.F.getSemantics(), 1);
117     *R = Floating(A.F);
118     return R->F.add(One, RM);
119   }
120 
121   static APFloat::opStatus sub(const Floating &A, const Floating &B,
122                                llvm::RoundingMode RM, Floating *R) {
123     *R = Floating(A.F);
124     return R->F.subtract(B.F, RM);
125   }
126 
127   static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM,
128                                      Floating *R) {
129     APFloat One(A.F.getSemantics(), 1);
130     *R = Floating(A.F);
131     return R->F.subtract(One, RM);
132   }
133 
134   static APFloat::opStatus mul(const Floating &A, const Floating &B,
135                                llvm::RoundingMode RM, Floating *R) {
136     *R = Floating(A.F);
137     return R->F.multiply(B.F, RM);
138   }
139 
140   static APFloat::opStatus div(const Floating &A, const Floating &B,
141                                llvm::RoundingMode RM, Floating *R) {
142     *R = Floating(A.F);
143     return R->F.divide(B.F, RM);
144   }
145 
146   static bool neg(const Floating &A, Floating *R) {
147     *R = -A;
148     return false;
149   }
150 };
151 
152 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Floating F);
153 Floating getSwappedBytes(Floating F);
154 
155 } // namespace interp
156 } // namespace clang
157 
158 #endif
159