Coverage Report

Created: 2024-01-17 10:31

/src/llvm-project/clang/lib/AST/Interp/Floating.h
Line
Count
Source (jump to first uncovered line)
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
0
  Floating() : F(0.0f) {}
34
0
  Floating(const APFloat &F) : F(F) {}
35
36
  // Static constructors for special floating point values.
37
0
  static Floating getInf(const llvm::fltSemantics &Sem) {
38
0
    return Floating(APFloat::getInf(Sem));
39
0
  }
40
0
  const APFloat &getAPFloat() const { return F; }
41
42
0
  bool operator<(Floating RHS) const { return F < RHS.F; }
43
0
  bool operator>(Floating RHS) const { return F > RHS.F; }
44
0
  bool operator<=(Floating RHS) const { return F <= RHS.F; }
45
0
  bool operator>=(Floating RHS) const { return F >= RHS.F; }
46
0
  bool operator==(Floating RHS) const { return F == RHS.F; }
47
0
  bool operator!=(Floating RHS) const { return F != RHS.F; }
48
0
  Floating operator-() const { return Floating(-F); }
49
50
0
  APFloat::opStatus convertToInteger(APSInt &Result) const {
51
0
    bool IsExact;
52
0
    return F.convertToInteger(Result, llvm::APFloat::rmTowardZero, &IsExact);
53
0
  }
54
55
  Floating toSemantics(const llvm::fltSemantics *Sem,
56
0
                       llvm::RoundingMode RM) const {
57
0
    APFloat Copy = F;
58
0
    bool LosesInfo;
59
0
    Copy.convert(*Sem, RM, &LosesInfo);
60
0
    (void)LosesInfo;
61
0
    return Floating(Copy);
62
0
  }
63
64
  /// Convert this Floating to one with the same semantics as \Other.
65
0
  Floating toSemantics(const Floating &Other, llvm::RoundingMode RM) const {
66
0
    return toSemantics(&Other.F.getSemantics(), RM);
67
0
  }
68
69
0
  APSInt toAPSInt(unsigned NumBits = 0) const {
70
0
    return APSInt(F.bitcastToAPInt());
71
0
  }
72
0
  APValue toAPValue() const { return APValue(F); }
73
0
  void print(llvm::raw_ostream &OS) const {
74
    // Can't use APFloat::print() since it appends a newline.
75
0
    SmallVector<char, 16> Buffer;
76
0
    F.toString(Buffer);
77
0
    OS << Buffer;
78
0
  }
79
0
  std::string toDiagnosticString(const ASTContext &Ctx) const {
80
0
    std::string NameStr;
81
0
    llvm::raw_string_ostream OS(NameStr);
82
0
    print(OS);
83
0
    return NameStr;
84
0
  }
85
86
0
  unsigned bitWidth() const { return F.semanticsSizeInBits(F.getSemantics()); }
87
88
0
  bool isSigned() const { return true; }
89
0
  bool isNegative() const { return F.isNegative(); }
90
0
  bool isPositive() const { return !F.isNegative(); }
91
0
  bool isZero() const { return F.isZero(); }
92
0
  bool isNonZero() const { return F.isNonZero(); }
93
0
  bool isMin() const { return F.isSmallest(); }
94
0
  bool isMinusOne() const { return F.isExactlyValue(-1.0); }
95
0
  bool isNan() const { return F.isNaN(); }
96
0
  bool isSignaling() const { return F.isSignaling(); }
97
0
  bool isInf() const { return F.isInfinity(); }
98
0
  bool isFinite() const { return F.isFinite(); }
99
0
  bool isNormal() const { return F.isNormal(); }
100
0
  bool isDenormal() const { return F.isDenormal(); }
101
0
  llvm::FPClassTest classify() const { return F.classify(); }
102
0
  APFloat::fltCategory getCategory() const { return F.getCategory(); }
103
104
0
  ComparisonCategoryResult compare(const Floating &RHS) const {
105
0
    llvm::APFloatBase::cmpResult CmpRes = F.compare(RHS.F);
106
0
    switch (CmpRes) {
107
0
    case llvm::APFloatBase::cmpLessThan:
108
0
      return ComparisonCategoryResult::Less;
109
0
    case llvm::APFloatBase::cmpEqual:
110
0
      return ComparisonCategoryResult::Equal;
111
0
    case llvm::APFloatBase::cmpGreaterThan:
112
0
      return ComparisonCategoryResult::Greater;
113
0
    case llvm::APFloatBase::cmpUnordered:
114
0
      return ComparisonCategoryResult::Unordered;
115
0
    }
116
0
    llvm_unreachable("Inavlid cmpResult value");
117
0
  }
