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