Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/AST/ByteCode/Floating.h
213799 views
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
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;
53
Floating(llvm::APFloatBase::Semantics Semantics)
54
: Val(0), Semantics(Semantics) {}
55
Floating(const APFloat &F) {
56
57
Semantics = llvm::APFloatBase::SemanticsToEnum(F.getSemantics());
58
this->copy(F);
59
}
60
Floating(uint64_t *Memory, llvm::APFloatBase::Semantics Semantics)
61
: Memory(Memory), Semantics(Semantics) {}
62
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
70
APFloat::opStatus convertToInteger(APSInt &Result) const {
71
bool IsExact;
72
return getValue().convertToInteger(Result, llvm::APFloat::rmTowardZero,
73
&IsExact);
74
}
75
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
}
88
APValue toAPValue(const ASTContext &) const { return APValue(getValue()); }
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
}
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
102
unsigned bitWidth() const {
103
return llvm::APFloatBase::semanticsSizeInBits(getSemantics());
104
}
105
unsigned numWords() const { return llvm::APInt::getNumWords(bitWidth()); }
106
bool singleWord() const {
107
#if ALLOCATE_ALL
108
return false;
109
#endif
110
return numWords() == 1;
111
}
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
}
118
const llvm::fltSemantics &getSemantics() const {
119
return llvm::APFloatBase::EnumToSemantics(Semantics);
120
}
121
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
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
141
bool isSigned() const { return true; }
142
bool isNegative() const { return getValue().isNegative(); }
143
bool isZero() const { return getValue().isZero(); }
144
bool isNonZero() const { return getValue().isNonZero(); }
145
bool isMin() const { return getValue().isSmallest(); }
146
bool isMinusOne() const { return getValue().isExactlyValue(-1.0); }
147
bool isNan() const { return getValue().isNaN(); }
148
bool isSignaling() const { return getValue().isSignaling(); }
149
bool isInf() const { return getValue().isInfinity(); }
150
bool isFinite() const { return getValue().isFinite(); }
151
bool isNormal() const { return getValue().isNormal(); }
152
bool isDenormal() const { return getValue().isDenormal(); }
153
llvm::FPClassTest classify() const { return getValue().classify(); }
154
APFloat::fltCategory getCategory() const { return getValue().getCategory(); }
155
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
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
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
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 ===
196
size_t bytesToSerialize() const {
197
return sizeof(Semantics) + (numWords() * sizeof(uint64_t));
198
}
199
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
211
deserializeSemantics(const std::byte *Buff) {
212
return *reinterpret_cast<const llvm::APFloatBase::Semantics *>(Buff);
213
}
214
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
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
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
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
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
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
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
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
310