Line data Source code
1 : // Copyright 2014 the V8 project authors. All rights reserved. Use of this
2 : // source code is governed by a BSD-style license that can be found in the
3 : // LICENSE file.
4 :
5 : #include "src/objects-inl.h"
6 : #include "src/wasm/wasm-external-refs.h"
7 : #include "test/cctest/cctest.h"
8 : #include "test/cctest/compiler/codegen-tester.h"
9 : #include "test/cctest/compiler/value-helper.h"
10 :
11 : namespace v8 {
12 : namespace internal {
13 : namespace compiler {
14 :
15 : template <typename InType, typename OutType, typename Iterable>
16 16 : void TestExternalReference_ConvertOp(
17 : BufferedRawMachineAssemblerTester<int32_t>* m, ExternalReference ref,
18 : void (*wrapper)(Address), Iterable inputs) {
19 : constexpr size_t kBufferSize = Max(sizeof(InType), sizeof(OutType));
20 16 : uint8_t buffer[kBufferSize] = {0};
21 16 : Address buffer_addr = reinterpret_cast<Address>(buffer);
22 :
23 16 : Node* function = m->ExternalConstant(ref);
24 : m->CallCFunction(
25 : function, MachineType::Pointer(),
26 : std::make_pair(MachineType::Pointer(), m->PointerConstant(buffer)));
27 16 : m->Return(m->Int32Constant(4356));
28 :
29 2608 : for (InType input : inputs) {
30 : WriteUnalignedValue<InType>(buffer_addr, input);
31 :
32 1296 : CHECK_EQ(4356, m->Call());
33 : OutType output = ReadUnalignedValue<OutType>(buffer_addr);
34 :
35 : WriteUnalignedValue<InType>(buffer_addr, input);
36 1296 : wrapper(buffer_addr);
37 : OutType expected_output = ReadUnalignedValue<OutType>(buffer_addr);
38 :
39 1296 : CHECK_EQ(expected_output, output);
40 : }
41 16 : }
42 :
43 : template <typename InType, typename OutType, typename Iterable>
44 16 : void TestExternalReference_ConvertOpWithOutputAndReturn(
45 : BufferedRawMachineAssemblerTester<int32_t>* m, ExternalReference ref,
46 : int32_t (*wrapper)(Address), Iterable inputs) {
47 : constexpr size_t kBufferSize = Max(sizeof(InType), sizeof(OutType));
48 16 : uint8_t buffer[kBufferSize] = {0};
49 16 : Address buffer_addr = reinterpret_cast<Address>(buffer);
50 :
51 16 : Node* function = m->ExternalConstant(ref);
52 16 : m->Return(m->CallCFunction(
53 : function, MachineType::Int32(),
54 : std::make_pair(MachineType::Pointer(), m->PointerConstant(buffer))));
55 :
56 2640 : for (InType input : inputs) {
57 : WriteUnalignedValue<InType>(buffer_addr, input);
58 :
59 : int32_t ret = m->Call();
60 : OutType output = ReadUnalignedValue<OutType>(buffer_addr);
61 :
62 : WriteUnalignedValue<InType>(buffer_addr, input);
63 1312 : int32_t expected_ret = wrapper(buffer_addr);
64 : OutType expected_output = ReadUnalignedValue<OutType>(buffer_addr);
65 :
66 1312 : CHECK_EQ(expected_ret, ret);
67 1312 : CHECK_EQ(expected_output, output);
68 : }
69 16 : }
70 :
71 : template <typename InType, typename OutType, typename Iterable>
72 16 : void TestExternalReference_ConvertOpWithReturn(
73 : BufferedRawMachineAssemblerTester<OutType>* m, ExternalReference ref,
74 : OutType (*wrapper)(Address), Iterable inputs) {
75 : constexpr size_t kBufferSize = sizeof(InType);
76 16 : uint8_t buffer[kBufferSize] = {0};
77 16 : Address buffer_addr = reinterpret_cast<Address>(buffer);
78 :
79 16 : Node* function = m->ExternalConstant(ref);
80 16 : m->Return(m->CallCFunction(
81 : function, MachineType::Int32(),
82 : std::make_pair(MachineType::Pointer(), m->PointerConstant(buffer))));
83 :
84 2240 : for (InType input : inputs) {
85 : WriteUnalignedValue<InType>(buffer_addr, input);
86 :
87 : OutType ret = m->Call();
88 :
89 : WriteUnalignedValue<InType>(buffer_addr, input);
90 1112 : OutType expected_ret = wrapper(buffer_addr);
91 :
92 1112 : CHECK_EQ(expected_ret, ret);
93 : }
94 16 : }
95 :
96 : template <typename Type>
97 : bool isnan(Type value) {
98 : return false;
99 : }
100 : template <>
101 0 : bool isnan<float>(float value) {
102 0 : return std::isnan(value);
103 : }
104 : template <>
105 0 : bool isnan<double>(double value) {
106 0 : return std::isnan(value);
107 : }
108 :
109 : template <typename Type, typename Iterable>
110 32 : void TestExternalReference_UnOp(BufferedRawMachineAssemblerTester<int32_t>* m,
111 : ExternalReference ref, void (*wrapper)(Address),
112 : Iterable inputs) {
113 : constexpr size_t kBufferSize = sizeof(Type);
114 32 : uint8_t buffer[kBufferSize] = {0};
115 32 : Address buffer_addr = reinterpret_cast<Address>(buffer);
116 :
117 32 : Node* function = m->ExternalConstant(ref);
118 : m->CallCFunction(
119 : function, MachineType::Int32(),
120 : std::make_pair(MachineType::Pointer(), m->PointerConstant(buffer)));
121 32 : m->Return(m->Int32Constant(4356));
122 :
123 5280 : for (Type input : inputs) {
124 : WriteUnalignedValue<Type>(buffer_addr, input);
125 2624 : CHECK_EQ(4356, m->Call());
126 : Type output = ReadUnalignedValue<Type>(buffer_addr);
127 :
128 : WriteUnalignedValue<Type>(buffer_addr, input);
129 2624 : wrapper(buffer_addr);
130 : Type expected_output = ReadUnalignedValue<Type>(buffer_addr);
131 :
132 2624 : if (isnan(expected_output) && isnan(output)) continue;
133 2560 : CHECK_EQ(expected_output, output);
134 : }
135 32 : }
136 :
137 : template <typename Type, typename Iterable>
138 4 : void TestExternalReference_BinOp(BufferedRawMachineAssemblerTester<int32_t>* m,
139 : ExternalReference ref,
140 : void (*wrapper)(Address), Iterable inputs) {
141 : constexpr size_t kBufferSize = 2 * sizeof(Type);
142 4 : uint8_t buffer[kBufferSize] = {0};
143 4 : Address buffer_addr = reinterpret_cast<Address>(buffer);
144 :
145 4 : Node* function = m->ExternalConstant(ref);
146 : m->CallCFunction(
147 : function, MachineType::Int32(),
148 : std::make_pair(MachineType::Pointer(), m->PointerConstant(buffer)));
149 4 : m->Return(m->Int32Constant(4356));
150 :
151 396 : for (Type input1 : inputs) {
152 19404 : for (Type input2 : inputs) {
153 : WriteUnalignedValue<Type>(buffer_addr, input1);
154 9604 : WriteUnalignedValue<Type>(buffer_addr + sizeof(Type), input2);
155 9604 : CHECK_EQ(4356, m->Call());
156 : Type output = ReadUnalignedValue<Type>(buffer_addr);
157 :
158 : WriteUnalignedValue<Type>(buffer_addr, input1);
159 : WriteUnalignedValue<Type>(buffer_addr + sizeof(Type), input2);
160 9604 : wrapper(buffer_addr);
161 : Type expected_output = ReadUnalignedValue<Type>(buffer_addr);
162 :
163 9604 : if (isnan(expected_output) && isnan(output)) continue;
164 7172 : CHECK_EQ(expected_output, output);
165 : }
166 : }
167 4 : }
168 :
169 : template <typename Type, typename Iterable>
170 16 : void TestExternalReference_BinOpWithReturn(
171 : BufferedRawMachineAssemblerTester<int32_t>* m, ExternalReference ref,
172 : int32_t (*wrapper)(Address), Iterable inputs) {
173 : constexpr size_t kBufferSize = 2 * sizeof(Type);
174 16 : uint8_t buffer[kBufferSize] = {0};
175 16 : Address buffer_addr = reinterpret_cast<Address>(buffer);
176 :
177 16 : Node* function = m->ExternalConstant(ref);
178 16 : m->Return(m->CallCFunction(
179 : function, MachineType::Int32(),
180 : std::make_pair(MachineType::Pointer(), m->PointerConstant(buffer))));
181 :
182 2608 : for (Type input1 : inputs) {
183 211248 : for (Type input2 : inputs) {
184 : WriteUnalignedValue<Type>(buffer_addr, input1);
185 104976 : WriteUnalignedValue<Type>(buffer_addr + sizeof(Type), input2);
186 : int32_t ret = m->Call();
187 : Type output = ReadUnalignedValue<Type>(buffer_addr);
188 :
189 : WriteUnalignedValue<Type>(buffer_addr, input1);
190 : WriteUnalignedValue<Type>(buffer_addr + sizeof(Type), input2);
191 104976 : int32_t expected_ret = wrapper(buffer_addr);
192 : Type expected_output = ReadUnalignedValue<Type>(buffer_addr);
193 :
194 104976 : CHECK_EQ(expected_ret, ret);
195 : if (isnan(expected_output) && isnan(output)) continue;
196 104976 : CHECK_EQ(expected_output, output);
197 : }
198 : }
199 16 : }
200 :
201 26660 : TEST(RunCallF32Trunc) {
202 4 : BufferedRawMachineAssemblerTester<int32_t> m;
203 4 : ExternalReference ref = ExternalReference::wasm_f32_trunc();
204 : TestExternalReference_UnOp<float>(&m, ref, wasm::f32_trunc_wrapper,
205 4 : ValueHelper::float32_vector());
206 4 : }
207 :
208 26660 : TEST(RunCallF32Floor) {
209 4 : BufferedRawMachineAssemblerTester<int32_t> m;
210 4 : ExternalReference ref = ExternalReference::wasm_f32_floor();
211 : TestExternalReference_UnOp<float>(&m, ref, wasm::f32_floor_wrapper,
212 4 : ValueHelper::float32_vector());
213 4 : }
214 :
215 26660 : TEST(RunCallF32Ceil) {
216 4 : BufferedRawMachineAssemblerTester<int32_t> m;
217 4 : ExternalReference ref = ExternalReference::wasm_f32_ceil();
218 : TestExternalReference_UnOp<float>(&m, ref, wasm::f32_ceil_wrapper,
219 4 : ValueHelper::float32_vector());
220 4 : }
221 :
222 26660 : TEST(RunCallF32RoundTiesEven) {
223 4 : BufferedRawMachineAssemblerTester<int32_t> m;
224 4 : ExternalReference ref = ExternalReference::wasm_f32_nearest_int();
225 : TestExternalReference_UnOp<float>(&m, ref, wasm::f32_nearest_int_wrapper,
226 4 : ValueHelper::float32_vector());
227 4 : }
228 :
229 26660 : TEST(RunCallF64Trunc) {
230 4 : BufferedRawMachineAssemblerTester<int32_t> m;
231 4 : ExternalReference ref = ExternalReference::wasm_f64_trunc();
232 : TestExternalReference_UnOp<double>(&m, ref, wasm::f64_trunc_wrapper,
233 4 : ValueHelper::float64_vector());
234 4 : }
235 :
236 26660 : TEST(RunCallF64Floor) {
237 4 : BufferedRawMachineAssemblerTester<int32_t> m;
238 4 : ExternalReference ref = ExternalReference::wasm_f64_floor();
239 : TestExternalReference_UnOp<double>(&m, ref, wasm::f64_floor_wrapper,
240 4 : ValueHelper::float64_vector());
241 4 : }
242 :
243 26660 : TEST(RunCallF64Ceil) {
244 4 : BufferedRawMachineAssemblerTester<int32_t> m;
245 4 : ExternalReference ref = ExternalReference::wasm_f64_ceil();
246 : TestExternalReference_UnOp<double>(&m, ref, wasm::f64_ceil_wrapper,
247 4 : ValueHelper::float64_vector());
248 4 : }
249 :
250 26660 : TEST(RunCallF64RoundTiesEven) {
251 4 : BufferedRawMachineAssemblerTester<int32_t> m;
252 4 : ExternalReference ref = ExternalReference::wasm_f64_nearest_int();
253 : TestExternalReference_UnOp<double>(&m, ref, wasm::f64_nearest_int_wrapper,
254 4 : ValueHelper::float64_vector());
255 4 : }
256 :
257 26660 : TEST(RunCallInt64ToFloat32) {
258 4 : BufferedRawMachineAssemblerTester<int32_t> m;
259 4 : ExternalReference ref = ExternalReference::wasm_int64_to_float32();
260 : TestExternalReference_ConvertOp<int64_t, float>(
261 4 : &m, ref, wasm::int64_to_float32_wrapper, ValueHelper::int64_vector());
262 4 : }
263 :
264 26660 : TEST(RunCallUint64ToFloat32) {
265 4 : BufferedRawMachineAssemblerTester<int32_t> m;
266 4 : ExternalReference ref = ExternalReference::wasm_uint64_to_float32();
267 : TestExternalReference_ConvertOp<uint64_t, float>(
268 4 : &m, ref, wasm::uint64_to_float32_wrapper, ValueHelper::uint64_vector());
269 4 : }
270 :
271 26660 : TEST(RunCallInt64ToFloat64) {
272 4 : BufferedRawMachineAssemblerTester<int32_t> m;
273 4 : ExternalReference ref = ExternalReference::wasm_int64_to_float64();
274 : TestExternalReference_ConvertOp<int64_t, double>(
275 4 : &m, ref, wasm::int64_to_float64_wrapper, ValueHelper::int64_vector());
276 4 : }
277 :
278 26660 : TEST(RunCallUint64ToFloat64) {
279 4 : BufferedRawMachineAssemblerTester<int32_t> m;
280 4 : ExternalReference ref = ExternalReference::wasm_uint64_to_float64();
281 : TestExternalReference_ConvertOp<uint64_t, double>(
282 4 : &m, ref, wasm::uint64_to_float64_wrapper, ValueHelper::uint64_vector());
283 4 : }
284 :
285 26660 : TEST(RunCallFloat32ToInt64) {
286 4 : BufferedRawMachineAssemblerTester<int32_t> m;
287 4 : ExternalReference ref = ExternalReference::wasm_float32_to_int64();
288 : TestExternalReference_ConvertOpWithOutputAndReturn<float, int64_t>(
289 4 : &m, ref, wasm::float32_to_int64_wrapper, ValueHelper::float32_vector());
290 4 : }
291 :
292 26660 : TEST(RunCallFloat32ToUint64) {
293 4 : BufferedRawMachineAssemblerTester<int32_t> m;
294 4 : ExternalReference ref = ExternalReference::wasm_float32_to_uint64();
295 : TestExternalReference_ConvertOpWithOutputAndReturn<float, uint64_t>(
296 4 : &m, ref, wasm::float32_to_uint64_wrapper, ValueHelper::float32_vector());
297 4 : }
298 :
299 26660 : TEST(RunCallFloat64ToInt64) {
300 4 : BufferedRawMachineAssemblerTester<int32_t> m;
301 4 : ExternalReference ref = ExternalReference::wasm_float64_to_int64();
302 : TestExternalReference_ConvertOpWithOutputAndReturn<double, int64_t>(
303 4 : &m, ref, wasm::float64_to_int64_wrapper, ValueHelper::float64_vector());
304 4 : }
305 :
306 26660 : TEST(RunCallFloat64ToUint64) {
307 4 : BufferedRawMachineAssemblerTester<int32_t> m;
308 4 : ExternalReference ref = ExternalReference::wasm_float64_to_uint64();
309 : TestExternalReference_ConvertOpWithOutputAndReturn<double, uint64_t>(
310 4 : &m, ref, wasm::float64_to_uint64_wrapper, ValueHelper::float64_vector());
311 4 : }
312 :
313 26660 : TEST(RunCallInt64Div) {
314 4 : BufferedRawMachineAssemblerTester<int32_t> m;
315 4 : ExternalReference ref = ExternalReference::wasm_int64_div();
316 : TestExternalReference_BinOpWithReturn<int64_t>(
317 4 : &m, ref, wasm::int64_div_wrapper, ValueHelper::int64_vector());
318 4 : }
319 :
320 26660 : TEST(RunCallInt64Mod) {
321 4 : BufferedRawMachineAssemblerTester<int32_t> m;
322 4 : ExternalReference ref = ExternalReference::wasm_int64_mod();
323 : TestExternalReference_BinOpWithReturn<int64_t>(
324 4 : &m, ref, wasm::int64_mod_wrapper, ValueHelper::int64_vector());
325 4 : }
326 :
327 26660 : TEST(RunCallUint64Div) {
328 4 : BufferedRawMachineAssemblerTester<int32_t> m;
329 4 : ExternalReference ref = ExternalReference::wasm_uint64_div();
330 : TestExternalReference_BinOpWithReturn<uint64_t>(
331 4 : &m, ref, wasm::uint64_div_wrapper, ValueHelper::uint64_vector());
332 4 : }
333 :
334 26660 : TEST(RunCallUint64Mod) {
335 4 : BufferedRawMachineAssemblerTester<int32_t> m;
336 4 : ExternalReference ref = ExternalReference::wasm_uint64_mod();
337 : TestExternalReference_BinOpWithReturn<uint64_t>(
338 4 : &m, ref, wasm::uint64_mod_wrapper, ValueHelper::uint64_vector());
339 4 : }
340 :
341 26660 : TEST(RunCallWord32Ctz) {
342 4 : BufferedRawMachineAssemblerTester<uint32_t> m;
343 4 : ExternalReference ref = ExternalReference::wasm_word32_ctz();
344 : TestExternalReference_ConvertOpWithReturn<int32_t, uint32_t>(
345 4 : &m, ref, wasm::word32_ctz_wrapper, ValueHelper::int32_vector());
346 4 : }
347 :
348 26660 : TEST(RunCallWord64Ctz) {
349 4 : BufferedRawMachineAssemblerTester<uint32_t> m;
350 4 : ExternalReference ref = ExternalReference::wasm_word64_ctz();
351 : TestExternalReference_ConvertOpWithReturn<int64_t, uint32_t>(
352 4 : &m, ref, wasm::word64_ctz_wrapper, ValueHelper::int64_vector());
353 4 : }
354 :
355 26660 : TEST(RunCallWord32Popcnt) {
356 4 : BufferedRawMachineAssemblerTester<uint32_t> m;
357 4 : ExternalReference ref = ExternalReference::wasm_word32_popcnt();
358 : TestExternalReference_ConvertOpWithReturn<uint32_t, uint32_t>(
359 4 : &m, ref, wasm::word32_popcnt_wrapper, ValueHelper::int32_vector());
360 4 : }
361 :
362 26660 : TEST(RunCallWord64Popcnt) {
363 4 : BufferedRawMachineAssemblerTester<uint32_t> m;
364 4 : ExternalReference ref = ExternalReference::wasm_word64_popcnt();
365 : TestExternalReference_ConvertOpWithReturn<int64_t, uint32_t>(
366 4 : &m, ref, wasm::word64_popcnt_wrapper, ValueHelper::int64_vector());
367 4 : }
368 :
369 26660 : TEST(RunCallFloat64Pow) {
370 4 : BufferedRawMachineAssemblerTester<int32_t> m;
371 4 : ExternalReference ref = ExternalReference::wasm_float64_pow();
372 : TestExternalReference_BinOp<double>(&m, ref, wasm::float64_pow_wrapper,
373 4 : ValueHelper::float64_vector());
374 4 : }
375 :
376 : } // namespace compiler
377 : } // namespace internal
378 79968 : } // namespace v8
|