1 //===--- Floating.h - Types for the constexpr VM ----------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // Defines the VM types and helpers operating on types.
11 //===----------------------------------------------------------------------===//
13 #ifndef LLVM_CLANG_AST_INTERP_FLOATING_H
14 #define LLVM_CLANG_AST_INTERP_FLOATING_H
16 #include "Primitives.h"
17 #include "clang/AST/APValue.h"
18 #include "llvm/ADT/APFloat.h"
23 using APFloat
= llvm::APFloat
;
24 using APSInt
= llvm::APSInt
;
26 class Floating final
{
28 // The underlying value storage.
32 /// Zero-initializes a Floating.
33 Floating() : F(0.0f
) {}
34 Floating(const APFloat
&F
) : F(F
) {}
36 // Static constructors for special floating point values.
37 static Floating
getInf(const llvm::fltSemantics
&Sem
) {
38 return Floating(APFloat::getInf(Sem
));
40 const APFloat
&getAPFloat() const { return F
; }
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
); }
50 APFloat::opStatus
convertToInteger(APSInt
&Result
) const {
52 return F
.convertToInteger(Result
, llvm::APFloat::rmTowardZero
, &IsExact
);
55 Floating
toSemantics(const llvm::fltSemantics
*Sem
,
56 llvm::RoundingMode RM
) const {
59 Copy
.convert(*Sem
, RM
, &LosesInfo
);
61 return Floating(Copy
);
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
);
69 APSInt
toAPSInt(unsigned NumBits
= 0) const {
70 return APSInt(F
.bitcastToAPInt());
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
;
79 std::string
toDiagnosticString(const ASTContext
&Ctx
) const {
81 llvm::raw_string_ostream
OS(NameStr
);
86 unsigned bitWidth() const { return F
.semanticsSizeInBits(F
.getSemantics()); }
88 bool isSigned() const { return true; }
89 bool isNegative() const { return F
.isNegative(); }
90 bool isPositive() const { return !F
.isNegative(); }
91 bool isZero() const { return F
.isZero(); }
92 bool isNonZero() const { return F
.isNonZero(); }
93 bool isMin() const { return F
.isSmallest(); }
94 bool isMinusOne() const { return F
.isExactlyValue(-1.0); }
95 bool isNan() const { return F
.isNaN(); }
96 bool isSignaling() const { return F
.isSignaling(); }
97 bool isInf() const { return F
.isInfinity(); }
98 bool isFinite() const { return F
.isFinite(); }
99 bool isNormal() const { return F
.isNormal(); }
100 bool isDenormal() const { return F
.isDenormal(); }
101 llvm::FPClassTest
classify() const { return F
.classify(); }
102 APFloat::fltCategory
getCategory() const { return F
.getCategory(); }
104 ComparisonCategoryResult
compare(const Floating
&RHS
) const {
105 llvm::APFloatBase::cmpResult CmpRes
= F
.compare(RHS
.F
);
107 case llvm::APFloatBase::cmpLessThan
:
108 return ComparisonCategoryResult::Less
;
109 case llvm::APFloatBase::cmpEqual
:
110 return ComparisonCategoryResult::Equal
;
111 case llvm::APFloatBase::cmpGreaterThan
:
112 return ComparisonCategoryResult::Greater
;
113 case llvm::APFloatBase::cmpUnordered
:
114 return ComparisonCategoryResult::Unordered
;
116 llvm_unreachable("Inavlid cmpResult value");
119 static APFloat::opStatus
fromIntegral(APSInt Val
,
120 const llvm::fltSemantics
&Sem
,
121 llvm::RoundingMode RM
,
123 APFloat F
= APFloat(Sem
);
124 APFloat::opStatus Status
= F
.convertFromAPInt(Val
, Val
.isSigned(), RM
);
125 Result
= Floating(F
);
129 static Floating
bitcastFromMemory(const std::byte
*Buff
,
130 const llvm::fltSemantics
&Sem
) {
131 size_t Size
= APFloat::semanticsSizeInBits(Sem
);
132 llvm::APInt
API(Size
, true);
133 llvm::LoadIntFromMemory(API
, (const uint8_t *)Buff
, Size
/ 8);
135 return Floating(APFloat(Sem
, API
));
138 // === Serialization support ===
139 size_t bytesToSerialize() const {
140 return sizeof(llvm::fltSemantics
*) +
141 (APFloat::semanticsSizeInBits(F
.getSemantics()) / 8);
144 void serialize(std::byte
*Buff
) const {
145 // Semantics followed by an APInt.
146 *reinterpret_cast<const llvm::fltSemantics
**>(Buff
) = &F
.getSemantics();
148 llvm::APInt API
= F
.bitcastToAPInt();
149 llvm::StoreIntToMemory(API
, (uint8_t *)(Buff
+ sizeof(void *)),
153 static Floating
deserialize(const std::byte
*Buff
) {
154 const llvm::fltSemantics
*Sem
;
155 std::memcpy((void *)&Sem
, Buff
, sizeof(void *));
156 return bitcastFromMemory(Buff
+ sizeof(void *), *Sem
);
159 static Floating
abs(const Floating
&F
) {
168 static APFloat::opStatus
add(const Floating
&A
, const Floating
&B
,
169 llvm::RoundingMode RM
, Floating
*R
) {
171 return R
->F
.add(B
.F
, RM
);
174 static APFloat::opStatus
increment(const Floating
&A
, llvm::RoundingMode RM
,
176 APFloat
One(A
.F
.getSemantics(), 1);
178 return R
->F
.add(One
, RM
);
181 static APFloat::opStatus
sub(const Floating
&A
, const Floating
&B
,
182 llvm::RoundingMode RM
, Floating
*R
) {
184 return R
->F
.subtract(B
.F
, RM
);
187 static APFloat::opStatus
decrement(const Floating
&A
, llvm::RoundingMode RM
,
189 APFloat
One(A
.F
.getSemantics(), 1);
191 return R
->F
.subtract(One
, RM
);
194 static APFloat::opStatus
mul(const Floating
&A
, const Floating
&B
,
195 llvm::RoundingMode RM
, Floating
*R
) {
197 return R
->F
.multiply(B
.F
, RM
);
200 static APFloat::opStatus
div(const Floating
&A
, const Floating
&B
,
201 llvm::RoundingMode RM
, Floating
*R
) {
203 return R
->F
.divide(B
.F
, RM
);
206 static bool neg(const Floating
&A
, Floating
*R
) {
212 llvm::raw_ostream
&operator<<(llvm::raw_ostream
&OS
, Floating F
);
213 Floating
getSwappedBytes(Floating F
);
215 } // namespace interp