• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef BERBERIS_INTRINSICS_INTRINSICS_FLOAT_H_
18 #define BERBERIS_INTRINSICS_INTRINSICS_FLOAT_H_
19 
20 // We couldn't safely pass arguments using "raw" float and double on X86 because of peculiarities
21 // of psABI (sometimes floating point registers are used by guest programs to pass integer value and
22 // certain integers when converted to fp80 type and back become corrupted).
23 //
24 // To make sure that we wouldn't use it to return value by accident we would wrap them and use class
25 // which makes such mistakes unlikely on x86.
26 //
27 // It's safe to pass "raw" values as float and double on modern ABI (RISC-V UABI, x86-64 psABI, etc).
28 //
29 // NOTE: That type must be layout-compatible with underlying type thus it must ONLY have one field
30 // value_ inside.
31 //
32 // NOTE: It's perfectly safe to do bit_cast<uint32_t>(Float32) or bit_cast<Float64>(uint64_t).
33 // Yet it's NOT safe to do bit_cast<float>(Float32) or bit_cast<Float64>(double). This is because
34 // bit_cast itself is just a regular function and is affected by that psABI issue as well.
35 //
36 // If you need to convert between float/double and Float32/Float64 then you have to use memcpy
37 // and couldn't use any helper function which would receive or return raw float or double value.
38 
39 #include <stdint.h>
40 
41 #include <limits>
42 
43 #include "berberis/base/bit_util.h"
44 
45 namespace berberis {
46 
47 namespace intrinsics {
48 
49 enum class FPInfo { kNaN, kInfinite, kNormal, kSubnormal, kZero };
50 
51 template <typename BaseType>
52 class WrappedFloatType {
53  public:
54   constexpr WrappedFloatType() = default;
WrappedFloatType(BaseType value)55   explicit constexpr WrappedFloatType(BaseType value) : value_(value) {}
56   constexpr WrappedFloatType(const WrappedFloatType& other) = default;
57   constexpr WrappedFloatType(WrappedFloatType&& other) noexcept = default;
58   WrappedFloatType& operator=(const WrappedFloatType& other) = default;
59   WrappedFloatType& operator=(WrappedFloatType&& other) noexcept = default;
60   ~WrappedFloatType() = default;
int16_t()61   explicit constexpr operator int16_t() const { return value_; }
uint16_t()62   explicit constexpr operator uint16_t() const { return value_; }
int32_t()63   explicit constexpr operator int32_t() const { return value_; }
uint32_t()64   explicit constexpr operator uint32_t() const { return value_; }
int64_t()65   explicit constexpr operator int64_t() const { return value_; }
uint64_t()66   explicit constexpr operator uint64_t() const { return value_; }
67   explicit constexpr operator WrappedFloatType<float>() const {
68     return WrappedFloatType<float>(value_);
69   }
70   explicit constexpr operator WrappedFloatType<double>() const {
71     return WrappedFloatType<double>(value_);
72   }
73 #if defined(__i386__) || defined(__x86_64__)
74   explicit constexpr operator long double() const { return value_; }
75 #endif
76   // Note: we don't provide unary operator-.  That's done on purpose: with floats -x and 0.-x
77   // produce different results which could be surprising.  Use fneg instead of unary operator-.
78   friend WrappedFloatType operator+(const WrappedFloatType& v1, const WrappedFloatType& v2);
79   friend WrappedFloatType& operator+=(WrappedFloatType& v1, const WrappedFloatType& v2);
80   friend WrappedFloatType operator-(const WrappedFloatType& v1, const WrappedFloatType& v2);
81   friend WrappedFloatType& operator-=(WrappedFloatType& v1, const WrappedFloatType& v2);
82   friend WrappedFloatType operator*(const WrappedFloatType& v1, const WrappedFloatType& v2);
83   friend WrappedFloatType& operator*=(WrappedFloatType& v1, const WrappedFloatType& v2);
84   friend WrappedFloatType operator/(const WrappedFloatType& v1, const WrappedFloatType& v2);
85   friend WrappedFloatType& operator/=(WrappedFloatType& v1, const WrappedFloatType& v2);
86   friend bool operator==(const WrappedFloatType& v1, const WrappedFloatType& v2);
87   friend bool operator!=(const WrappedFloatType& v1, const WrappedFloatType& v2);
88   friend bool operator<(const WrappedFloatType& v1, const WrappedFloatType& v2);
89   friend bool operator<=(const WrappedFloatType& v1, const WrappedFloatType& v2);
90   friend bool operator>(const WrappedFloatType& v1, const WrappedFloatType& v2);
91   friend bool operator>=(const WrappedFloatType& v1, const WrappedFloatType& v2);
92   friend inline WrappedFloatType CopySignBit(const WrappedFloatType& v1,
93                                              const WrappedFloatType& v2);
94   friend inline WrappedFloatType Absolute(const WrappedFloatType& v);
95   friend inline WrappedFloatType Negative(const WrappedFloatType& v);
96   friend inline FPInfo FPClassify(const WrappedFloatType& v);
97   friend inline WrappedFloatType FPRound(const WrappedFloatType& value, uint32_t round_control);
98   friend inline int IsNan(const WrappedFloatType& v);
99   friend inline int SignBit(const WrappedFloatType& v);
100   friend inline WrappedFloatType Sqrt(const WrappedFloatType& v);
101   friend inline WrappedFloatType MulAdd(const WrappedFloatType& v1,
102                                         const WrappedFloatType& v2,
103                                         const WrappedFloatType& v3);
104 
105  private:
106   static_assert(!std::numeric_limits<BaseType>::is_exact,
107                 "WrappedFloatType should only be used with float types!");
108   BaseType value_;
109 };
110 
111 using Float32 = WrappedFloatType<float>;
112 using Float64 = WrappedFloatType<double>;
113 
114 }  // namespace intrinsics
115 
116 }  // namespace berberis
117 
118 namespace std {
119 
120 template <typename BaseType>
121 class numeric_limits<berberis::intrinsics::WrappedFloatType<BaseType>> {
122  public:
123   static constexpr bool is_specialized = true;
124   static constexpr bool is_signed = true;
125   static constexpr bool is_integer = false;
126   static constexpr bool is_exact = false;
127   static constexpr bool has_infinity = true;
128   static constexpr bool has_quiet_NaN = std::numeric_limits<BaseType>::has_quiet_NaN;
129   static constexpr bool has_signaling_NaN = std::numeric_limits<BaseType>::has_signaling_NaN;
130   static constexpr std::float_denorm_style has_denorm = std::numeric_limits<BaseType>::has_denorm;
131   static constexpr bool has_denorm_loss = std::numeric_limits<BaseType>::has_denorm_loss;
132   static constexpr std::float_round_style round_style = std::numeric_limits<BaseType>::round_style;
133   static constexpr bool is_iec559 = std::numeric_limits<BaseType>::is_iec559;
134   static constexpr bool is_bounded = true;
135   static constexpr bool is_modulo = false;
136   static constexpr int digits = std::numeric_limits<BaseType>::digits;
137   static constexpr int digits10 = std::numeric_limits<BaseType>::digits10;
138   static constexpr int max_digits10 = std::numeric_limits<BaseType>::max_digits10;
139   static constexpr int radix = std::numeric_limits<BaseType>::radix;
140   static constexpr int min_exponent = std::numeric_limits<BaseType>::min_exponent;
141   static constexpr int min_exponent10 = std::numeric_limits<BaseType>::min_exponent10;
142   static constexpr int max_exponent = std::numeric_limits<BaseType>::max_exponent;
143   static constexpr int max_exponent10 = std::numeric_limits<BaseType>::max_exponent10;
144   static constexpr bool traps = std::numeric_limits<BaseType>::traps;
145   static constexpr bool tinyness_before = std::numeric_limits<BaseType>::tinyness_before;
min()146   static constexpr berberis::intrinsics::WrappedFloatType<BaseType> min() {
147     return berberis::intrinsics::WrappedFloatType<BaseType>(std::numeric_limits<BaseType>::min());
148   }
lowest()149   static constexpr berberis::intrinsics::WrappedFloatType<BaseType> lowest() {
150     return berberis::intrinsics::WrappedFloatType<BaseType>(
151         std::numeric_limits<BaseType>::lowest());
152   }
max()153   static constexpr berberis::intrinsics::WrappedFloatType<BaseType> max() {
154     return berberis::intrinsics::WrappedFloatType<BaseType>(std::numeric_limits<BaseType>::max());
155   }
epsilon()156   static constexpr berberis::intrinsics::WrappedFloatType<BaseType> epsilon() {
157     return berberis::intrinsics::WrappedFloatType<BaseType>(
158         std::numeric_limits<BaseType>::epsilon());
159   }
round_error()160   static constexpr berberis::intrinsics::WrappedFloatType<BaseType> round_error() {
161     return berberis::intrinsics::WrappedFloatType<BaseType>(
162         std::numeric_limits<BaseType>::round_error());
163   }
infinity()164   static constexpr berberis::intrinsics::WrappedFloatType<BaseType> infinity() {
165     return berberis::intrinsics::WrappedFloatType<BaseType>(
166         std::numeric_limits<BaseType>::infinity());
167   }
quiet_NaN()168   static constexpr berberis::intrinsics::WrappedFloatType<BaseType> quiet_NaN() {
169     return berberis::intrinsics::WrappedFloatType<BaseType>(
170         std::numeric_limits<BaseType>::quiet_NaN());
171   }
signaling_NaN()172   static constexpr berberis::intrinsics::WrappedFloatType<BaseType> signaling_NaN() {
173     return berberis::intrinsics::WrappedFloatType<BaseType>(
174         std::numeric_limits<BaseType>::signaling_NaN());
175   }
denorm_min()176   static constexpr berberis::intrinsics::WrappedFloatType<BaseType> denorm_min() {
177     return berberis::intrinsics::WrappedFloatType<BaseType>(
178         std::numeric_limits<BaseType>::denorm_min());
179   }
180 };
181 
182 }  // namespace std
183 
184 // Export arch-specific definitions as well.
185 #if defined(__i386__) || defined(__x86_64__)
186 #include "berberis/intrinsics/intrinsics_float_x86.h"
187 #endif
188 
189 #endif  // BERBERIS_INTRINSICS_INTRINSICS_FLOAT_H_
190