1 // Copyright 2016 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <math.h> 6 #include <stdint.h> 7 #include <stdlib.h> 8 #include <limits> 9 10 #include "include/v8config.h" 11 12 #include "src/base/bits.h" 13 #include "src/utils.h" 14 #include "src/wasm/wasm-external-refs.h" 15 16 namespace v8 { 17 namespace internal { 18 namespace wasm { 19 20 void f32_trunc_wrapper(float* param) { *param = truncf(*param); } 21 22 void f32_floor_wrapper(float* param) { *param = floorf(*param); } 23 24 void f32_ceil_wrapper(float* param) { *param = ceilf(*param); } 25 26 void f32_nearest_int_wrapper(float* param) { *param = nearbyintf(*param); } 27 28 void f64_trunc_wrapper(double* param) { 29 WriteDoubleValue(param, trunc(ReadDoubleValue(param))); 30 } 31 32 void f64_floor_wrapper(double* param) { 33 WriteDoubleValue(param, floor(ReadDoubleValue(param))); 34 } 35 36 void f64_ceil_wrapper(double* param) { 37 WriteDoubleValue(param, ceil(ReadDoubleValue(param))); 38 } 39 40 void f64_nearest_int_wrapper(double* param) { 41 WriteDoubleValue(param, nearbyint(ReadDoubleValue(param))); 42 } 43 44 void int64_to_float32_wrapper(int64_t* input, float* output) { 45 *output = static_cast<float>(*input); 46 } 47 48 void uint64_to_float32_wrapper(uint64_t* input, float* output) { 49 #if V8_CC_MSVC 50 // With MSVC we use static_cast<float>(uint32_t) instead of 51 // static_cast<float>(uint64_t) to achieve round-to-nearest-ties-even 52 // semantics. The idea is to calculate 53 // static_cast<float>(high_word) * 2^32 + static_cast<float>(low_word). To 54 // achieve proper rounding in all cases we have to adjust the high_word 55 // with a "rounding bit" sometimes. The rounding bit is stored in the LSB of 56 // the high_word if the low_word may affect the rounding of the high_word. 57 uint32_t low_word = static_cast<uint32_t>(*input & 0xffffffff); 58 uint32_t high_word = static_cast<uint32_t>(*input >> 32); 59 60 float shift = static_cast<float>(1ull << 32); 61 // If the MSB of the high_word is set, then we make space for a rounding bit. 62 if (high_word < 0x80000000) { 63 high_word <<= 1; 64 shift = static_cast<float>(1ull << 31); 65 } 66 67 if ((high_word & 0xfe000000) && low_word) { 68 // Set the rounding bit. 69 high_word |= 1; 70 } 71 72 float result = static_cast<float>(high_word); 73 result *= shift; 74 result += static_cast<float>(low_word); 75 *output = result; 76 77 #else 78 *output = static_cast<float>(*input); 79 #endif 80 } 81 82 void int64_to_float64_wrapper(int64_t* input, double* output) { 83 *output = static_cast<double>(*input); 84 } 85 86 void uint64_to_float64_wrapper(uint64_t* input, double* output) { 87 #if V8_CC_MSVC 88 // With MSVC we use static_cast<double>(uint32_t) instead of 89 // static_cast<double>(uint64_t) to achieve round-to-nearest-ties-even 90 // semantics. The idea is to calculate 91 // static_cast<double>(high_word) * 2^32 + static_cast<double>(low_word). 92 uint32_t low_word = static_cast<uint32_t>(*input & 0xffffffff); 93 uint32_t high_word = static_cast<uint32_t>(*input >> 32); 94 95 double shift = static_cast<double>(1ull << 32); 96 97 double result = static_cast<double>(high_word); 98 result *= shift; 99 result += static_cast<double>(low_word); 100 *output = result; 101 102 #else 103 *output = static_cast<double>(*input); 104 #endif 105 } 106 107 int32_t float32_to_int64_wrapper(float* input, int64_t* output) { 108 // We use "<" here to check the upper bound because of rounding problems: With 109 // "<=" some inputs would be considered within int64 range which are actually 110 // not within int64 range. 111 if (*input >= static_cast<float>(std::numeric_limits<int64_t>::min()) && 112 *input < static_cast<float>(std::numeric_limits<int64_t>::max())) { 113 *output = static_cast<int64_t>(*input); 114 return 1; 115 } 116 return 0; 117 } 118 119 int32_t float32_to_uint64_wrapper(float* input, uint64_t* output) { 120 // We use "<" here to check the upper bound because of rounding problems: With 121 // "<=" some inputs would be considered within uint64 range which are actually 122 // not within uint64 range. 123 if (*input > -1.0 && 124 *input < static_cast<float>(std::numeric_limits<uint64_t>::max())) { 125 *output = static_cast<uint64_t>(*input); 126 return 1; 127 } 128 return 0; 129 } 130 131 int32_t float64_to_int64_wrapper(double* input, int64_t* output) { 132 // We use "<" here to check the upper bound because of rounding problems: With 133 // "<=" some inputs would be considered within int64 range which are actually 134 // not within int64 range. 135 if (*input >= static_cast<double>(std::numeric_limits<int64_t>::min()) && 136 *input < static_cast<double>(std::numeric_limits<int64_t>::max())) { 137 *output = static_cast<int64_t>(*input); 138 return 1; 139 } 140 return 0; 141 } 142 143 int32_t float64_to_uint64_wrapper(double* input, uint64_t* output) { 144 // We use "<" here to check the upper bound because of rounding problems: With 145 // "<=" some inputs would be considered within uint64 range which are actually 146 // not within uint64 range. 147 if (*input > -1.0 && 148 *input < static_cast<double>(std::numeric_limits<uint64_t>::max())) { 149 *output = static_cast<uint64_t>(*input); 150 return 1; 151 } 152 return 0; 153 } 154 155 int32_t int64_div_wrapper(int64_t* dst, int64_t* src) { 156 if (*src == 0) { 157 return 0; 158 } 159 if (*src == -1 && *dst == std::numeric_limits<int64_t>::min()) { 160 return -1; 161 } 162 *dst /= *src; 163 return 1; 164 } 165 166 int32_t int64_mod_wrapper(int64_t* dst, int64_t* src) { 167 if (*src == 0) { 168 return 0; 169 } 170 *dst %= *src; 171 return 1; 172 } 173 174 int32_t uint64_div_wrapper(uint64_t* dst, uint64_t* src) { 175 if (*src == 0) { 176 return 0; 177 } 178 *dst /= *src; 179 return 1; 180 } 181 182 int32_t uint64_mod_wrapper(uint64_t* dst, uint64_t* src) { 183 if (*src == 0) { 184 return 0; 185 } 186 *dst %= *src; 187 return 1; 188 } 189 190 uint32_t word32_ctz_wrapper(uint32_t* input) { 191 return static_cast<uint32_t>(base::bits::CountTrailingZeros32(*input)); 192 } 193 194 uint32_t word64_ctz_wrapper(uint64_t* input) { 195 return static_cast<uint32_t>(base::bits::CountTrailingZeros64(*input)); 196 } 197 198 uint32_t word32_popcnt_wrapper(uint32_t* input) { 199 return static_cast<uint32_t>(base::bits::CountPopulation(*input)); 200 } 201 202 uint32_t word64_popcnt_wrapper(uint64_t* input) { 203 return static_cast<uint32_t>(base::bits::CountPopulation(*input)); 204 } 205 206 void float64_pow_wrapper(double* param0, double* param1) { 207 double x = ReadDoubleValue(param0); 208 double y = ReadDoubleValue(param1); 209 WriteDoubleValue(param0, Pow(x, y)); 210 } 211 212 static WasmTrapCallbackForTesting wasm_trap_callback_for_testing = nullptr; 213 214 void set_trap_callback_for_testing(WasmTrapCallbackForTesting callback) { 215 wasm_trap_callback_for_testing = callback; 216 } 217 218 void call_trap_callback_for_testing() { 219 if (wasm_trap_callback_for_testing) { 220 wasm_trap_callback_for_testing(); 221 } 222 } 223 224 } // namespace wasm 225 } // namespace internal 226 } // namespace v8 227