Line data Source code
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 14 : void f32_trunc_wrapper(float* param) { *param = truncf(*param); }
21 :
22 14 : void f32_floor_wrapper(float* param) { *param = floorf(*param); }
23 :
24 14 : void f32_ceil_wrapper(float* param) { *param = ceilf(*param); }
25 :
26 14 : void f32_nearest_int_wrapper(float* param) { *param = nearbyintf(*param); }
27 :
28 14 : void f64_trunc_wrapper(double* param) {
29 14 : WriteDoubleValue(param, trunc(ReadDoubleValue(param)));
30 14 : }
31 :
32 14 : void f64_floor_wrapper(double* param) {
33 14 : WriteDoubleValue(param, floor(ReadDoubleValue(param)));
34 14 : }
35 :
36 14 : void f64_ceil_wrapper(double* param) {
37 14 : WriteDoubleValue(param, ceil(ReadDoubleValue(param)));
38 14 : }
39 :
40 14 : void f64_nearest_int_wrapper(double* param) {
41 14 : WriteDoubleValue(param, nearbyint(ReadDoubleValue(param)));
42 14 : }
43 :
44 553 : void int64_to_float32_wrapper(int64_t* input, float* output) {
45 553 : *output = static_cast<float>(*input);
46 553 : }
47 :
48 546 : 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 546 : *output = static_cast<float>(*input);
79 : #endif
80 546 : }
81 :
82 23690 : void int64_to_float64_wrapper(int64_t* input, double* output) {
83 23690 : *output = static_cast<double>(*input);
84 23690 : }
85 :
86 539 : 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 539 : *output = static_cast<double>(*input);
104 : #endif
105 539 : }
106 :
107 1624 : 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 1624 : if (*input >= static_cast<float>(std::numeric_limits<int64_t>::min()) &&
112 : *input < static_cast<float>(std::numeric_limits<int64_t>::max())) {
113 1176 : *output = static_cast<int64_t>(*input);
114 1176 : return 1;
115 : }
116 : return 0;
117 : }
118 :
119 1624 : 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 1624 : if (*input > -1.0 &&
124 : *input < static_cast<float>(std::numeric_limits<uint64_t>::max())) {
125 728 : *output = static_cast<uint64_t>(*input);
126 728 : return 1;
127 : }
128 : return 0;
129 : }
130 :
131 1254 : 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 1254 : if (*input >= static_cast<double>(std::numeric_limits<int64_t>::min()) &&
136 : *input < static_cast<double>(std::numeric_limits<int64_t>::max())) {
137 1100 : *output = static_cast<int64_t>(*input);
138 1100 : return 1;
139 : }
140 : return 0;
141 : }
142 :
143 700 : 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 700 : if (*input > -1.0 &&
148 : *input < static_cast<double>(std::numeric_limits<uint64_t>::max())) {
149 420 : *output = static_cast<uint64_t>(*input);
150 420 : return 1;
151 : }
152 : return 0;
153 : }
154 :
155 14 : int32_t int64_div_wrapper(int64_t* dst, int64_t* src) {
156 14 : if (*src == 0) {
157 : return 0;
158 : }
159 14 : if (*src == -1 && *dst == std::numeric_limits<int64_t>::min()) {
160 : return -1;
161 : }
162 14 : *dst /= *src;
163 14 : return 1;
164 : }
165 :
166 14 : int32_t int64_mod_wrapper(int64_t* dst, int64_t* src) {
167 14 : if (*src == 0) {
168 : return 0;
169 : }
170 14 : *dst %= *src;
171 14 : return 1;
172 : }
173 :
174 14 : int32_t uint64_div_wrapper(uint64_t* dst, uint64_t* src) {
175 14 : if (*src == 0) {
176 : return 0;
177 : }
178 14 : *dst /= *src;
179 14 : return 1;
180 : }
181 :
182 14 : int32_t uint64_mod_wrapper(uint64_t* dst, uint64_t* src) {
183 14 : if (*src == 0) {
184 : return 0;
185 : }
186 14 : *dst %= *src;
187 14 : return 1;
188 : }
189 :
190 14 : uint32_t word32_ctz_wrapper(uint32_t* input) {
191 28 : return static_cast<uint32_t>(base::bits::CountTrailingZeros32(*input));
192 : }
193 :
194 14 : uint32_t word64_ctz_wrapper(uint64_t* input) {
195 28 : return static_cast<uint32_t>(base::bits::CountTrailingZeros64(*input));
196 : }
197 :
198 84 : uint32_t word32_popcnt_wrapper(uint32_t* input) {
199 168 : return static_cast<uint32_t>(base::bits::CountPopulation(*input));
200 : }
201 :
202 84 : uint32_t word64_popcnt_wrapper(uint64_t* input) {
203 168 : return static_cast<uint32_t>(base::bits::CountPopulation(*input));
204 : }
205 :
206 74 : void float64_pow_wrapper(double* param0, double* param1) {
207 : double x = ReadDoubleValue(param0);
208 : double y = ReadDoubleValue(param1);
209 74 : WriteDoubleValue(param0, Pow(x, y));
210 74 : }
211 :
212 : static WasmTrapCallbackForTesting wasm_trap_callback_for_testing = nullptr;
213 :
214 2936972 : void set_trap_callback_for_testing(WasmTrapCallbackForTesting callback) {
215 2936972 : wasm_trap_callback_for_testing = callback;
216 2936972 : }
217 :
218 12572 : void call_trap_callback_for_testing() {
219 12572 : if (wasm_trap_callback_for_testing) {
220 12572 : wasm_trap_callback_for_testing();
221 : }
222 12572 : }
223 :
224 : } // namespace wasm
225 : } // namespace internal
226 : } // namespace v8
|