118
119
  static APFloat::opStatus fromIntegral(APSInt Val,
120
                                        const llvm::fltSemantics &Sem,
121
                                        llvm::RoundingMode RM,
122
0
                                        Floating &Result) {
123
0
    APFloat F = APFloat(Sem);
124
0
    APFloat::opStatus Status = F.convertFromAPInt(Val, Val.isSigned(), RM);
125
0
    Result = Floating(F);
126
0
    return Status;
127
0
  }
128
129
  static Floating bitcastFromMemory(const std::byte *Buff,
130
0
                                    const llvm::fltSemantics &Sem) {
131
0
    size_t Size = APFloat::semanticsSizeInBits(Sem);
132
0
    llvm::APInt API(Size, true);
133
0
    llvm::LoadIntFromMemory(API, (const uint8_t *)Buff, Size / 8);
134
135
0
    return Floating(APFloat(Sem, API));
136
0
  }
137
138
  // === Serialization support ===
139
0
  size_t bytesToSerialize() const {
140
0
    return sizeof(llvm::fltSemantics *) +
141
0
           (APFloat::semanticsSizeInBits(F.getSemantics()) / 8);
142
0
  }
143
144
0
  void serialize(std::byte *Buff) const {
145
    // Semantics followed by an APInt.
146
0
    *reinterpret_cast<const llvm::fltSemantics **>(Buff) = &F.getSemantics();
147
148
0
    llvm::APInt API = F.bitcastToAPInt();
149
0
    llvm::StoreIntToMemory(API, (uint8_t *)(Buff + sizeof(void *)),
150
0
                           bitWidth() / 8);
151
0
  }
152
153
0
  static Floating deserialize(const std::byte *Buff) {
154
0
    const llvm::fltSemantics *Sem;
155
0
    std::memcpy((void *)&Sem, Buff, sizeof(void *));
156
0
    return bitcastFromMemory(Buff + sizeof(void *), *Sem);
157
0
  }
158
159
0
  static Floating abs(const Floating &F) {
160
0
    APFloat V = F.F;
161
0
    if (V.isNegative())
162
0
      V.changeSign();
163
0
    return Floating(V);
164
0
  }
165
166
  // -------
167
168
  static APFloat::opStatus add(const Floating &A, const Floating &B,
169
0
                               llvm::RoundingMode RM, Floating *R) {
170
0
    *R = Floating(A.F);
171
0
    return R->F.add(B.F, RM);
172
0
  }
173
174
  static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM,
175
0
                                     Floating *R) {
176
0
    APFloat One(A.F.getSemantics(), 1);
177
0
    *R = Floating(A.F);
178
0
    return R->F.add(One, RM);
179
0
  }
180
181
  static APFloat::opStatus sub(const Floating &A, const Floating &B,
182
0
                               llvm::RoundingMode RM, Floating *R) {
183
0
    *R = Floating(A.F);
184
0
    return R->F.subtract(B.F, RM);
185
0
  }
186
187
  static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM,
188
0
                                     Floating *R) {
189
0
    APFloat One(A.F.getSemantics(), 1);
190
0
    *R = Floating(A.F);
191
0
    return R->F.subtract(One, RM);
192
0
  }
193
194
  static APFloat::opStatus mul(const Floating &A, const Floating &B,
195
0
                               llvm::RoundingMode RM, Floating *R) {
196
0
    *R = Floating(A.F);
197
0
    return R->F.multiply(B.F, RM);
198
0
  }
199
200
  static APFloat::opStatus div(const Floating &A, const Floating &B,
201
0
                               llvm::RoundingMode RM, Floating *R) {
202
0
    *R = Floating(A.F);
203
0
    return R->F.divide(B.F, RM);
204
0
  }
205
206
0
  static bool neg(const Floating &A, Floating *R) {
207
0
    *R = -A;
208
0
    return false;
209
0
  }
210
};
211
212
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Floating F);
213
Floating getSwappedBytes(Floating F);
214
215
} // namespace interp
216
} // namespace clang
217
218
#endif