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
f32_trunc_wrapper(float * param)20 void f32_trunc_wrapper(float* param) { *param = truncf(*param); }
21
f32_floor_wrapper(float * param)22 void f32_floor_wrapper(float* param) { *param = floorf(*param); }
23
f32_ceil_wrapper(float * param)24 void f32_ceil_wrapper(float* param) { *param = ceilf(*param); }
25
f32_nearest_int_wrapper(float * param)26 void f32_nearest_int_wrapper(float* param) { *param = nearbyintf(*param); }
27
f64_trunc_wrapper(double * param)28 void f64_trunc_wrapper(double* param) {
29 WriteDoubleValue(param, trunc(ReadDoubleValue(param)));
30 }
31
f64_floor_wrapper(double * param)32 void f64_floor_wrapper(double* param) {
33 WriteDoubleValue(param, floor(ReadDoubleValue(param)));
34 }
35
f64_ceil_wrapper(double * param)36 void f64_ceil_wrapper(double* param) {
37 WriteDoubleValue(param, ceil(ReadDoubleValue(param)));
38 }
39
f64_nearest_int_wrapper(double * param)40 void f64_nearest_int_wrapper(double* param) {
41 WriteDoubleValue(param, nearbyint(ReadDoubleValue(param)));
42 }
43
int64_to_float32_wrapper(int64_t * input,float * output)44 void int64_to_float32_wrapper(int64_t* input, float* output) {
45 *output = static_cast<float>(*input);
46 }
47
uint64_to_float32_wrapper(uint64_t * input,float * output)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
int64_to_float64_wrapper(int64_t * input,double * output)82 void int64_to_float64_wrapper(int64_t* input, double* output) {
83 *output = static_cast<double>(*input);
84 }
85
uint64_to_float64_wrapper(uint64_t * input,double * output)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
float32_to_int64_wrapper(float * input,int64_t * output)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
float32_to_uint64_wrapper(float * input,uint64_t * output)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
float64_to_int64_wrapper(double * input,int64_t * output)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
float64_to_uint64_wrapper(double * input,uint64_t * output)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
int64_div_wrapper(int64_t * dst,int64_t * src)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
int64_mod_wrapper(int64_t * dst,int64_t * src)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
uint64_div_wrapper(uint64_t * dst,uint64_t * src)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
uint64_mod_wrapper(uint64_t * dst,uint64_t * src)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
word32_ctz_wrapper(uint32_t * input)190 uint32_t word32_ctz_wrapper(uint32_t* input) {
191 return static_cast<uint32_t>(base::bits::CountTrailingZeros32(*input));
192 }
193
word64_ctz_wrapper(uint64_t * input)194 uint32_t word64_ctz_wrapper(uint64_t* input) {
195 return static_cast<uint32_t>(base::bits::CountTrailingZeros64(*input));
196 }
197
word32_popcnt_wrapper(uint32_t * input)198 uint32_t word32_popcnt_wrapper(uint32_t* input) {
199 return static_cast<uint32_t>(base::bits::CountPopulation(*input));
200 }
201
word64_popcnt_wrapper(uint64_t * input)202 uint32_t word64_popcnt_wrapper(uint64_t* input) {
203 return static_cast<uint32_t>(base::bits::CountPopulation(*input));
204 }
205
float64_pow_wrapper(double * param0,double * param1)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
set_trap_callback_for_testing(WasmTrapCallbackForTesting callback)214 void set_trap_callback_for_testing(WasmTrapCallbackForTesting callback) {
215 wasm_trap_callback_for_testing = callback;
216 }
217
call_trap_callback_for_testing()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