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
20namespace clang {
21namespace interp {
22
23using APFloat = llvm::APFloat;
24using APSInt = llvm::APSInt;
25
26class Floating final {
27private:
28 // The underlying value storage.
29 APFloat F;
30
31public:
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, RM: llvm::APFloat::rmTowardZero, IsExact: &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(ToSemantics: *Sem, RM, losesInfo: &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(Sem: &Other.F.getSemantics(), RM);
67 }
68
69 APSInt toAPSInt(unsigned NumBits = 0) const {
70 return APSInt(F.bitcastToAPInt());
71 }
72 APValue toAPValue(const ASTContext &) 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(Str&: Buffer);
77 OS << Buffer;
78 }
79 std::string toDiagnosticString(const ASTContext &Ctx) const {
80 std::string NameStr;
81 llvm::raw_string_ostream OS(NameStr);
82 print(OS);
83 return NameStr;
84 }
85
86 unsigned bitWidth() const { return F.semanticsSizeInBits(F.getSemantics()); }
87
88 bool isSigned() const { return true; }
89 bool isNegative() const { return F.isNegative(); }
90 bool isZero() const { return F.isZero(); }
91 bool isNonZero() const { return F.isNonZero(); }
92 bool isMin() const { return F.isSmallest(); }
93 bool isMinusOne() const { return F.isExactlyValue(V: -1.0); }
94 bool isNan() const { return F.isNaN(); }
95 bool isSignaling() const { return F.isSignaling(); }
96 bool isInf() const { return F.isInfinity(); }
97 bool isFinite() const { return F.isFinite(); }
98 bool isNormal() const { return F.isNormal(); }
99 bool isDenormal() const { return F.isDenormal(); }
100 llvm::FPClassTest classify() const { return F.classify(); }
101 APFloat::fltCategory getCategory() const { return F.getCategory(); }
102
103 ComparisonCategoryResult compare(const Floating &RHS) const {
104 llvm::APFloatBase::cmpResult CmpRes = F.compare(RHS: RHS.F);
105 switch (CmpRes) {
106 case llvm::APFloatBase::cmpLessThan:
107 return ComparisonCategoryResult::Less;
108 case llvm::APFloatBase::cmpEqual:
109 return ComparisonCategoryResult::Equal;
110 case llvm::APFloatBase::cmpGreaterThan:
111 return ComparisonCategoryResult::Greater;
112 case llvm::APFloatBase::cmpUnordered:
113 return ComparisonCategoryResult::Unordered;
114 }
115 llvm_unreachable("Inavlid cmpResult value");
116 }
117
118 static APFloat::opStatus fromIntegral(APSInt Val,
119 const llvm::fltSemantics &Sem,
120 llvm::RoundingMode RM,
121 Floating &Result) {
122 APFloat F = APFloat(Sem);
123 APFloat::opStatus Status = F.convertFromAPInt(Input: Val, IsSigned: Val.isSigned(), RM);
124 Result = Floating(F);
125 return Status;
126 }
127
128 static Floating bitcastFromMemory(const std::byte *Buff,
129 const llvm::fltSemantics &Sem) {
130 size_t Size = APFloat::semanticsSizeInBits(Sem);
131 llvm::APInt API(Size, true);
132 llvm::LoadIntFromMemory(IntVal&: API, Src: (const uint8_t *)Buff, LoadBytes: Size / 8);
133
134 return Floating(APFloat(Sem, API));
135 }
136
137 void bitcastToMemory(std::byte *Buff) const {
138 llvm::APInt API = F.bitcastToAPInt();
139 llvm::StoreIntToMemory(IntVal: API, Dst: (uint8_t *)Buff, StoreBytes: bitWidth() / 8);
140 }
141
142 // === Serialization support ===
143 size_t bytesToSerialize() const {
144 return sizeof(llvm::fltSemantics *) +
145 (APFloat::semanticsSizeInBits(F.getSemantics()) / 8);
146 }
147
148 void serialize(std::byte *Buff) const {
149 // Semantics followed by an APInt.
150 *reinterpret_cast<const llvm::fltSemantics **>(Buff) = &F.getSemantics();
151
152 llvm::APInt API = F.bitcastToAPInt();
153 llvm::StoreIntToMemory(IntVal: API, Dst: (uint8_t *)(Buff + sizeof(void *)),
154 StoreBytes: bitWidth() / 8);
155 }
156
157 static Floating deserialize(const std::byte *Buff) {
158 const llvm::fltSemantics *Sem;
159 std::memcpy(dest: (void *)&Sem, src: Buff, n: sizeof(void *));
160 return bitcastFromMemory(Buff: Buff + sizeof(void *), Sem: *Sem);
161 }
162
163 static Floating abs(const Floating &F) {
164 APFloat V = F.F;
165 if (V.isNegative())
166 V.changeSign();
167 return Floating(V);
168 }
169
170 // -------
171
172 static APFloat::opStatus add(const Floating &A, const Floating &B,
173 llvm::RoundingMode RM, Floating *R) {
174 *R = Floating(A.F);
175 return R->F.add(RHS: B.F, RM);
176 }
177
178 static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM,
179 Floating *R) {
180 APFloat One(A.F.getSemantics(), 1);
181 *R = Floating(A.F);
182 return R->F.add(RHS: One, RM);
183 }
184
185 static APFloat::opStatus sub(const Floating &A, const Floating &B,
186 llvm::RoundingMode RM, Floating *R) {
187 *R = Floating(A.F);
188 return R->F.subtract(RHS: B.F, RM);
189 }
190
191 static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM,
192 Floating *R) {
193 APFloat One(A.F.getSemantics(), 1);
194 *R = Floating(A.F);
195 return R->F.subtract(RHS: One, RM);
196 }
197
198 static APFloat::opStatus mul(const Floating &A, const Floating &B,
199 llvm::RoundingMode RM, Floating *R) {
200 *R = Floating(A.F);
201 return R->F.multiply(RHS: B.F, RM);
202 }
203
204 static APFloat::opStatus div(const Floating &A, const Floating &B,
205 llvm::RoundingMode RM, Floating *R) {
206 *R = Floating(A.F);
207 return R->F.divide(RHS: B.F, RM);
208 }
209
210 static bool neg(const Floating &A, Floating *R) {
211 *R = -A;
212 return false;
213 }
214};
215
216llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Floating F);
217Floating getSwappedBytes(Floating F);
218
219} // namespace interp
220} // namespace clang
221
222#endif
223

source code of clang/lib/AST/ByteCode/Floating.h