clang 22.0.0git
Floating.h
Go to the documentation of this file.
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
24namespace clang {
25namespace interp {
26
27using APFloat = llvm::APFloat;
28using APSInt = llvm::APSInt;
29using 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.
35class Floating final {
36private:
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(),
49 APInt(BitWidth, llvm::ArrayRef(Memory, NumWords)));
50 }
51
52public:
53 Floating() = default;
54 Floating(llvm::APFloatBase::Semantics Semantics)
55 : Val(0), Semantics(Semantics) {}
56 Floating(const APFloat &F) {
57
58 Semantics = llvm::APFloatBase::SemanticsToEnum(F.getSemantics());
59 this->copy(F);
60 }
61 Floating(uint64_t *Memory, llvm::APFloatBase::Semantics Semantics)
62 : Memory(Memory), Semantics(Semantics) {}
63
64 APFloat getAPFloat() const { return getValue(); }
65
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 bool operator>=(Floating RHS) const { return getValue() >= RHS.getValue(); }
70
71 APFloat::opStatus convertToInteger(APSInt &Result) const {
72 bool IsExact;
73 return getValue().convertToInteger(Result, llvm::APFloat::rmTowardZero,
74 &IsExact);
75 }
76
77 void toSemantics(const llvm::fltSemantics *Sem, llvm::RoundingMode RM,
78 Floating *Result) const {
79 APFloat Copy = getValue();
80 bool LosesInfo;
81 Copy.convert(*Sem, RM, &LosesInfo);
82 (void)LosesInfo;
83 Result->copy(Copy);
84 }
85
86 APSInt toAPSInt(unsigned NumBits = 0) const {
87 return APSInt(getValue().bitcastToAPInt());
88 }
89 APValue toAPValue(const ASTContext &) const { return APValue(getValue()); }
90 void print(llvm::raw_ostream &OS) const {
91 // Can't use APFloat::print() since it appends a newline.
93 getValue().toString(Buffer);
94 OS << Buffer;
95 }
96 std::string toDiagnosticString(const ASTContext &Ctx) const {
97 std::string NameStr;
98 llvm::raw_string_ostream OS(NameStr);
99 print(OS);
100 return NameStr;
101 }
102
103 unsigned bitWidth() const {
104 return llvm::APFloatBase::semanticsSizeInBits(getSemantics());
105 }
106 unsigned numWords() const { return llvm::APInt::getNumWords(bitWidth()); }
107 bool singleWord() const {
108#if ALLOCATE_ALL
109 return false;
110#endif
111 return numWords() == 1;
112 }
113 static bool singleWord(const llvm::fltSemantics &Sem) {
114#if ALLOCATE_ALL
115 return false;
116#endif
117 return APInt::getNumWords(llvm::APFloatBase::getSizeInBits(Sem)) == 1;
118 }
119 const llvm::fltSemantics &getSemantics() const {
120 return llvm::APFloatBase::EnumToSemantics(Semantics);
121 }
122
123 void copy(const APFloat &F) {
124 if (singleWord()) {
125 Val = F.bitcastToAPInt().getZExtValue();
126 } else {
127 assert(Memory);
128 std::memcpy(Memory, F.bitcastToAPInt().getRawData(),
129 numWords() * sizeof(uint64_t));
130 }
131 }
132
133 void take(uint64_t *NewMemory) {
134 if (singleWord())
135 return;
136
137 if (Memory)
138 std::memcpy(NewMemory, Memory, numWords() * sizeof(uint64_t));
139 Memory = NewMemory;
140 }
141
142 bool isSigned() const { return true; }
143 bool isNegative() const { return getValue().isNegative(); }
144 bool isZero() const { return getValue().isZero(); }
145 bool isNonZero() const { return getValue().isNonZero(); }
146 bool isMin() const { return getValue().isSmallest(); }
147 bool isMinusOne() const { return getValue().isExactlyValue(-1.0); }
148 bool isNan() const { return getValue().isNaN(); }
149 bool isSignaling() const { return getValue().isSignaling(); }
150 bool isInf() const { return getValue().isInfinity(); }
151 bool isFinite() const { return getValue().isFinite(); }
152 bool isNormal() const { return getValue().isNormal(); }
153 bool isDenormal() const { return getValue().isDenormal(); }
154 llvm::FPClassTest classify() const { return getValue().classify(); }
155 APFloat::fltCategory getCategory() const { return getValue().getCategory(); }
156
158 llvm::APFloatBase::cmpResult CmpRes = getValue().compare(RHS.getValue());
159 switch (CmpRes) {
160 case llvm::APFloatBase::cmpLessThan:
162 case llvm::APFloatBase::cmpEqual:
164 case llvm::APFloatBase::cmpGreaterThan:
166 case llvm::APFloatBase::cmpUnordered:
168 }
169 llvm_unreachable("Inavlid cmpResult value");
170 }
171
172 static APFloat::opStatus fromIntegral(APSInt Val,
173 const llvm::fltSemantics &Sem,
174 llvm::RoundingMode RM,
175 Floating *Result) {
176 APFloat F = APFloat(Sem);
177 APFloat::opStatus Status = F.convertFromAPInt(Val, Val.isSigned(), RM);
178 Result->copy(F);
179 return Status;
180 }
181
182 static void bitcastFromMemory(const std::byte *Buff,
183 const llvm::fltSemantics &Sem,
184 Floating *Result) {
185 size_t Size = APFloat::semanticsSizeInBits(Sem);
186 llvm::APInt API(Size, true);
187 llvm::LoadIntFromMemory(API, (const uint8_t *)Buff, Size / 8);
188 Result->copy(APFloat(Sem, API));
189 }
190
191 void bitcastToMemory(std::byte *Buff) const {
192 llvm::APInt API = getValue().bitcastToAPInt();
193 llvm::StoreIntToMemory(API, (uint8_t *)Buff, bitWidth() / 8);
194 }
195
196 // === Serialization support ===
197 size_t bytesToSerialize() const {
198 return sizeof(Semantics) + (numWords() * sizeof(uint64_t));
199 }
200
201 void serialize(std::byte *Buff) const {
202 std::memcpy(Buff, &Semantics, sizeof(Semantics));
203 if (singleWord()) {
204 std::memcpy(Buff + sizeof(Semantics), &Val, sizeof(uint64_t));
205 } else {
206 std::memcpy(Buff + sizeof(Semantics), Memory,
207 numWords() * sizeof(uint64_t));
208 }
209 }
210
211 static llvm::APFloatBase::Semantics
212 deserializeSemantics(const std::byte *Buff) {
213 return *reinterpret_cast<const llvm::APFloatBase::Semantics *>(Buff);
214 }
215
216 static void deserialize(const std::byte *Buff, Floating *Result) {
217 llvm::APFloatBase::Semantics Semantics;
218 std::memcpy(&Semantics, Buff, sizeof(Semantics));
219
220 unsigned BitWidth = llvm::APFloat::semanticsSizeInBits(
221 llvm::APFloatBase::EnumToSemantics(Semantics));
222 unsigned NumWords = llvm::APInt::getNumWords(BitWidth);
223
224 Result->Semantics = Semantics;
225 if (NumWords == 1 && !ALLOCATE_ALL) {
226 std::memcpy(&Result->Val, Buff + sizeof(Semantics), sizeof(uint64_t));
227 } else {
228 assert(Result->Memory);
229 std::memcpy(Result->Memory, Buff + sizeof(Semantics),
230 NumWords * sizeof(uint64_t));
231 }
232 }
233
234 // -------
235
236 static APFloat::opStatus add(const Floating &A, const Floating &B,
237 llvm::RoundingMode RM, Floating *R) {
238 APFloat LHS = A.getValue();
239 APFloat RHS = B.getValue();
240
241 auto Status = LHS.add(RHS, RM);
242 R->copy(LHS);
243 return Status;
244 }
245
246 static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM,
247 Floating *R) {
248 APFloat One(A.getSemantics(), 1);
249 APFloat LHS = A.getValue();
250
251 auto Status = LHS.add(One, RM);
252 R->copy(LHS);
253 return Status;
254 }
255
256 static APFloat::opStatus sub(const Floating &A, const Floating &B,
257 llvm::RoundingMode RM, Floating *R) {
258 APFloat LHS = A.getValue();
259 APFloat RHS = B.getValue();
260
261 auto Status = LHS.subtract(RHS, RM);
262 R->copy(LHS);
263 return Status;
264 }
265
266 static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM,
267 Floating *R) {
268 APFloat One(A.getSemantics(), 1);
269 APFloat LHS = A.getValue();
270
271 auto Status = LHS.subtract(One, RM);
272 R->copy(LHS);
273 return Status;
274 }
275
276 static APFloat::opStatus mul(const Floating &A, const Floating &B,
277 llvm::RoundingMode RM, Floating *R) {
278
279 APFloat LHS = A.getValue();
280 APFloat RHS = B.getValue();
281
282 auto Status = LHS.multiply(RHS, RM);
283 R->copy(LHS);
284 return Status;
285 }
286
287 static APFloat::opStatus div(const Floating &A, const Floating &B,
288 llvm::RoundingMode RM, Floating *R) {
289 APFloat LHS = A.getValue();
290 APFloat RHS = B.getValue();
291
292 auto Status = LHS.divide(RHS, RM);
293 R->copy(LHS);
294 return Status;
295 }
296
297 static bool neg(const Floating &A, Floating *R) {
298 R->copy(-A.getValue());
299 return false;
300 }
301};
302
303llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Floating F);
304Floating getSwappedBytes(Floating F);
305
306} // namespace interp
307} // namespace clang
308
309#endif
#define ALLOCATE_ALL
Definition Floating.h:22
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
Definition APValue.h:122
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:220
bool operator<(Floating RHS) const
Definition Floating.h:66
static APFloat::opStatus div(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
Definition Floating.h:287
static llvm::APFloatBase::Semantics deserializeSemantics(const std::byte *Buff)
Definition Floating.h:212
void copy(const APFloat &F)
Definition Floating.h:123
static APFloat::opStatus fromIntegral(APSInt Val, const llvm::fltSemantics &Sem, llvm::RoundingMode RM, Floating *Result)
Definition Floating.h:172
void print(llvm::raw_ostream &OS) const
Definition Floating.h:90
APSInt toAPSInt(unsigned NumBits=0) const
Definition Floating.h:86
void serialize(std::byte *Buff) const
Definition Floating.h:201
static APFloat::opStatus sub(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
Definition Floating.h:256
llvm::FPClassTest classify() const
Definition Floating.h:154
Floating(llvm::APFloatBase::Semantics Semantics)
Definition Floating.h:54
bool operator>(Floating RHS) const
Definition Floating.h:67
bool isSignaling() const
Definition Floating.h:149
unsigned bitWidth() const
Definition Floating.h:103
bool isNormal() const
Definition Floating.h:152
ComparisonCategoryResult compare(const Floating &RHS) const
Definition Floating.h:157
static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM, Floating *R)
Definition Floating.h:246
bool operator>=(Floating RHS) const
Definition Floating.h:69
void take(uint64_t *NewMemory)
Definition Floating.h:133
bool isSigned() const
Definition Floating.h:142
bool operator<=(Floating RHS) const
Definition Floating.h:68
unsigned numWords() const
Definition Floating.h:106
size_t bytesToSerialize() const
Definition Floating.h:197
static APFloat::opStatus add(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
Definition Floating.h:236
static void deserialize(const std::byte *Buff, Floating *Result)
Definition Floating.h:216
static APFloat::opStatus mul(const Floating &A, const Floating &B, llvm::RoundingMode RM, Floating *R)
Definition Floating.h:276
bool isNonZero() const
Definition Floating.h:145
void toSemantics(const llvm::fltSemantics *Sem, llvm::RoundingMode RM, Floating *Result) const
Definition Floating.h:77
std::string toDiagnosticString(const ASTContext &Ctx) const
Definition Floating.h:96
const llvm::fltSemantics & getSemantics() const
Definition Floating.h:119
bool isZero() const
Definition Floating.h:144
bool isNegative() const
Definition Floating.h:143
Floating(uint64_t *Memory, llvm::APFloatBase::Semantics Semantics)
Definition Floating.h:61
static bool neg(const Floating &A, Floating *R)
Definition Floating.h:297
bool isFinite() const
Definition Floating.h:151
static bool singleWord(const llvm::fltSemantics &Sem)
Definition Floating.h:113
static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM, Floating *R)
Definition Floating.h:266
Floating(const APFloat &F)
Definition Floating.h:56
bool isDenormal() const
Definition Floating.h:153
bool isMinusOne() const
Definition Floating.h:147
bool singleWord() const
Definition Floating.h:107
APFloat::opStatus convertToInteger(APSInt &Result) const
Definition Floating.h:71
APValue toAPValue(const ASTContext &) const
Definition Floating.h:89
APFloat::fltCategory getCategory() const
Definition Floating.h:155
void bitcastToMemory(std::byte *Buff) const
Definition Floating.h:191
static void bitcastFromMemory(const std::byte *Buff, const llvm::fltSemantics &Sem, Floating *Result)
Definition Floating.h:182
APFloat getAPFloat() const
Definition Floating.h:64
FixedPoint getSwappedBytes(FixedPoint F)
Definition FixedPoint.h:188
llvm::APFloat APFloat
Definition Floating.h:27
llvm::APInt APInt
Definition FixedPoint.h:19
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const Boolean &B)
Definition Boolean.h:154
llvm::APSInt APSInt
Definition FixedPoint.h:20
The JSON file list parser is used to communicate input to InstallAPI.
ComparisonCategoryResult
An enumeration representing the possible results of a three-way comparison.
@ Result
The result type of a method or function.
Definition TypeBase.h:905