Line data Source code
1 : // Copyright 2009 the V8 project authors. All rights reserved.
2 : // Redistribution and use in source and binary forms, with or without
3 : // modification, are permitted provided that the following conditions are
4 : // met:
5 : //
6 : // * Redistributions of source code must retain the above copyright
7 : // notice, this list of conditions and the following disclaimer.
8 : // * Redistributions in binary form must reproduce the above
9 : // copyright notice, this list of conditions and the following
10 : // disclaimer in the documentation and/or other materials provided
11 : // with the distribution.
12 : // * Neither the name of Google Inc. nor the names of its
13 : // contributors may be used to endorse or promote products derived
14 : // from this software without specific prior written permission.
15 : //
16 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 : // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 : // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 : // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 : // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 : // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 : // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 : // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 : // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 : // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 :
28 : #include <cstdlib>
29 : #include <iostream>
30 :
31 : #include "src/v8.h"
32 :
33 : #include "src/base/platform/platform.h"
34 : #include "src/base/utils/random-number-generator.h"
35 : #include "src/double.h"
36 : #include "src/heap/factory.h"
37 : #include "src/macro-assembler.h"
38 : #include "src/objects-inl.h"
39 : #include "src/ostreams.h"
40 : #include "src/simulator.h"
41 : #include "test/cctest/cctest.h"
42 : #include "test/common/assembler-tester.h"
43 :
44 : namespace v8 {
45 : namespace internal {
46 :
47 : // Test the x64 assembler by compiling some simple functions into
48 : // a buffer and executing them. These tests do not initialize the
49 : // V8 library, create a context, or use any V8 objects.
50 : // The AMD64 calling convention is used, with the first six arguments
51 : // in RDI, RSI, RDX, RCX, R8, and R9, and floating point arguments in
52 : // the XMM registers. The return value is in RAX.
53 : // This calling convention is used on Linux, with GCC, and on Mac OS,
54 : // with GCC. A different convention is used on 64-bit windows,
55 : // where the first four integer arguments are passed in RCX, RDX, R8 and R9.
56 :
57 : typedef int(F0)();
58 : typedef int(F1)(int64_t x);
59 : typedef int(F2)(int64_t x, int64_t y);
60 : typedef unsigned(F3)(double x);
61 : typedef uint64_t(F4)(uint64_t* x, uint64_t* y);
62 : typedef uint64_t(F5)(uint64_t x);
63 :
64 : #ifdef _WIN64
65 : static const Register arg1 = rcx;
66 : static const Register arg2 = rdx;
67 : #else
68 : static const Register arg1 = rdi;
69 : static const Register arg2 = rsi;
70 : #endif
71 :
72 : #define __ masm.
73 :
74 28342 : TEST(AssemblerX64ReturnOperation) {
75 5 : CcTest::InitializeVM();
76 : auto buffer = AllocateAssemblerBuffer();
77 25 : Assembler masm(AssemblerOptions{}, buffer->CreateView());
78 :
79 : // Assemble a simple function that copies argument 2 and returns it.
80 : __ movq(rax, arg2);
81 5 : __ nop();
82 5 : __ ret(0);
83 :
84 5 : CodeDesc desc;
85 5 : masm.GetCode(CcTest::i_isolate(), &desc);
86 5 : buffer->MakeExecutable();
87 : // Call the function from C++.
88 5 : auto f = GeneratedCode<F2>::FromBuffer(CcTest::i_isolate(), buffer->start());
89 : int result = f.Call(3, 2);
90 5 : CHECK_EQ(2, result);
91 5 : }
92 :
93 :
94 28342 : TEST(AssemblerX64StackOperations) {
95 5 : CcTest::InitializeVM();
96 : auto buffer = AllocateAssemblerBuffer();
97 25 : Assembler masm(AssemblerOptions{}, buffer->CreateView());
98 :
99 : // Assemble a simple function that copies argument 2 and returns it.
100 : // We compile without stack frame pointers, so the gdb debugger shows
101 : // incorrect stack frames when debugging this function (which has them).
102 5 : __ pushq(rbp);
103 : __ movq(rbp, rsp);
104 5 : __ pushq(arg2); // Value at (rbp - 8)
105 5 : __ pushq(arg2); // Value at (rbp - 16)
106 5 : __ pushq(arg1); // Value at (rbp - 24)
107 5 : __ popq(rax);
108 5 : __ popq(rax);
109 5 : __ popq(rax);
110 5 : __ popq(rbp);
111 5 : __ nop();
112 5 : __ ret(0);
113 :
114 5 : CodeDesc desc;
115 5 : masm.GetCode(CcTest::i_isolate(), &desc);
116 5 : buffer->MakeExecutable();
117 : // Call the function from C++.
118 5 : auto f = GeneratedCode<F2>::FromBuffer(CcTest::i_isolate(), buffer->start());
119 : int result = f.Call(3, 2);
120 5 : CHECK_EQ(2, result);
121 5 : }
122 :
123 :
124 28342 : TEST(AssemblerX64ArithmeticOperations) {
125 5 : CcTest::InitializeVM();
126 : auto buffer = AllocateAssemblerBuffer();
127 25 : Assembler masm(AssemblerOptions{}, buffer->CreateView());
128 :
129 : // Assemble a simple function that adds arguments returning the sum.
130 : __ movq(rax, arg2);
131 5 : __ addq(rax, arg1);
132 5 : __ ret(0);
133 :
134 5 : CodeDesc desc;
135 5 : masm.GetCode(CcTest::i_isolate(), &desc);
136 5 : buffer->MakeExecutable();
137 : // Call the function from C++.
138 5 : auto f = GeneratedCode<F2>::FromBuffer(CcTest::i_isolate(), buffer->start());
139 : int result = f.Call(3, 2);
140 5 : CHECK_EQ(5, result);
141 5 : }
142 :
143 :
144 28342 : TEST(AssemblerX64CmpbOperation) {
145 5 : CcTest::InitializeVM();
146 : auto buffer = AllocateAssemblerBuffer();
147 25 : Assembler masm(AssemblerOptions{}, buffer->CreateView());
148 :
149 : // Assemble a function that compare argument byte returing 1 if equal else 0.
150 : // On Windows, it compares rcx with rdx which does not require REX prefix;
151 : // on Linux, it compares rdi with rsi which requires REX prefix.
152 :
153 5 : Label done;
154 : __ movq(rax, Immediate(1));
155 : __ cmpb(arg1, arg2);
156 5 : __ j(equal, &done);
157 : __ movq(rax, Immediate(0));
158 5 : __ bind(&done);
159 5 : __ ret(0);
160 :
161 5 : CodeDesc desc;
162 5 : masm.GetCode(CcTest::i_isolate(), &desc);
163 5 : buffer->MakeExecutable();
164 : // Call the function from C++.
165 5 : auto f = GeneratedCode<F2>::FromBuffer(CcTest::i_isolate(), buffer->start());
166 : int result = f.Call(0x1002, 0x2002);
167 5 : CHECK_EQ(1, result);
168 : result = f.Call(0x1002, 0x2003);
169 5 : CHECK_EQ(0, result);
170 5 : }
171 :
172 28342 : TEST(AssemblerX64ImulOperation) {
173 5 : CcTest::InitializeVM();
174 : auto buffer = AllocateAssemblerBuffer();
175 25 : Assembler masm(AssemblerOptions{}, buffer->CreateView());
176 :
177 : // Assemble a simple function that multiplies arguments returning the high
178 : // word.
179 : __ movq(rax, arg2);
180 : __ imulq(arg1);
181 : __ movq(rax, rdx);
182 5 : __ ret(0);
183 :
184 5 : CodeDesc desc;
185 5 : masm.GetCode(CcTest::i_isolate(), &desc);
186 5 : buffer->MakeExecutable();
187 : // Call the function from C++.
188 5 : auto f = GeneratedCode<F2>::FromBuffer(CcTest::i_isolate(), buffer->start());
189 : int result = f.Call(3, 2);
190 5 : CHECK_EQ(0, result);
191 : result = f.Call(0x100000000l, 0x100000000l);
192 5 : CHECK_EQ(1, result);
193 : result = f.Call(-0x100000000l, 0x100000000l);
194 5 : CHECK_EQ(-1, result);
195 5 : }
196 :
197 28342 : TEST(AssemblerX64testbwqOperation) {
198 5 : CcTest::InitializeVM();
199 5 : v8::HandleScope scope(CcTest::isolate());
200 : auto buffer = AllocateAssemblerBuffer();
201 25 : Assembler masm(AssemblerOptions{}, buffer->CreateView());
202 :
203 5 : __ pushq(rbx);
204 5 : __ pushq(rdi);
205 5 : __ pushq(rsi);
206 5 : __ pushq(r12);
207 5 : __ pushq(r13);
208 5 : __ pushq(r14);
209 5 : __ pushq(r15);
210 :
211 : // Assemble a simple function that tests testb and testw
212 5 : Label bad;
213 5 : Label done;
214 :
215 : // Test immediate testb and testw
216 : __ movq(rax, Immediate(2));
217 : __ movq(rbx, Immediate(4));
218 : __ movq(rcx, Immediate(8));
219 : __ movq(rdx, Immediate(16));
220 : __ movq(rsi, Immediate(32));
221 : __ movq(rdi, Immediate(64));
222 : __ movq(r10, Immediate(128));
223 : __ movq(r11, Immediate(0));
224 : __ movq(r12, Immediate(0));
225 : __ movq(r13, Immediate(0));
226 5 : __ testb(rax, Immediate(2));
227 5 : __ j(zero, &bad);
228 5 : __ testb(rbx, Immediate(4));
229 5 : __ j(zero, &bad);
230 5 : __ testb(rcx, Immediate(8));
231 5 : __ j(zero, &bad);
232 5 : __ testb(rdx, Immediate(16));
233 5 : __ j(zero, &bad);
234 5 : __ testb(rsi, Immediate(32));
235 5 : __ j(zero, &bad);
236 5 : __ testb(rdi, Immediate(64));
237 5 : __ j(zero, &bad);
238 5 : __ testb(r10, Immediate(128));
239 5 : __ j(zero, &bad);
240 5 : __ testw(rax, Immediate(2));
241 5 : __ j(zero, &bad);
242 5 : __ testw(rbx, Immediate(4));
243 5 : __ j(zero, &bad);
244 5 : __ testw(rcx, Immediate(8));
245 5 : __ j(zero, &bad);
246 5 : __ testw(rdx, Immediate(16));
247 5 : __ j(zero, &bad);
248 5 : __ testw(rsi, Immediate(32));
249 5 : __ j(zero, &bad);
250 5 : __ testw(rdi, Immediate(64));
251 5 : __ j(zero, &bad);
252 5 : __ testw(r10, Immediate(128));
253 5 : __ j(zero, &bad);
254 :
255 : // Test reg, reg testb and testw
256 : __ movq(rax, Immediate(2));
257 : __ movq(rbx, Immediate(2));
258 5 : __ testb(rax, rbx);
259 5 : __ j(zero, &bad);
260 : __ movq(rbx, Immediate(4));
261 : __ movq(rax, Immediate(4));
262 5 : __ testb(rbx, rax);
263 5 : __ j(zero, &bad);
264 : __ movq(rax, Immediate(8));
265 5 : __ testb(rcx, rax);
266 5 : __ j(zero, &bad);
267 : __ movq(rax, Immediate(16));
268 5 : __ testb(rdx, rax);
269 5 : __ j(zero, &bad);
270 : __ movq(rax, Immediate(32));
271 5 : __ testb(rsi, rax);
272 5 : __ j(zero, &bad);
273 : __ movq(rax, Immediate(64));
274 5 : __ testb(rdi, rax);
275 5 : __ j(zero, &bad);
276 : __ movq(rax, Immediate(128));
277 5 : __ testb(r10, rax);
278 5 : __ j(zero, &bad);
279 : __ movq(rax, Immediate(2));
280 : __ movq(rbx, Immediate(2));
281 5 : __ testw(rax, rbx);
282 5 : __ j(zero, &bad);
283 : __ movq(rbx, Immediate(4));
284 : __ movq(rax, Immediate(4));
285 5 : __ testw(rbx, rax);
286 5 : __ j(zero, &bad);
287 : __ movq(rax, Immediate(8));
288 5 : __ testw(rcx, rax);
289 5 : __ j(zero, &bad);
290 : __ movq(rax, Immediate(16));
291 5 : __ testw(rdx, rax);
292 5 : __ j(zero, &bad);
293 : __ movq(rax, Immediate(32));
294 5 : __ testw(rsi, rax);
295 5 : __ j(zero, &bad);
296 : __ movq(rax, Immediate(64));
297 5 : __ testw(rdi, rax);
298 5 : __ j(zero, &bad);
299 : __ movq(rax, Immediate(128));
300 5 : __ testw(r10, rax);
301 5 : __ j(zero, &bad);
302 :
303 : // Test diffrrent extended register coding combinations.
304 : __ movq(rax, Immediate(5));
305 : __ movq(r11, Immediate(5));
306 5 : __ testb(r11, rax);
307 5 : __ j(zero, &bad);
308 5 : __ testb(rax, r11);
309 5 : __ j(zero, &bad);
310 5 : __ testw(r11, rax);
311 5 : __ j(zero, &bad);
312 5 : __ testw(rax, r11);
313 5 : __ j(zero, &bad);
314 : __ movq(r11, Immediate(3));
315 : __ movq(r12, Immediate(3));
316 : __ movq(rdi, Immediate(3));
317 5 : __ testb(r12, rdi);
318 5 : __ j(zero, &bad);
319 5 : __ testb(rdi, r12);
320 5 : __ j(zero, &bad);
321 5 : __ testb(r12, r11);
322 5 : __ j(zero, &bad);
323 5 : __ testb(r11, r12);
324 5 : __ j(zero, &bad);
325 5 : __ testw(r12, r11);
326 5 : __ j(zero, &bad);
327 5 : __ testw(r11, r12);
328 5 : __ j(zero, &bad);
329 :
330 : // Test sign-extended imediate tests
331 : __ movq(r11, Immediate(2));
332 : __ shlq(r11, Immediate(32));
333 : __ testq(r11, Immediate(-1));
334 5 : __ j(zero, &bad);
335 :
336 : // All tests passed
337 : __ movq(rax, Immediate(1));
338 5 : __ jmp(&done);
339 :
340 5 : __ bind(&bad);
341 : __ movq(rax, Immediate(0));
342 5 : __ bind(&done);
343 :
344 5 : __ popq(r15);
345 5 : __ popq(r14);
346 5 : __ popq(r13);
347 5 : __ popq(r12);
348 5 : __ popq(rsi);
349 5 : __ popq(rdi);
350 5 : __ popq(rbx);
351 :
352 5 : __ ret(0);
353 :
354 5 : CodeDesc desc;
355 5 : masm.GetCode(CcTest::i_isolate(), &desc);
356 5 : buffer->MakeExecutable();
357 : // Call the function from C++.
358 5 : auto f = GeneratedCode<F2>::FromBuffer(CcTest::i_isolate(), buffer->start());
359 : int result = f.Call(0, 0);
360 10 : CHECK_EQ(1, result);
361 5 : }
362 :
363 28342 : TEST(AssemblerX64XchglOperations) {
364 5 : CcTest::InitializeVM();
365 : auto buffer = AllocateAssemblerBuffer();
366 25 : Assembler masm(AssemblerOptions{}, buffer->CreateView());
367 :
368 10 : __ movq(rax, Operand(arg1, 0));
369 10 : __ movq(r11, Operand(arg2, 0));
370 : __ xchgl(rax, r11);
371 10 : __ movq(Operand(arg1, 0), rax);
372 10 : __ movq(Operand(arg2, 0), r11);
373 5 : __ ret(0);
374 :
375 5 : CodeDesc desc;
376 5 : masm.GetCode(CcTest::i_isolate(), &desc);
377 5 : buffer->MakeExecutable();
378 : // Call the function from C++.
379 5 : uint64_t left = V8_2PART_UINT64_C(0x10000000, 20000000);
380 5 : uint64_t right = V8_2PART_UINT64_C(0x30000000, 40000000);
381 5 : auto f = GeneratedCode<F4>::FromBuffer(CcTest::i_isolate(), buffer->start());
382 : uint64_t result = f.Call(&left, &right);
383 5 : CHECK_EQ(V8_2PART_UINT64_C(0x00000000, 40000000), left);
384 5 : CHECK_EQ(V8_2PART_UINT64_C(0x00000000, 20000000), right);
385 : USE(result);
386 5 : }
387 :
388 :
389 28342 : TEST(AssemblerX64OrlOperations) {
390 5 : CcTest::InitializeVM();
391 : auto buffer = AllocateAssemblerBuffer();
392 25 : Assembler masm(AssemblerOptions{}, buffer->CreateView());
393 :
394 10 : __ movq(rax, Operand(arg2, 0));
395 5 : __ orl(Operand(arg1, 0), rax);
396 5 : __ ret(0);
397 :
398 5 : CodeDesc desc;
399 5 : masm.GetCode(CcTest::i_isolate(), &desc);
400 5 : buffer->MakeExecutable();
401 : // Call the function from C++.
402 5 : uint64_t left = V8_2PART_UINT64_C(0x10000000, 20000000);
403 5 : uint64_t right = V8_2PART_UINT64_C(0x30000000, 40000000);
404 5 : auto f = GeneratedCode<F4>::FromBuffer(CcTest::i_isolate(), buffer->start());
405 : uint64_t result = f.Call(&left, &right);
406 5 : CHECK_EQ(V8_2PART_UINT64_C(0x10000000, 60000000), left);
407 : USE(result);
408 5 : }
409 :
410 :
411 28342 : TEST(AssemblerX64RollOperations) {
412 5 : CcTest::InitializeVM();
413 : auto buffer = AllocateAssemblerBuffer();
414 25 : Assembler masm(AssemblerOptions{}, buffer->CreateView());
415 :
416 : __ movq(rax, arg1);
417 : __ roll(rax, Immediate(1));
418 5 : __ ret(0);
419 :
420 5 : CodeDesc desc;
421 5 : masm.GetCode(CcTest::i_isolate(), &desc);
422 5 : buffer->MakeExecutable();
423 : // Call the function from C++.
424 : uint64_t src = V8_2PART_UINT64_C(0x10000000, C0000000);
425 5 : auto f = GeneratedCode<F5>::FromBuffer(CcTest::i_isolate(), buffer->start());
426 : uint64_t result = f.Call(src);
427 5 : CHECK_EQ(V8_2PART_UINT64_C(0x00000000, 80000001), result);
428 5 : }
429 :
430 :
431 28342 : TEST(AssemblerX64SublOperations) {
432 5 : CcTest::InitializeVM();
433 : auto buffer = AllocateAssemblerBuffer();
434 25 : Assembler masm(AssemblerOptions{}, buffer->CreateView());
435 :
436 10 : __ movq(rax, Operand(arg2, 0));
437 5 : __ subl(Operand(arg1, 0), rax);
438 5 : __ ret(0);
439 :
440 5 : CodeDesc desc;
441 5 : masm.GetCode(CcTest::i_isolate(), &desc);
442 5 : buffer->MakeExecutable();
443 : // Call the function from C++.
444 5 : uint64_t left = V8_2PART_UINT64_C(0x10000000, 20000000);
445 5 : uint64_t right = V8_2PART_UINT64_C(0x30000000, 40000000);
446 5 : auto f = GeneratedCode<F4>::FromBuffer(CcTest::i_isolate(), buffer->start());
447 : uint64_t result = f.Call(&left, &right);
448 5 : CHECK_EQ(V8_2PART_UINT64_C(0x10000000, E0000000), left);
449 : USE(result);
450 5 : }
451 :
452 :
453 28342 : TEST(AssemblerX64TestlOperations) {
454 5 : CcTest::InitializeVM();
455 : auto buffer = AllocateAssemblerBuffer();
456 25 : Assembler masm(AssemblerOptions{}, buffer->CreateView());
457 :
458 : // Set rax with the ZF flag of the testl instruction.
459 5 : Label done;
460 : __ movq(rax, Immediate(1));
461 10 : __ movq(r11, Operand(arg2, 0));
462 10 : __ testl(Operand(arg1, 0), r11);
463 5 : __ j(zero, &done, Label::kNear);
464 : __ movq(rax, Immediate(0));
465 5 : __ bind(&done);
466 5 : __ ret(0);
467 :
468 5 : CodeDesc desc;
469 5 : masm.GetCode(CcTest::i_isolate(), &desc);
470 5 : buffer->MakeExecutable();
471 : // Call the function from C++.
472 5 : uint64_t left = V8_2PART_UINT64_C(0x10000000, 20000000);
473 5 : uint64_t right = V8_2PART_UINT64_C(0x30000000, 00000000);
474 5 : auto f = GeneratedCode<F4>::FromBuffer(CcTest::i_isolate(), buffer->start());
475 : uint64_t result = f.Call(&left, &right);
476 5 : CHECK_EQ(1u, result);
477 5 : }
478 :
479 28342 : TEST(AssemblerX64TestwOperations) {
480 : typedef uint16_t(F)(uint16_t * x);
481 5 : CcTest::InitializeVM();
482 : auto buffer = AllocateAssemblerBuffer();
483 25 : Assembler masm(AssemblerOptions{}, buffer->CreateView());
484 :
485 : // Set rax with the ZF flag of the testl instruction.
486 5 : Label done;
487 : __ movq(rax, Immediate(1));
488 5 : __ testw(Operand(arg1, 0), Immediate(0xF0F0));
489 5 : __ j(not_zero, &done, Label::kNear);
490 : __ movq(rax, Immediate(0));
491 5 : __ bind(&done);
492 5 : __ ret(0);
493 :
494 5 : CodeDesc desc;
495 5 : masm.GetCode(CcTest::i_isolate(), &desc);
496 5 : buffer->MakeExecutable();
497 : // Call the function from C++.
498 5 : uint16_t operand = 0x8000;
499 5 : auto f = GeneratedCode<F>::FromBuffer(CcTest::i_isolate(), buffer->start());
500 : uint16_t result = f.Call(&operand);
501 5 : CHECK_EQ(1u, result);
502 5 : }
503 :
504 28342 : TEST(AssemblerX64XorlOperations) {
505 5 : CcTest::InitializeVM();
506 : auto buffer = AllocateAssemblerBuffer();
507 25 : Assembler masm(AssemblerOptions{}, buffer->CreateView());
508 :
509 10 : __ movq(rax, Operand(arg2, 0));
510 5 : __ xorl(Operand(arg1, 0), rax);
511 5 : __ ret(0);
512 :
513 5 : CodeDesc desc;
514 5 : masm.GetCode(CcTest::i_isolate(), &desc);
515 5 : buffer->MakeExecutable();
516 : // Call the function from C++.
517 5 : uint64_t left = V8_2PART_UINT64_C(0x10000000, 20000000);
518 5 : uint64_t right = V8_2PART_UINT64_C(0x30000000, 60000000);
519 5 : auto f = GeneratedCode<F4>::FromBuffer(CcTest::i_isolate(), buffer->start());
520 : uint64_t result = f.Call(&left, &right);
521 5 : CHECK_EQ(V8_2PART_UINT64_C(0x10000000, 40000000), left);
522 : USE(result);
523 5 : }
524 :
525 :
526 28342 : TEST(AssemblerX64MemoryOperands) {
527 5 : CcTest::InitializeVM();
528 : auto buffer = AllocateAssemblerBuffer();
529 25 : Assembler masm(AssemblerOptions{}, buffer->CreateView());
530 :
531 : // Assemble a simple function that copies argument 2 and returns it.
532 5 : __ pushq(rbp);
533 : __ movq(rbp, rsp);
534 :
535 5 : __ pushq(arg2); // Value at (rbp - 8)
536 5 : __ pushq(arg2); // Value at (rbp - 16)
537 5 : __ pushq(arg1); // Value at (rbp - 24)
538 :
539 : const int kStackElementSize = 8;
540 10 : __ movq(rax, Operand(rbp, -3 * kStackElementSize));
541 5 : __ popq(arg2);
542 5 : __ popq(arg2);
543 5 : __ popq(arg2);
544 5 : __ popq(rbp);
545 5 : __ nop();
546 5 : __ ret(0);
547 :
548 5 : CodeDesc desc;
549 5 : masm.GetCode(CcTest::i_isolate(), &desc);
550 5 : buffer->MakeExecutable();
551 : // Call the function from C++.
552 5 : auto f = GeneratedCode<F2>::FromBuffer(CcTest::i_isolate(), buffer->start());
553 : int result = f.Call(3, 2);
554 5 : CHECK_EQ(3, result);
555 5 : }
556 :
557 :
558 28342 : TEST(AssemblerX64ControlFlow) {
559 5 : CcTest::InitializeVM();
560 : auto buffer = AllocateAssemblerBuffer();
561 25 : Assembler masm(AssemblerOptions{}, buffer->CreateView());
562 :
563 : // Assemble a simple function that copies argument 1 and returns it.
564 5 : __ pushq(rbp);
565 :
566 : __ movq(rbp, rsp);
567 : __ movq(rax, arg1);
568 5 : Label target;
569 5 : __ jmp(&target);
570 : __ movq(rax, arg2);
571 5 : __ bind(&target);
572 5 : __ popq(rbp);
573 5 : __ ret(0);
574 :
575 5 : CodeDesc desc;
576 5 : masm.GetCode(CcTest::i_isolate(), &desc);
577 5 : buffer->MakeExecutable();
578 : // Call the function from C++.
579 5 : auto f = GeneratedCode<F2>::FromBuffer(CcTest::i_isolate(), buffer->start());
580 : int result = f.Call(3, 2);
581 5 : CHECK_EQ(3, result);
582 5 : }
583 :
584 :
585 28342 : TEST(AssemblerX64LoopImmediates) {
586 5 : CcTest::InitializeVM();
587 : auto buffer = AllocateAssemblerBuffer();
588 25 : Assembler masm(AssemblerOptions{}, buffer->CreateView());
589 :
590 : // Assemble two loops using rax as counter, and verify the ending counts.
591 5 : Label Fail;
592 : __ movq(rax, Immediate(-3));
593 5 : Label Loop1_test;
594 5 : Label Loop1_body;
595 5 : __ jmp(&Loop1_test);
596 5 : __ bind(&Loop1_body);
597 5 : __ addq(rax, Immediate(7));
598 5 : __ bind(&Loop1_test);
599 5 : __ cmpq(rax, Immediate(20));
600 5 : __ j(less_equal, &Loop1_body);
601 : // Did the loop terminate with the expected value?
602 5 : __ cmpq(rax, Immediate(25));
603 5 : __ j(not_equal, &Fail);
604 :
605 5 : Label Loop2_test;
606 5 : Label Loop2_body;
607 : __ movq(rax, Immediate(0x11FEED00));
608 5 : __ jmp(&Loop2_test);
609 5 : __ bind(&Loop2_body);
610 5 : __ addq(rax, Immediate(-0x1100));
611 5 : __ bind(&Loop2_test);
612 5 : __ cmpq(rax, Immediate(0x11FE8000));
613 5 : __ j(greater, &Loop2_body);
614 : // Did the loop terminate with the expected value?
615 5 : __ cmpq(rax, Immediate(0x11FE7600));
616 5 : __ j(not_equal, &Fail);
617 :
618 : __ movq(rax, Immediate(1));
619 5 : __ ret(0);
620 5 : __ bind(&Fail);
621 : __ movq(rax, Immediate(0));
622 5 : __ ret(0);
623 :
624 5 : CodeDesc desc;
625 5 : masm.GetCode(CcTest::i_isolate(), &desc);
626 5 : buffer->MakeExecutable();
627 : // Call the function from C++.
628 5 : auto f = GeneratedCode<F0>::FromBuffer(CcTest::i_isolate(), buffer->start());
629 : int result = f.Call();
630 5 : CHECK_EQ(1, result);
631 5 : }
632 :
633 :
634 28342 : TEST(OperandRegisterDependency) {
635 5 : int offsets[4] = {0, 1, 0xFED, 0xBEEFCAD};
636 25 : for (int i = 0; i < 4; i++) {
637 20 : int offset = offsets[i];
638 20 : CHECK(Operand(rax, offset).AddressUsesRegister(rax));
639 20 : CHECK(!Operand(rax, offset).AddressUsesRegister(r8));
640 20 : CHECK(!Operand(rax, offset).AddressUsesRegister(rcx));
641 :
642 20 : CHECK(Operand(rax, rax, times_1, offset).AddressUsesRegister(rax));
643 20 : CHECK(!Operand(rax, rax, times_1, offset).AddressUsesRegister(r8));
644 20 : CHECK(!Operand(rax, rax, times_1, offset).AddressUsesRegister(rcx));
645 :
646 20 : CHECK(Operand(rax, rcx, times_1, offset).AddressUsesRegister(rax));
647 20 : CHECK(Operand(rax, rcx, times_1, offset).AddressUsesRegister(rcx));
648 20 : CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(r8));
649 20 : CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(r9));
650 20 : CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(rdx));
651 20 : CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(rsp));
652 :
653 20 : CHECK(Operand(rsp, offset).AddressUsesRegister(rsp));
654 20 : CHECK(!Operand(rsp, offset).AddressUsesRegister(rax));
655 20 : CHECK(!Operand(rsp, offset).AddressUsesRegister(r15));
656 :
657 20 : CHECK(Operand(rbp, offset).AddressUsesRegister(rbp));
658 20 : CHECK(!Operand(rbp, offset).AddressUsesRegister(rax));
659 20 : CHECK(!Operand(rbp, offset).AddressUsesRegister(r13));
660 :
661 20 : CHECK(Operand(rbp, rax, times_1, offset).AddressUsesRegister(rbp));
662 20 : CHECK(Operand(rbp, rax, times_1, offset).AddressUsesRegister(rax));
663 20 : CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(rcx));
664 20 : CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(r13));
665 20 : CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(r8));
666 20 : CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(rsp));
667 :
668 20 : CHECK(Operand(rsp, rbp, times_1, offset).AddressUsesRegister(rsp));
669 20 : CHECK(Operand(rsp, rbp, times_1, offset).AddressUsesRegister(rbp));
670 20 : CHECK(!Operand(rsp, rbp, times_1, offset).AddressUsesRegister(rax));
671 20 : CHECK(!Operand(rsp, rbp, times_1, offset).AddressUsesRegister(r15));
672 20 : CHECK(!Operand(rsp, rbp, times_1, offset).AddressUsesRegister(r13));
673 : }
674 5 : }
675 :
676 :
677 28342 : TEST(AssemblerX64LabelChaining) {
678 : // Test chaining of label usages within instructions (issue 1644).
679 5 : CcTest::InitializeVM();
680 5 : v8::HandleScope scope(CcTest::isolate());
681 20 : Assembler masm(AssemblerOptions{});
682 :
683 5 : Label target;
684 5 : __ j(equal, &target);
685 5 : __ j(not_equal, &target);
686 5 : __ bind(&target);
687 10 : __ nop();
688 5 : }
689 :
690 :
691 28342 : TEST(AssemblerMultiByteNop) {
692 5 : CcTest::InitializeVM();
693 5 : v8::HandleScope scope(CcTest::isolate());
694 : byte buffer[1024];
695 : Isolate* isolate = CcTest::i_isolate();
696 : Assembler masm(AssemblerOptions{},
697 20 : ExternalAssemblerBuffer(buffer, sizeof(buffer)));
698 5 : __ pushq(rbx);
699 5 : __ pushq(rcx);
700 5 : __ pushq(rdx);
701 5 : __ pushq(rdi);
702 5 : __ pushq(rsi);
703 : __ movq(rax, Immediate(1));
704 : __ movq(rbx, Immediate(2));
705 : __ movq(rcx, Immediate(3));
706 : __ movq(rdx, Immediate(4));
707 : __ movq(rdi, Immediate(5));
708 : __ movq(rsi, Immediate(6));
709 85 : for (int i = 0; i < 16; i++) {
710 80 : int before = masm.pc_offset();
711 80 : __ Nop(i);
712 160 : CHECK_EQ(masm.pc_offset() - before, i);
713 : }
714 :
715 5 : Label fail;
716 5 : __ cmpq(rax, Immediate(1));
717 5 : __ j(not_equal, &fail);
718 5 : __ cmpq(rbx, Immediate(2));
719 5 : __ j(not_equal, &fail);
720 5 : __ cmpq(rcx, Immediate(3));
721 5 : __ j(not_equal, &fail);
722 5 : __ cmpq(rdx, Immediate(4));
723 5 : __ j(not_equal, &fail);
724 5 : __ cmpq(rdi, Immediate(5));
725 5 : __ j(not_equal, &fail);
726 5 : __ cmpq(rsi, Immediate(6));
727 5 : __ j(not_equal, &fail);
728 : __ movq(rax, Immediate(42));
729 5 : __ popq(rsi);
730 5 : __ popq(rdi);
731 5 : __ popq(rdx);
732 5 : __ popq(rcx);
733 5 : __ popq(rbx);
734 5 : __ ret(0);
735 5 : __ bind(&fail);
736 : __ movq(rax, Immediate(13));
737 5 : __ popq(rsi);
738 5 : __ popq(rdi);
739 5 : __ popq(rdx);
740 5 : __ popq(rcx);
741 5 : __ popq(rbx);
742 5 : __ ret(0);
743 :
744 5 : CodeDesc desc;
745 5 : masm.GetCode(isolate, &desc);
746 : Handle<Code> code =
747 10 : isolate->factory()->NewCode(desc, Code::STUB, Handle<Code>());
748 :
749 : auto f = GeneratedCode<F0>::FromCode(*code);
750 : int res = f.Call();
751 10 : CHECK_EQ(42, res);
752 5 : }
753 :
754 :
755 : #ifdef __GNUC__
756 : #define ELEMENT_COUNT 4u
757 :
758 10 : void DoSSE2(const v8::FunctionCallbackInfo<v8::Value>& args) {
759 5 : v8::HandleScope scope(CcTest::isolate());
760 5 : v8::Local<v8::Context> context = CcTest::isolate()->GetCurrentContext();
761 : byte buffer[1024];
762 :
763 5 : CHECK(args[0]->IsArray());
764 : v8::Local<v8::Array> vec = v8::Local<v8::Array>::Cast(args[0]);
765 5 : CHECK_EQ(ELEMENT_COUNT, vec->Length());
766 :
767 : Isolate* isolate = CcTest::i_isolate();
768 : Assembler masm(AssemblerOptions{},
769 20 : ExternalAssemblerBuffer(buffer, sizeof(buffer)));
770 :
771 : // Remove return address from the stack for fix stack frame alignment.
772 5 : __ popq(rcx);
773 :
774 : // Store input vector on the stack.
775 15 : for (unsigned i = 0; i < ELEMENT_COUNT; i++) {
776 : __ movl(rax, Immediate(vec->Get(context, i)
777 10 : .ToLocalChecked()
778 : ->Int32Value(context)
779 20 : .FromJust()));
780 : __ shlq(rax, Immediate(0x20));
781 : __ orq(rax, Immediate(vec->Get(context, ++i)
782 10 : .ToLocalChecked()
783 : ->Int32Value(context)
784 20 : .FromJust()));
785 10 : __ pushq(rax);
786 : }
787 :
788 : // Read vector into a xmm register.
789 5 : __ xorps(xmm0, xmm0);
790 5 : __ movdqa(xmm0, Operand(rsp, 0));
791 : // Create mask and store it in the return register.
792 5 : __ movmskps(rax, xmm0);
793 :
794 : // Remove unused data from the stack.
795 5 : __ addq(rsp, Immediate(ELEMENT_COUNT * sizeof(int32_t)));
796 : // Restore return address.
797 5 : __ pushq(rcx);
798 :
799 5 : __ ret(0);
800 :
801 5 : CodeDesc desc;
802 5 : masm.GetCode(isolate, &desc);
803 : Handle<Code> code =
804 10 : isolate->factory()->NewCode(desc, Code::STUB, Handle<Code>());
805 :
806 : auto f = GeneratedCode<F0>::FromCode(*code);
807 : int res = f.Call();
808 10 : args.GetReturnValue().Set(v8::Integer::New(CcTest::isolate(), res));
809 5 : }
810 :
811 :
812 28342 : TEST(StackAlignmentForSSE2) {
813 5 : CcTest::InitializeVM();
814 5 : CHECK_EQ(0, v8::base::OS::ActivationFrameAlignment() % 16);
815 :
816 5 : v8::Isolate* isolate = CcTest::isolate();
817 5 : v8::HandleScope handle_scope(isolate);
818 : v8::Local<v8::ObjectTemplate> global_template =
819 5 : v8::ObjectTemplate::New(isolate);
820 : global_template->Set(v8_str("do_sse2"),
821 15 : v8::FunctionTemplate::New(isolate, DoSSE2));
822 :
823 10 : LocalContext env(nullptr, global_template);
824 : CompileRun(
825 : "function foo(vec) {"
826 : " return do_sse2(vec);"
827 : "}");
828 :
829 5 : v8::Local<v8::Object> global_object = env->Global();
830 : v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
831 20 : global_object->Get(env.local(), v8_str("foo")).ToLocalChecked());
832 :
833 5 : int32_t vec[ELEMENT_COUNT] = { -1, 1, 1, 1 };
834 5 : v8::Local<v8::Array> v8_vec = v8::Array::New(isolate, ELEMENT_COUNT);
835 25 : for (unsigned i = 0; i < ELEMENT_COUNT; i++) {
836 60 : v8_vec->Set(env.local(), i, v8_num(vec[i])).FromJust();
837 : }
838 :
839 : v8::Local<v8::Value> args[] = { v8_vec };
840 : v8::Local<v8::Value> result =
841 10 : foo->Call(env.local(), global_object, 1, args).ToLocalChecked();
842 :
843 : // The mask should be 0b1000.
844 15 : CHECK_EQ(8, result->Int32Value(env.local()).FromJust());
845 5 : }
846 :
847 : #undef ELEMENT_COUNT
848 : #endif // __GNUC__
849 :
850 :
851 28342 : TEST(AssemblerX64Extractps) {
852 5 : CcTest::InitializeVM();
853 5 : if (!CpuFeatures::IsSupported(SSE4_1)) return;
854 :
855 5 : v8::HandleScope scope(CcTest::isolate());
856 : byte buffer[256];
857 : Isolate* isolate = CcTest::i_isolate();
858 : Assembler masm(AssemblerOptions{},
859 20 : ExternalAssemblerBuffer(buffer, sizeof(buffer)));
860 : {
861 : CpuFeatureScope fscope2(&masm, SSE4_1);
862 5 : __ extractps(rax, xmm0, 0x1);
863 5 : __ ret(0);
864 : }
865 :
866 5 : CodeDesc desc;
867 5 : masm.GetCode(isolate, &desc);
868 : Handle<Code> code =
869 10 : isolate->factory()->NewCode(desc, Code::STUB, Handle<Code>());
870 : #ifdef OBJECT_PRINT
871 : StdoutStream os;
872 : code->Print(os);
873 : #endif
874 :
875 : auto f = GeneratedCode<F3>::FromCode(*code);
876 : uint64_t value1 = V8_2PART_UINT64_C(0x12345678, 87654321);
877 5 : CHECK_EQ(0x12345678u, f.Call(uint64_to_double(value1)));
878 : uint64_t value2 = V8_2PART_UINT64_C(0x87654321, 12345678);
879 10 : CHECK_EQ(0x87654321u, f.Call(uint64_to_double(value2)));
880 : }
881 :
882 : typedef int(F6)(float x, float y);
883 28342 : TEST(AssemblerX64SSE) {
884 5 : CcTest::InitializeVM();
885 :
886 5 : Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
887 : HandleScope scope(isolate);
888 : v8::internal::byte buffer[256];
889 : MacroAssembler masm(isolate, v8::internal::CodeObjectRequired::kYes,
890 15 : ExternalAssemblerBuffer(buffer, sizeof(buffer)));
891 : {
892 5 : __ shufps(xmm0, xmm0, 0x0); // brocast first argument
893 5 : __ shufps(xmm1, xmm1, 0x0); // brocast second argument
894 5 : __ movaps(xmm2, xmm1);
895 5 : __ addps(xmm2, xmm0);
896 5 : __ mulps(xmm2, xmm1);
897 5 : __ subps(xmm2, xmm0);
898 5 : __ divps(xmm2, xmm1);
899 5 : __ cvttss2si(rax, xmm2);
900 5 : __ ret(0);
901 : }
902 :
903 5 : CodeDesc desc;
904 5 : masm.GetCode(isolate, &desc);
905 : Handle<Code> code =
906 10 : isolate->factory()->NewCode(desc, Code::STUB, Handle<Code>());
907 : #ifdef OBJECT_PRINT
908 : StdoutStream os;
909 : code->Print(os);
910 : #endif
911 :
912 : auto f = GeneratedCode<F6>::FromCode(*code);
913 5 : CHECK_EQ(2, f.Call(1.0, 2.0));
914 5 : }
915 :
916 28342 : TEST(AssemblerX64SSE3) {
917 5 : CcTest::InitializeVM();
918 5 : if (!CpuFeatures::IsSupported(SSE3)) return;
919 :
920 5 : Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
921 : HandleScope scope(isolate);
922 : v8::internal::byte buffer[256];
923 : MacroAssembler masm(isolate, v8::internal::CodeObjectRequired::kYes,
924 15 : ExternalAssemblerBuffer(buffer, sizeof(buffer)));
925 : {
926 : CpuFeatureScope fscope(&masm, SSE3);
927 5 : __ shufps(xmm0, xmm0, 0x0); // brocast first argument
928 5 : __ shufps(xmm1, xmm1, 0x0); // brocast second argument
929 5 : __ haddps(xmm1, xmm0);
930 5 : __ cvttss2si(rax, xmm1);
931 5 : __ ret(0);
932 : }
933 :
934 5 : CodeDesc desc;
935 5 : masm.GetCode(isolate, &desc);
936 : Handle<Code> code =
937 10 : isolate->factory()->NewCode(desc, Code::STUB, Handle<Code>());
938 : #ifdef OBJECT_PRINT
939 : StdoutStream os;
940 : code->Print(os);
941 : #endif
942 :
943 : auto f = GeneratedCode<F6>::FromCode(*code);
944 5 : CHECK_EQ(4, f.Call(1.0, 2.0));
945 : }
946 :
947 : typedef int(F7)(double x, double y, double z);
948 28342 : TEST(AssemblerX64FMA_sd) {
949 5 : CcTest::InitializeVM();
950 5 : if (!CpuFeatures::IsSupported(FMA3)) return;
951 :
952 5 : Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
953 : HandleScope scope(isolate);
954 : v8::internal::byte buffer[1024];
955 : MacroAssembler masm(isolate, v8::internal::CodeObjectRequired::kYes,
956 15 : ExternalAssemblerBuffer(buffer, sizeof(buffer)));
957 : {
958 : CpuFeatureScope fscope(&masm, FMA3);
959 5 : Label exit;
960 : // argument in xmm0, xmm1 and xmm2
961 : // xmm0 * xmm1 + xmm2
962 5 : __ movaps(xmm3, xmm0);
963 5 : __ mulsd(xmm3, xmm1);
964 5 : __ addsd(xmm3, xmm2); // Expected result in xmm3
965 :
966 5 : __ subq(rsp, Immediate(kDoubleSize)); // For memory operand
967 : // vfmadd132sd
968 : __ movl(rax, Immediate(1)); // Test number
969 5 : __ movaps(xmm8, xmm0);
970 : __ vfmadd132sd(xmm8, xmm2, xmm1);
971 5 : __ ucomisd(xmm8, xmm3);
972 5 : __ j(not_equal, &exit);
973 : // vfmadd213sd
974 : __ incq(rax);
975 5 : __ movaps(xmm8, xmm1);
976 : __ vfmadd213sd(xmm8, xmm0, xmm2);
977 5 : __ ucomisd(xmm8, xmm3);
978 5 : __ j(not_equal, &exit);
979 : // vfmadd231sd
980 : __ incq(rax);
981 5 : __ movaps(xmm8, xmm2);
982 : __ vfmadd231sd(xmm8, xmm0, xmm1);
983 5 : __ ucomisd(xmm8, xmm3);
984 5 : __ j(not_equal, &exit);
985 :
986 : // vfmadd132sd
987 : __ incq(rax);
988 5 : __ movaps(xmm8, xmm0);
989 5 : __ movsd(Operand(rsp, 0), xmm1);
990 10 : __ vfmadd132sd(xmm8, xmm2, Operand(rsp, 0));
991 5 : __ ucomisd(xmm8, xmm3);
992 5 : __ j(not_equal, &exit);
993 : // vfmadd213sd
994 : __ incq(rax);
995 5 : __ movaps(xmm8, xmm1);
996 5 : __ movsd(Operand(rsp, 0), xmm2);
997 10 : __ vfmadd213sd(xmm8, xmm0, Operand(rsp, 0));
998 5 : __ ucomisd(xmm8, xmm3);
999 5 : __ j(not_equal, &exit);
1000 : // vfmadd231sd
1001 : __ incq(rax);
1002 5 : __ movaps(xmm8, xmm2);
1003 5 : __ movsd(Operand(rsp, 0), xmm1);
1004 10 : __ vfmadd231sd(xmm8, xmm0, Operand(rsp, 0));
1005 5 : __ ucomisd(xmm8, xmm3);
1006 5 : __ j(not_equal, &exit);
1007 :
1008 : // xmm0 * xmm1 - xmm2
1009 5 : __ movaps(xmm3, xmm0);
1010 5 : __ mulsd(xmm3, xmm1);
1011 5 : __ subsd(xmm3, xmm2); // Expected result in xmm3
1012 :
1013 : // vfmsub132sd
1014 : __ incq(rax);
1015 5 : __ movaps(xmm8, xmm0);
1016 : __ vfmsub132sd(xmm8, xmm2, xmm1);
1017 5 : __ ucomisd(xmm8, xmm3);
1018 5 : __ j(not_equal, &exit);
1019 : // vfmadd213sd
1020 : __ incq(rax);
1021 5 : __ movaps(xmm8, xmm1);
1022 : __ vfmsub213sd(xmm8, xmm0, xmm2);
1023 5 : __ ucomisd(xmm8, xmm3);
1024 5 : __ j(not_equal, &exit);
1025 : // vfmsub231sd
1026 : __ incq(rax);
1027 5 : __ movaps(xmm8, xmm2);
1028 : __ vfmsub231sd(xmm8, xmm0, xmm1);
1029 5 : __ ucomisd(xmm8, xmm3);
1030 5 : __ j(not_equal, &exit);
1031 :
1032 : // vfmsub132sd
1033 : __ incq(rax);
1034 5 : __ movaps(xmm8, xmm0);
1035 5 : __ movsd(Operand(rsp, 0), xmm1);
1036 10 : __ vfmsub132sd(xmm8, xmm2, Operand(rsp, 0));
1037 5 : __ ucomisd(xmm8, xmm3);
1038 5 : __ j(not_equal, &exit);
1039 : // vfmsub213sd
1040 : __ incq(rax);
1041 5 : __ movaps(xmm8, xmm1);
1042 5 : __ movsd(Operand(rsp, 0), xmm2);
1043 10 : __ vfmsub213sd(xmm8, xmm0, Operand(rsp, 0));
1044 5 : __ ucomisd(xmm8, xmm3);
1045 5 : __ j(not_equal, &exit);
1046 : // vfmsub231sd
1047 : __ incq(rax);
1048 5 : __ movaps(xmm8, xmm2);
1049 5 : __ movsd(Operand(rsp, 0), xmm1);
1050 10 : __ vfmsub231sd(xmm8, xmm0, Operand(rsp, 0));
1051 5 : __ ucomisd(xmm8, xmm3);
1052 5 : __ j(not_equal, &exit);
1053 :
1054 :
1055 : // - xmm0 * xmm1 + xmm2
1056 5 : __ movaps(xmm3, xmm0);
1057 5 : __ mulsd(xmm3, xmm1);
1058 5 : __ Move(xmm4, static_cast<uint64_t>(1) << 63);
1059 5 : __ xorpd(xmm3, xmm4);
1060 5 : __ addsd(xmm3, xmm2); // Expected result in xmm3
1061 :
1062 : // vfnmadd132sd
1063 : __ incq(rax);
1064 5 : __ movaps(xmm8, xmm0);
1065 : __ vfnmadd132sd(xmm8, xmm2, xmm1);
1066 5 : __ ucomisd(xmm8, xmm3);
1067 5 : __ j(not_equal, &exit);
1068 : // vfmadd213sd
1069 : __ incq(rax);
1070 5 : __ movaps(xmm8, xmm1);
1071 : __ vfnmadd213sd(xmm8, xmm0, xmm2);
1072 5 : __ ucomisd(xmm8, xmm3);
1073 5 : __ j(not_equal, &exit);
1074 : // vfnmadd231sd
1075 : __ incq(rax);
1076 5 : __ movaps(xmm8, xmm2);
1077 : __ vfnmadd231sd(xmm8, xmm0, xmm1);
1078 5 : __ ucomisd(xmm8, xmm3);
1079 5 : __ j(not_equal, &exit);
1080 :
1081 : // vfnmadd132sd
1082 : __ incq(rax);
1083 5 : __ movaps(xmm8, xmm0);
1084 5 : __ movsd(Operand(rsp, 0), xmm1);
1085 10 : __ vfnmadd132sd(xmm8, xmm2, Operand(rsp, 0));
1086 5 : __ ucomisd(xmm8, xmm3);
1087 5 : __ j(not_equal, &exit);
1088 : // vfnmadd213sd
1089 : __ incq(rax);
1090 5 : __ movaps(xmm8, xmm1);
1091 5 : __ movsd(Operand(rsp, 0), xmm2);
1092 10 : __ vfnmadd213sd(xmm8, xmm0, Operand(rsp, 0));
1093 5 : __ ucomisd(xmm8, xmm3);
1094 5 : __ j(not_equal, &exit);
1095 : // vfnmadd231sd
1096 : __ incq(rax);
1097 5 : __ movaps(xmm8, xmm2);
1098 5 : __ movsd(Operand(rsp, 0), xmm1);
1099 10 : __ vfnmadd231sd(xmm8, xmm0, Operand(rsp, 0));
1100 5 : __ ucomisd(xmm8, xmm3);
1101 5 : __ j(not_equal, &exit);
1102 :
1103 :
1104 : // - xmm0 * xmm1 - xmm2
1105 5 : __ movaps(xmm3, xmm0);
1106 5 : __ mulsd(xmm3, xmm1);
1107 5 : __ Move(xmm4, static_cast<uint64_t>(1) << 63);
1108 5 : __ xorpd(xmm3, xmm4);
1109 5 : __ subsd(xmm3, xmm2); // Expected result in xmm3
1110 :
1111 : // vfnmsub132sd
1112 : __ incq(rax);
1113 5 : __ movaps(xmm8, xmm0);
1114 : __ vfnmsub132sd(xmm8, xmm2, xmm1);
1115 5 : __ ucomisd(xmm8, xmm3);
1116 5 : __ j(not_equal, &exit);
1117 : // vfmsub213sd
1118 : __ incq(rax);
1119 5 : __ movaps(xmm8, xmm1);
1120 : __ vfnmsub213sd(xmm8, xmm0, xmm2);
1121 5 : __ ucomisd(xmm8, xmm3);
1122 5 : __ j(not_equal, &exit);
1123 : // vfnmsub231sd
1124 : __ incq(rax);
1125 5 : __ movaps(xmm8, xmm2);
1126 : __ vfnmsub231sd(xmm8, xmm0, xmm1);
1127 5 : __ ucomisd(xmm8, xmm3);
1128 5 : __ j(not_equal, &exit);
1129 :
1130 : // vfnmsub132sd
1131 : __ incq(rax);
1132 5 : __ movaps(xmm8, xmm0);
1133 5 : __ movsd(Operand(rsp, 0), xmm1);
1134 10 : __ vfnmsub132sd(xmm8, xmm2, Operand(rsp, 0));
1135 5 : __ ucomisd(xmm8, xmm3);
1136 5 : __ j(not_equal, &exit);
1137 : // vfnmsub213sd
1138 : __ incq(rax);
1139 5 : __ movaps(xmm8, xmm1);
1140 5 : __ movsd(Operand(rsp, 0), xmm2);
1141 10 : __ vfnmsub213sd(xmm8, xmm0, Operand(rsp, 0));
1142 5 : __ ucomisd(xmm8, xmm3);
1143 5 : __ j(not_equal, &exit);
1144 : // vfnmsub231sd
1145 : __ incq(rax);
1146 5 : __ movaps(xmm8, xmm2);
1147 5 : __ movsd(Operand(rsp, 0), xmm1);
1148 10 : __ vfnmsub231sd(xmm8, xmm0, Operand(rsp, 0));
1149 5 : __ ucomisd(xmm8, xmm3);
1150 5 : __ j(not_equal, &exit);
1151 :
1152 :
1153 : __ xorl(rax, rax);
1154 5 : __ bind(&exit);
1155 5 : __ addq(rsp, Immediate(kDoubleSize));
1156 5 : __ ret(0);
1157 : }
1158 :
1159 5 : CodeDesc desc;
1160 5 : masm.GetCode(isolate, &desc);
1161 : Handle<Code> code =
1162 10 : isolate->factory()->NewCode(desc, Code::STUB, Handle<Code>());
1163 : #ifdef OBJECT_PRINT
1164 : StdoutStream os;
1165 : code->Print(os);
1166 : #endif
1167 :
1168 : auto f = GeneratedCode<F7>::FromCode(*code);
1169 5 : CHECK_EQ(
1170 : 0, f.Call(0.000092662107262076, -2.460774966188315, -1.0958787393627414));
1171 : }
1172 :
1173 : typedef int(F8)(float x, float y, float z);
1174 28342 : TEST(AssemblerX64FMA_ss) {
1175 5 : CcTest::InitializeVM();
1176 5 : if (!CpuFeatures::IsSupported(FMA3)) return;
1177 :
1178 5 : Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
1179 : HandleScope scope(isolate);
1180 : v8::internal::byte buffer[1024];
1181 : MacroAssembler masm(isolate, v8::internal::CodeObjectRequired::kYes,
1182 15 : ExternalAssemblerBuffer(buffer, sizeof(buffer)));
1183 : {
1184 : CpuFeatureScope fscope(&masm, FMA3);
1185 5 : Label exit;
1186 : // arguments in xmm0, xmm1 and xmm2
1187 : // xmm0 * xmm1 + xmm2
1188 5 : __ movaps(xmm3, xmm0);
1189 5 : __ mulss(xmm3, xmm1);
1190 5 : __ addss(xmm3, xmm2); // Expected result in xmm3
1191 :
1192 5 : __ subq(rsp, Immediate(kDoubleSize)); // For memory operand
1193 : // vfmadd132ss
1194 : __ movl(rax, Immediate(1)); // Test number
1195 5 : __ movaps(xmm8, xmm0);
1196 : __ vfmadd132ss(xmm8, xmm2, xmm1);
1197 5 : __ ucomiss(xmm8, xmm3);
1198 5 : __ j(not_equal, &exit);
1199 : // vfmadd213ss
1200 : __ incq(rax);
1201 5 : __ movaps(xmm8, xmm1);
1202 : __ vfmadd213ss(xmm8, xmm0, xmm2);
1203 5 : __ ucomiss(xmm8, xmm3);
1204 5 : __ j(not_equal, &exit);
1205 : // vfmadd231ss
1206 : __ incq(rax);
1207 5 : __ movaps(xmm8, xmm2);
1208 : __ vfmadd231ss(xmm8, xmm0, xmm1);
1209 5 : __ ucomiss(xmm8, xmm3);
1210 5 : __ j(not_equal, &exit);
1211 :
1212 : // vfmadd132ss
1213 : __ incq(rax);
1214 5 : __ movaps(xmm8, xmm0);
1215 5 : __ movss(Operand(rsp, 0), xmm1);
1216 10 : __ vfmadd132ss(xmm8, xmm2, Operand(rsp, 0));
1217 5 : __ ucomiss(xmm8, xmm3);
1218 5 : __ j(not_equal, &exit);
1219 : // vfmadd213ss
1220 : __ incq(rax);
1221 5 : __ movaps(xmm8, xmm1);
1222 5 : __ movss(Operand(rsp, 0), xmm2);
1223 10 : __ vfmadd213ss(xmm8, xmm0, Operand(rsp, 0));
1224 5 : __ ucomiss(xmm8, xmm3);
1225 5 : __ j(not_equal, &exit);
1226 : // vfmadd231ss
1227 : __ incq(rax);
1228 5 : __ movaps(xmm8, xmm2);
1229 5 : __ movss(Operand(rsp, 0), xmm1);
1230 10 : __ vfmadd231ss(xmm8, xmm0, Operand(rsp, 0));
1231 5 : __ ucomiss(xmm8, xmm3);
1232 5 : __ j(not_equal, &exit);
1233 :
1234 : // xmm0 * xmm1 - xmm2
1235 5 : __ movaps(xmm3, xmm0);
1236 5 : __ mulss(xmm3, xmm1);
1237 5 : __ subss(xmm3, xmm2); // Expected result in xmm3
1238 :
1239 : // vfmsub132ss
1240 : __ incq(rax);
1241 5 : __ movaps(xmm8, xmm0);
1242 : __ vfmsub132ss(xmm8, xmm2, xmm1);
1243 5 : __ ucomiss(xmm8, xmm3);
1244 5 : __ j(not_equal, &exit);
1245 : // vfmadd213ss
1246 : __ incq(rax);
1247 5 : __ movaps(xmm8, xmm1);
1248 : __ vfmsub213ss(xmm8, xmm0, xmm2);
1249 5 : __ ucomiss(xmm8, xmm3);
1250 5 : __ j(not_equal, &exit);
1251 : // vfmsub231ss
1252 : __ incq(rax);
1253 5 : __ movaps(xmm8, xmm2);
1254 : __ vfmsub231ss(xmm8, xmm0, xmm1);
1255 5 : __ ucomiss(xmm8, xmm3);
1256 5 : __ j(not_equal, &exit);
1257 :
1258 : // vfmsub132ss
1259 : __ incq(rax);
1260 5 : __ movaps(xmm8, xmm0);
1261 5 : __ movss(Operand(rsp, 0), xmm1);
1262 10 : __ vfmsub132ss(xmm8, xmm2, Operand(rsp, 0));
1263 5 : __ ucomiss(xmm8, xmm3);
1264 5 : __ j(not_equal, &exit);
1265 : // vfmsub213ss
1266 : __ incq(rax);
1267 5 : __ movaps(xmm8, xmm1);
1268 5 : __ movss(Operand(rsp, 0), xmm2);
1269 10 : __ vfmsub213ss(xmm8, xmm0, Operand(rsp, 0));
1270 5 : __ ucomiss(xmm8, xmm3);
1271 5 : __ j(not_equal, &exit);
1272 : // vfmsub231ss
1273 : __ incq(rax);
1274 5 : __ movaps(xmm8, xmm2);
1275 5 : __ movss(Operand(rsp, 0), xmm1);
1276 10 : __ vfmsub231ss(xmm8, xmm0, Operand(rsp, 0));
1277 5 : __ ucomiss(xmm8, xmm3);
1278 5 : __ j(not_equal, &exit);
1279 :
1280 :
1281 : // - xmm0 * xmm1 + xmm2
1282 5 : __ movaps(xmm3, xmm0);
1283 5 : __ mulss(xmm3, xmm1);
1284 5 : __ Move(xmm4, static_cast<uint32_t>(1) << 31);
1285 5 : __ xorps(xmm3, xmm4);
1286 5 : __ addss(xmm3, xmm2); // Expected result in xmm3
1287 :
1288 : // vfnmadd132ss
1289 : __ incq(rax);
1290 5 : __ movaps(xmm8, xmm0);
1291 : __ vfnmadd132ss(xmm8, xmm2, xmm1);
1292 5 : __ ucomiss(xmm8, xmm3);
1293 5 : __ j(not_equal, &exit);
1294 : // vfmadd213ss
1295 : __ incq(rax);
1296 5 : __ movaps(xmm8, xmm1);
1297 : __ vfnmadd213ss(xmm8, xmm0, xmm2);
1298 5 : __ ucomiss(xmm8, xmm3);
1299 5 : __ j(not_equal, &exit);
1300 : // vfnmadd231ss
1301 : __ incq(rax);
1302 5 : __ movaps(xmm8, xmm2);
1303 : __ vfnmadd231ss(xmm8, xmm0, xmm1);
1304 5 : __ ucomiss(xmm8, xmm3);
1305 5 : __ j(not_equal, &exit);
1306 :
1307 : // vfnmadd132ss
1308 : __ incq(rax);
1309 5 : __ movaps(xmm8, xmm0);
1310 5 : __ movss(Operand(rsp, 0), xmm1);
1311 10 : __ vfnmadd132ss(xmm8, xmm2, Operand(rsp, 0));
1312 5 : __ ucomiss(xmm8, xmm3);
1313 5 : __ j(not_equal, &exit);
1314 : // vfnmadd213ss
1315 : __ incq(rax);
1316 5 : __ movaps(xmm8, xmm1);
1317 5 : __ movss(Operand(rsp, 0), xmm2);
1318 10 : __ vfnmadd213ss(xmm8, xmm0, Operand(rsp, 0));
1319 5 : __ ucomiss(xmm8, xmm3);
1320 5 : __ j(not_equal, &exit);
1321 : // vfnmadd231ss
1322 : __ incq(rax);
1323 5 : __ movaps(xmm8, xmm2);
1324 5 : __ movss(Operand(rsp, 0), xmm1);
1325 10 : __ vfnmadd231ss(xmm8, xmm0, Operand(rsp, 0));
1326 5 : __ ucomiss(xmm8, xmm3);
1327 5 : __ j(not_equal, &exit);
1328 :
1329 :
1330 : // - xmm0 * xmm1 - xmm2
1331 5 : __ movaps(xmm3, xmm0);
1332 5 : __ mulss(xmm3, xmm1);
1333 5 : __ Move(xmm4, static_cast<uint32_t>(1) << 31);
1334 5 : __ xorps(xmm3, xmm4);
1335 5 : __ subss(xmm3, xmm2); // Expected result in xmm3
1336 :
1337 : // vfnmsub132ss
1338 : __ incq(rax);
1339 5 : __ movaps(xmm8, xmm0);
1340 : __ vfnmsub132ss(xmm8, xmm2, xmm1);
1341 5 : __ ucomiss(xmm8, xmm3);
1342 5 : __ j(not_equal, &exit);
1343 : // vfmsub213ss
1344 : __ incq(rax);
1345 5 : __ movaps(xmm8, xmm1);
1346 : __ vfnmsub213ss(xmm8, xmm0, xmm2);
1347 5 : __ ucomiss(xmm8, xmm3);
1348 5 : __ j(not_equal, &exit);
1349 : // vfnmsub231ss
1350 : __ incq(rax);
1351 5 : __ movaps(xmm8, xmm2);
1352 : __ vfnmsub231ss(xmm8, xmm0, xmm1);
1353 5 : __ ucomiss(xmm8, xmm3);
1354 5 : __ j(not_equal, &exit);
1355 :
1356 : // vfnmsub132ss
1357 : __ incq(rax);
1358 5 : __ movaps(xmm8, xmm0);
1359 5 : __ movss(Operand(rsp, 0), xmm1);
1360 10 : __ vfnmsub132ss(xmm8, xmm2, Operand(rsp, 0));
1361 5 : __ ucomiss(xmm8, xmm3);
1362 5 : __ j(not_equal, &exit);
1363 : // vfnmsub213ss
1364 : __ incq(rax);
1365 5 : __ movaps(xmm8, xmm1);
1366 5 : __ movss(Operand(rsp, 0), xmm2);
1367 10 : __ vfnmsub213ss(xmm8, xmm0, Operand(rsp, 0));
1368 5 : __ ucomiss(xmm8, xmm3);
1369 5 : __ j(not_equal, &exit);
1370 : // vfnmsub231ss
1371 : __ incq(rax);
1372 5 : __ movaps(xmm8, xmm2);
1373 5 : __ movss(Operand(rsp, 0), xmm1);
1374 10 : __ vfnmsub231ss(xmm8, xmm0, Operand(rsp, 0));
1375 5 : __ ucomiss(xmm8, xmm3);
1376 5 : __ j(not_equal, &exit);
1377 :
1378 :
1379 : __ xorl(rax, rax);
1380 5 : __ bind(&exit);
1381 5 : __ addq(rsp, Immediate(kDoubleSize));
1382 5 : __ ret(0);
1383 : }
1384 :
1385 5 : CodeDesc desc;
1386 5 : masm.GetCode(isolate, &desc);
1387 : Handle<Code> code =
1388 10 : isolate->factory()->NewCode(desc, Code::STUB, Handle<Code>());
1389 : #ifdef OBJECT_PRINT
1390 : StdoutStream os;
1391 : code->Print(os);
1392 : #endif
1393 :
1394 : auto f = GeneratedCode<F8>::FromCode(*code);
1395 5 : CHECK_EQ(0, f.Call(9.26621069e-05f, -2.4607749f, -1.09587872f));
1396 : }
1397 :
1398 :
1399 28342 : TEST(AssemblerX64SSE_ss) {
1400 5 : CcTest::InitializeVM();
1401 :
1402 5 : Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
1403 : HandleScope scope(isolate);
1404 : v8::internal::byte buffer[1024];
1405 : Assembler masm(AssemblerOptions{},
1406 20 : ExternalAssemblerBuffer(buffer, sizeof(buffer)));
1407 : {
1408 5 : Label exit;
1409 : // arguments in xmm0, xmm1 and xmm2
1410 : __ movl(rax, Immediate(0));
1411 :
1412 5 : __ movaps(xmm3, xmm0);
1413 5 : __ maxss(xmm3, xmm1);
1414 5 : __ ucomiss(xmm3, xmm1);
1415 5 : __ j(parity_even, &exit);
1416 5 : __ j(not_equal, &exit);
1417 : __ movl(rax, Immediate(1));
1418 :
1419 5 : __ movaps(xmm3, xmm1);
1420 5 : __ minss(xmm3, xmm2);
1421 5 : __ ucomiss(xmm3, xmm1);
1422 5 : __ j(parity_even, &exit);
1423 5 : __ j(not_equal, &exit);
1424 : __ movl(rax, Immediate(2));
1425 :
1426 5 : __ movaps(xmm3, xmm2);
1427 5 : __ subss(xmm3, xmm1);
1428 5 : __ ucomiss(xmm3, xmm0);
1429 5 : __ j(parity_even, &exit);
1430 5 : __ j(not_equal, &exit);
1431 : __ movl(rax, Immediate(3));
1432 :
1433 5 : __ movaps(xmm3, xmm0);
1434 5 : __ addss(xmm3, xmm1);
1435 5 : __ ucomiss(xmm3, xmm2);
1436 5 : __ j(parity_even, &exit);
1437 5 : __ j(not_equal, &exit);
1438 : __ movl(rax, Immediate(4));
1439 :
1440 5 : __ movaps(xmm3, xmm0);
1441 5 : __ mulss(xmm3, xmm1);
1442 5 : __ ucomiss(xmm3, xmm1);
1443 5 : __ j(parity_even, &exit);
1444 5 : __ j(not_equal, &exit);
1445 : __ movl(rax, Immediate(5));
1446 :
1447 5 : __ movaps(xmm3, xmm0);
1448 5 : __ divss(xmm3, xmm1);
1449 5 : __ mulss(xmm3, xmm2);
1450 5 : __ mulss(xmm3, xmm1);
1451 5 : __ ucomiss(xmm3, xmm2);
1452 5 : __ j(parity_even, &exit);
1453 5 : __ j(not_equal, &exit);
1454 : __ movl(rax, Immediate(6));
1455 :
1456 : // result in eax
1457 5 : __ bind(&exit);
1458 5 : __ ret(0);
1459 : }
1460 :
1461 5 : CodeDesc desc;
1462 5 : masm.GetCode(isolate, &desc);
1463 : Handle<Code> code =
1464 10 : isolate->factory()->NewCode(desc, Code::STUB, Handle<Code>());
1465 : #ifdef OBJECT_PRINT
1466 : StdoutStream os;
1467 : code->Print(os);
1468 : #endif
1469 :
1470 : auto f = GeneratedCode<F8>::FromCode(*code);
1471 : int res = f.Call(1.0f, 2.0f, 3.0f);
1472 5 : PrintF("f(1,2,3) = %d\n", res);
1473 5 : CHECK_EQ(6, res);
1474 5 : }
1475 :
1476 :
1477 28342 : TEST(AssemblerX64AVX_ss) {
1478 5 : CcTest::InitializeVM();
1479 5 : if (!CpuFeatures::IsSupported(AVX)) return;
1480 :
1481 5 : Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
1482 : HandleScope scope(isolate);
1483 : v8::internal::byte buffer[1024];
1484 : Assembler masm(AssemblerOptions{},
1485 20 : ExternalAssemblerBuffer(buffer, sizeof(buffer)));
1486 : {
1487 : CpuFeatureScope avx_scope(&masm, AVX);
1488 5 : Label exit;
1489 : // arguments in xmm0, xmm1 and xmm2
1490 5 : __ subq(rsp, Immediate(kDoubleSize * 2)); // For memory operand
1491 :
1492 : __ movl(rdx, Immediate(0xC2F64000)); // -123.125
1493 5 : __ vmovd(xmm4, rdx);
1494 10 : __ vmovss(Operand(rsp, 0), xmm4);
1495 10 : __ vmovss(xmm5, Operand(rsp, 0));
1496 : __ vmovaps(xmm6, xmm5);
1497 5 : __ vmovd(rcx, xmm6);
1498 5 : __ cmpl(rcx, rdx);
1499 : __ movl(rax, Immediate(9));
1500 5 : __ j(not_equal, &exit);
1501 :
1502 : __ movl(rax, Immediate(0));
1503 : __ vmaxss(xmm3, xmm0, xmm1);
1504 5 : __ vucomiss(xmm3, xmm1);
1505 5 : __ j(parity_even, &exit);
1506 5 : __ j(not_equal, &exit);
1507 : __ movl(rax, Immediate(1));
1508 :
1509 : __ vminss(xmm3, xmm1, xmm2);
1510 5 : __ vucomiss(xmm3, xmm1);
1511 5 : __ j(parity_even, &exit);
1512 5 : __ j(not_equal, &exit);
1513 : __ movl(rax, Immediate(2));
1514 :
1515 : __ vsubss(xmm3, xmm2, xmm1);
1516 5 : __ vucomiss(xmm3, xmm0);
1517 5 : __ j(parity_even, &exit);
1518 5 : __ j(not_equal, &exit);
1519 : __ movl(rax, Immediate(3));
1520 :
1521 : __ vaddss(xmm3, xmm0, xmm1);
1522 5 : __ vucomiss(xmm3, xmm2);
1523 5 : __ j(parity_even, &exit);
1524 5 : __ j(not_equal, &exit);
1525 : __ movl(rax, Immediate(4));
1526 :
1527 : __ vmulss(xmm3, xmm0, xmm1);
1528 5 : __ vucomiss(xmm3, xmm1);
1529 5 : __ j(parity_even, &exit);
1530 5 : __ j(not_equal, &exit);
1531 : __ movl(rax, Immediate(5));
1532 :
1533 : __ vdivss(xmm3, xmm0, xmm1);
1534 : __ vmulss(xmm3, xmm3, xmm2);
1535 : __ vmulss(xmm3, xmm3, xmm1);
1536 5 : __ vucomiss(xmm3, xmm2);
1537 5 : __ j(parity_even, &exit);
1538 5 : __ j(not_equal, &exit);
1539 : __ movl(rax, Immediate(6));
1540 :
1541 : // result in eax
1542 5 : __ bind(&exit);
1543 5 : __ addq(rsp, Immediate(kDoubleSize * 2));
1544 5 : __ ret(0);
1545 : }
1546 :
1547 5 : CodeDesc desc;
1548 5 : masm.GetCode(isolate, &desc);
1549 : Handle<Code> code =
1550 10 : isolate->factory()->NewCode(desc, Code::STUB, Handle<Code>());
1551 : #ifdef OBJECT_PRINT
1552 : StdoutStream os;
1553 : code->Print(os);
1554 : #endif
1555 :
1556 : auto f = GeneratedCode<F8>::FromCode(*code);
1557 : int res = f.Call(1.0f, 2.0f, 3.0f);
1558 5 : PrintF("f(1,2,3) = %d\n", res);
1559 5 : CHECK_EQ(6, res);
1560 : }
1561 :
1562 :
1563 28342 : TEST(AssemblerX64AVX_sd) {
1564 5 : CcTest::InitializeVM();
1565 5 : if (!CpuFeatures::IsSupported(AVX)) return;
1566 :
1567 5 : Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
1568 : HandleScope scope(isolate);
1569 : v8::internal::byte buffer[1024];
1570 : Assembler masm(AssemblerOptions{},
1571 20 : ExternalAssemblerBuffer(buffer, sizeof(buffer)));
1572 : {
1573 : CpuFeatureScope avx_scope(&masm, AVX);
1574 5 : Label exit;
1575 : // arguments in xmm0, xmm1 and xmm2
1576 5 : __ subq(rsp, Immediate(kDoubleSize * 2)); // For memory operand
1577 : __ movl(rax, Immediate(0));
1578 :
1579 5 : __ vmaxsd(xmm4, xmm0, xmm1);
1580 5 : __ vmovsd(Operand(rsp, kDoubleSize), xmm4);
1581 5 : __ vmovsd(xmm5, Operand(rsp, kDoubleSize));
1582 5 : __ vmovsd(xmm6, xmm6, xmm5);
1583 : __ vmovapd(xmm3, xmm6);
1584 :
1585 : // Test vcvtss2sd & vcvtsd2ss
1586 : __ movl(rax, Immediate(9));
1587 5 : __ movq(rdx, uint64_t{0x426D1A0000000000});
1588 10 : __ movq(Operand(rsp, 0), rdx);
1589 5 : __ vcvtsd2ss(xmm6, xmm6, Operand(rsp, 0));
1590 : __ vcvtss2sd(xmm7, xmm6, xmm6);
1591 5 : __ vcvtsd2ss(xmm8, xmm7, xmm7);
1592 10 : __ vmovss(Operand(rsp, 0), xmm8);
1593 10 : __ vcvtss2sd(xmm9, xmm8, Operand(rsp, 0));
1594 5 : __ vmovq(rcx, xmm9);
1595 5 : __ cmpq(rcx, rdx);
1596 5 : __ j(not_equal, &exit);
1597 :
1598 : // Test vcvttsd2si
1599 : __ movl(rax, Immediate(10));
1600 : __ movl(rdx, Immediate(123));
1601 : __ vcvtlsi2sd(xmm6, xmm6, rdx);
1602 5 : __ vcvttsd2si(rcx, xmm6);
1603 5 : __ cmpl(rcx, rdx);
1604 5 : __ j(not_equal, &exit);
1605 : __ xorl(rcx, rcx);
1606 5 : __ vmovsd(Operand(rsp, 0), xmm6);
1607 5 : __ vcvttsd2si(rcx, Operand(rsp, 0));
1608 5 : __ cmpl(rcx, rdx);
1609 5 : __ j(not_equal, &exit);
1610 :
1611 : // Test vcvttsd2siq
1612 : __ movl(rax, Immediate(11));
1613 5 : __ movq(rdx, uint64_t{0x426D1A94A2000000}); // 1.0e12
1614 5 : __ vmovq(xmm6, rdx);
1615 5 : __ vcvttsd2siq(rcx, xmm6);
1616 5 : __ movq(rdx, uint64_t{1000000000000});
1617 5 : __ cmpq(rcx, rdx);
1618 5 : __ j(not_equal, &exit);
1619 : __ xorq(rcx, rcx);
1620 5 : __ vmovsd(Operand(rsp, 0), xmm6);
1621 5 : __ vcvttsd2siq(rcx, Operand(rsp, 0));
1622 5 : __ cmpq(rcx, rdx);
1623 5 : __ j(not_equal, &exit);
1624 :
1625 : // Test vmovmskpd
1626 : __ movl(rax, Immediate(12));
1627 5 : __ movq(rdx, uint64_t{0x426D1A94A2000000}); // 1.0e12
1628 5 : __ vmovq(xmm6, rdx);
1629 5 : __ movq(rdx, uint64_t{0xC26D1A94A2000000}); // -1.0e12
1630 5 : __ vmovq(xmm7, rdx);
1631 5 : __ shufps(xmm6, xmm7, 0x44);
1632 : __ vmovmskpd(rdx, xmm6);
1633 5 : __ cmpl(rdx, Immediate(2));
1634 5 : __ j(not_equal, &exit);
1635 :
1636 : // Test vpcmpeqd
1637 5 : __ movq(rdx, uint64_t{0x0123456789ABCDEF});
1638 5 : __ movq(rcx, uint64_t{0x0123456788888888});
1639 5 : __ vmovq(xmm6, rdx);
1640 5 : __ vmovq(xmm7, rcx);
1641 : __ vpcmpeqd(xmm8, xmm6, xmm7);
1642 5 : __ vmovq(rdx, xmm8);
1643 5 : __ movq(rcx, uint64_t{0xFFFFFFFF00000000});
1644 5 : __ cmpq(rcx, rdx);
1645 : __ movl(rax, Immediate(13));
1646 5 : __ j(not_equal, &exit);
1647 :
1648 : // Test vpsllq, vpsrlq
1649 : __ movl(rax, Immediate(13));
1650 5 : __ movq(rdx, uint64_t{0x0123456789ABCDEF});
1651 5 : __ vmovq(xmm6, rdx);
1652 : __ vpsrlq(xmm7, xmm6, 4);
1653 5 : __ vmovq(rdx, xmm7);
1654 5 : __ movq(rcx, uint64_t{0x00123456789ABCDE});
1655 5 : __ cmpq(rdx, rcx);
1656 5 : __ j(not_equal, &exit);
1657 : __ vpsllq(xmm7, xmm6, 12);
1658 5 : __ vmovq(rdx, xmm7);
1659 5 : __ movq(rcx, uint64_t{0x3456789ABCDEF000});
1660 5 : __ cmpq(rdx, rcx);
1661 5 : __ j(not_equal, &exit);
1662 :
1663 : // Test vandpd, vorpd, vxorpd
1664 : __ movl(rax, Immediate(14));
1665 : __ movl(rdx, Immediate(0x00FF00FF));
1666 : __ movl(rcx, Immediate(0x0F0F0F0F));
1667 5 : __ vmovd(xmm4, rdx);
1668 5 : __ vmovd(xmm5, rcx);
1669 : __ vandpd(xmm6, xmm4, xmm5);
1670 5 : __ vmovd(rdx, xmm6);
1671 5 : __ cmpl(rdx, Immediate(0x000F000F));
1672 5 : __ j(not_equal, &exit);
1673 : __ vorpd(xmm6, xmm4, xmm5);
1674 5 : __ vmovd(rdx, xmm6);
1675 5 : __ cmpl(rdx, Immediate(0x0FFF0FFF));
1676 5 : __ j(not_equal, &exit);
1677 : __ vxorpd(xmm6, xmm4, xmm5);
1678 5 : __ vmovd(rdx, xmm6);
1679 5 : __ cmpl(rdx, Immediate(0x0FF00FF0));
1680 5 : __ j(not_equal, &exit);
1681 :
1682 : // Test vsqrtsd
1683 : __ movl(rax, Immediate(15));
1684 5 : __ movq(rdx, uint64_t{0x4004000000000000}); // 2.5
1685 5 : __ vmovq(xmm4, rdx);
1686 5 : __ vmulsd(xmm5, xmm4, xmm4);
1687 5 : __ vmovsd(Operand(rsp, 0), xmm5);
1688 5 : __ vsqrtsd(xmm6, xmm5, xmm5);
1689 5 : __ vmovq(rcx, xmm6);
1690 5 : __ cmpq(rcx, rdx);
1691 5 : __ j(not_equal, &exit);
1692 5 : __ vsqrtsd(xmm7, xmm7, Operand(rsp, 0));
1693 5 : __ vmovq(rcx, xmm7);
1694 5 : __ cmpq(rcx, rdx);
1695 5 : __ j(not_equal, &exit);
1696 :
1697 : // Test vroundsd
1698 : __ movl(rax, Immediate(16));
1699 5 : __ movq(rdx, uint64_t{0x4002000000000000}); // 2.25
1700 5 : __ vmovq(xmm4, rdx);
1701 5 : __ vroundsd(xmm5, xmm4, xmm4, kRoundUp);
1702 5 : __ movq(rcx, uint64_t{0x4008000000000000}); // 3.0
1703 5 : __ vmovq(xmm6, rcx);
1704 : __ vucomisd(xmm5, xmm6);
1705 5 : __ j(not_equal, &exit);
1706 :
1707 : // Test vcvtlsi2sd
1708 : __ movl(rax, Immediate(17));
1709 : __ movl(rdx, Immediate(6));
1710 5 : __ movq(rcx, uint64_t{0x4018000000000000}); // 6.0
1711 5 : __ vmovq(xmm5, rcx);
1712 : __ vcvtlsi2sd(xmm6, xmm6, rdx);
1713 : __ vucomisd(xmm5, xmm6);
1714 5 : __ j(not_equal, &exit);
1715 10 : __ movl(Operand(rsp, 0), rdx);
1716 10 : __ vcvtlsi2sd(xmm7, xmm7, Operand(rsp, 0));
1717 : __ vucomisd(xmm5, xmm6);
1718 5 : __ j(not_equal, &exit);
1719 :
1720 : // Test vcvtqsi2sd
1721 : __ movl(rax, Immediate(18));
1722 5 : __ movq(rdx, uint64_t{0x2000000000000000}); // 2 << 0x3C
1723 5 : __ movq(rcx, uint64_t{0x43C0000000000000});
1724 5 : __ vmovq(xmm5, rcx);
1725 : __ vcvtqsi2sd(xmm6, xmm6, rdx);
1726 : __ vucomisd(xmm5, xmm6);
1727 5 : __ j(not_equal, &exit);
1728 :
1729 : // Test vcvtsd2si
1730 : __ movl(rax, Immediate(19));
1731 5 : __ movq(rdx, uint64_t{0x4018000000000000}); // 6.0
1732 5 : __ vmovq(xmm5, rdx);
1733 5 : __ vcvtsd2si(rcx, xmm5);
1734 5 : __ cmpl(rcx, Immediate(6));
1735 5 : __ j(not_equal, &exit);
1736 :
1737 5 : __ movq(rdx, uint64_t{0x3FF0000000000000}); // 1.0
1738 5 : __ vmovq(xmm7, rdx);
1739 5 : __ vmulsd(xmm1, xmm1, xmm7);
1740 10 : __ movq(Operand(rsp, 0), rdx);
1741 5 : __ vmovq(xmm6, Operand(rsp, 0));
1742 5 : __ vmulsd(xmm1, xmm1, xmm6);
1743 :
1744 : __ vucomisd(xmm3, xmm1);
1745 5 : __ j(parity_even, &exit);
1746 5 : __ j(not_equal, &exit);
1747 : __ movl(rax, Immediate(1));
1748 :
1749 5 : __ vminsd(xmm3, xmm1, xmm2);
1750 : __ vucomisd(xmm3, xmm1);
1751 5 : __ j(parity_even, &exit);
1752 5 : __ j(not_equal, &exit);
1753 : __ movl(rax, Immediate(2));
1754 :
1755 5 : __ vsubsd(xmm3, xmm2, xmm1);
1756 : __ vucomisd(xmm3, xmm0);
1757 5 : __ j(parity_even, &exit);
1758 5 : __ j(not_equal, &exit);
1759 : __ movl(rax, Immediate(3));
1760 :
1761 5 : __ vaddsd(xmm3, xmm0, xmm1);
1762 : __ vucomisd(xmm3, xmm2);
1763 5 : __ j(parity_even, &exit);
1764 5 : __ j(not_equal, &exit);
1765 : __ movl(rax, Immediate(4));
1766 :
1767 5 : __ vmulsd(xmm3, xmm0, xmm1);
1768 : __ vucomisd(xmm3, xmm1);
1769 5 : __ j(parity_even, &exit);
1770 5 : __ j(not_equal, &exit);
1771 : __ movl(rax, Immediate(5));
1772 :
1773 5 : __ vdivsd(xmm3, xmm0, xmm1);
1774 5 : __ vmulsd(xmm3, xmm3, xmm2);
1775 5 : __ vmulsd(xmm3, xmm3, xmm1);
1776 : __ vucomisd(xmm3, xmm2);
1777 5 : __ j(parity_even, &exit);
1778 5 : __ j(not_equal, &exit);
1779 : __ movl(rax, Immediate(6));
1780 :
1781 : // result in eax
1782 5 : __ bind(&exit);
1783 5 : __ addq(rsp, Immediate(kDoubleSize * 2));
1784 5 : __ ret(0);
1785 : }
1786 :
1787 5 : CodeDesc desc;
1788 5 : masm.GetCode(isolate, &desc);
1789 : Handle<Code> code =
1790 10 : isolate->factory()->NewCode(desc, Code::STUB, Handle<Code>());
1791 : #ifdef OBJECT_PRINT
1792 : StdoutStream os;
1793 : code->Print(os);
1794 : #endif
1795 :
1796 : auto f = GeneratedCode<F7>::FromCode(*code);
1797 : int res = f.Call(1.0, 2.0, 3.0);
1798 5 : PrintF("f(1,2,3) = %d\n", res);
1799 5 : CHECK_EQ(6, res);
1800 : }
1801 :
1802 :
1803 28342 : TEST(AssemblerX64BMI1) {
1804 5 : CcTest::InitializeVM();
1805 5 : if (!CpuFeatures::IsSupported(BMI1)) return;
1806 :
1807 5 : Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
1808 : HandleScope scope(isolate);
1809 : v8::internal::byte buffer[1024];
1810 : MacroAssembler masm(isolate, v8::internal::CodeObjectRequired::kYes,
1811 15 : ExternalAssemblerBuffer(buffer, sizeof(buffer)));
1812 : {
1813 : CpuFeatureScope fscope(&masm, BMI1);
1814 5 : Label exit;
1815 :
1816 5 : __ movq(rcx, uint64_t{0x1122334455667788}); // source operand
1817 5 : __ pushq(rcx); // For memory operand
1818 :
1819 : // andn
1820 5 : __ movq(rdx, uint64_t{0x1000000020000000});
1821 :
1822 : __ movl(rax, Immediate(1)); // Test number
1823 : __ andnq(r8, rdx, rcx);
1824 5 : __ movq(r9, uint64_t{0x0122334455667788}); // expected result
1825 5 : __ cmpq(r8, r9);
1826 5 : __ j(not_equal, &exit);
1827 :
1828 : __ incq(rax);
1829 10 : __ andnq(r8, rdx, Operand(rsp, 0));
1830 5 : __ movq(r9, uint64_t{0x0122334455667788}); // expected result
1831 5 : __ cmpq(r8, r9);
1832 5 : __ j(not_equal, &exit);
1833 :
1834 : __ incq(rax);
1835 : __ andnl(r8, rdx, rcx);
1836 5 : __ movq(r9, uint64_t{0x0000000055667788}); // expected result
1837 5 : __ cmpq(r8, r9);
1838 5 : __ j(not_equal, &exit);
1839 :
1840 : __ incq(rax);
1841 10 : __ andnl(r8, rdx, Operand(rsp, 0));
1842 5 : __ movq(r9, uint64_t{0x0000000055667788}); // expected result
1843 5 : __ cmpq(r8, r9);
1844 5 : __ j(not_equal, &exit);
1845 :
1846 : // bextr
1847 5 : __ movq(rdx, uint64_t{0x0000000000002808});
1848 :
1849 : __ incq(rax);
1850 : __ bextrq(r8, rcx, rdx);
1851 5 : __ movq(r9, uint64_t{0x0000003344556677}); // expected result
1852 5 : __ cmpq(r8, r9);
1853 5 : __ j(not_equal, &exit);
1854 :
1855 : __ incq(rax);
1856 10 : __ bextrq(r8, Operand(rsp, 0), rdx);
1857 5 : __ movq(r9, uint64_t{0x0000003344556677}); // expected result
1858 5 : __ cmpq(r8, r9);
1859 5 : __ j(not_equal, &exit);
1860 :
1861 : __ incq(rax);
1862 : __ bextrl(r8, rcx, rdx);
1863 5 : __ movq(r9, uint64_t{0x0000000000556677}); // expected result
1864 5 : __ cmpq(r8, r9);
1865 5 : __ j(not_equal, &exit);
1866 :
1867 : __ incq(rax);
1868 10 : __ bextrl(r8, Operand(rsp, 0), rdx);
1869 5 : __ movq(r9, uint64_t{0x0000000000556677}); // expected result
1870 5 : __ cmpq(r8, r9);
1871 5 : __ j(not_equal, &exit);
1872 :
1873 : // blsi
1874 : __ incq(rax);
1875 : __ blsiq(r8, rcx);
1876 5 : __ movq(r9, uint64_t{0x0000000000000008}); // expected result
1877 5 : __ cmpq(r8, r9);
1878 5 : __ j(not_equal, &exit);
1879 :
1880 : __ incq(rax);
1881 10 : __ blsiq(r8, Operand(rsp, 0));
1882 5 : __ movq(r9, uint64_t{0x0000000000000008}); // expected result
1883 5 : __ cmpq(r8, r9);
1884 5 : __ j(not_equal, &exit);
1885 :
1886 : __ incq(rax);
1887 : __ blsil(r8, rcx);
1888 5 : __ movq(r9, uint64_t{0x0000000000000008}); // expected result
1889 5 : __ cmpq(r8, r9);
1890 5 : __ j(not_equal, &exit);
1891 :
1892 : __ incq(rax);
1893 10 : __ blsil(r8, Operand(rsp, 0));
1894 5 : __ movq(r9, uint64_t{0x0000000000000008}); // expected result
1895 5 : __ cmpq(r8, r9);
1896 5 : __ j(not_equal, &exit);
1897 :
1898 : // blsmsk
1899 : __ incq(rax);
1900 : __ blsmskq(r8, rcx);
1901 5 : __ movq(r9, uint64_t{0x000000000000000F}); // expected result
1902 5 : __ cmpq(r8, r9);
1903 5 : __ j(not_equal, &exit);
1904 :
1905 : __ incq(rax);
1906 10 : __ blsmskq(r8, Operand(rsp, 0));
1907 5 : __ movq(r9, uint64_t{0x000000000000000F}); // expected result
1908 5 : __ cmpq(r8, r9);
1909 5 : __ j(not_equal, &exit);
1910 :
1911 : __ incq(rax);
1912 : __ blsmskl(r8, rcx);
1913 5 : __ movq(r9, uint64_t{0x000000000000000F}); // expected result
1914 5 : __ cmpq(r8, r9);
1915 5 : __ j(not_equal, &exit);
1916 :
1917 : __ incq(rax);
1918 10 : __ blsmskl(r8, Operand(rsp, 0));
1919 5 : __ movq(r9, uint64_t{0x000000000000000F}); // expected result
1920 5 : __ cmpq(r8, r9);
1921 5 : __ j(not_equal, &exit);
1922 :
1923 : // blsr
1924 : __ incq(rax);
1925 : __ blsrq(r8, rcx);
1926 5 : __ movq(r9, uint64_t{0x1122334455667780}); // expected result
1927 5 : __ cmpq(r8, r9);
1928 5 : __ j(not_equal, &exit);
1929 :
1930 : __ incq(rax);
1931 10 : __ blsrq(r8, Operand(rsp, 0));
1932 5 : __ movq(r9, uint64_t{0x1122334455667780}); // expected result
1933 5 : __ cmpq(r8, r9);
1934 5 : __ j(not_equal, &exit);
1935 :
1936 : __ incq(rax);
1937 : __ blsrl(r8, rcx);
1938 5 : __ movq(r9, uint64_t{0x0000000055667780}); // expected result
1939 5 : __ cmpq(r8, r9);
1940 5 : __ j(not_equal, &exit);
1941 :
1942 : __ incq(rax);
1943 10 : __ blsrl(r8, Operand(rsp, 0));
1944 5 : __ movq(r9, uint64_t{0x0000000055667780}); // expected result
1945 5 : __ cmpq(r8, r9);
1946 5 : __ j(not_equal, &exit);
1947 :
1948 : // tzcnt
1949 : __ incq(rax);
1950 5 : __ tzcntq(r8, rcx);
1951 5 : __ movq(r9, uint64_t{0x0000000000000003}); // expected result
1952 5 : __ cmpq(r8, r9);
1953 5 : __ j(not_equal, &exit);
1954 :
1955 : __ incq(rax);
1956 5 : __ tzcntq(r8, Operand(rsp, 0));
1957 5 : __ movq(r9, uint64_t{0x0000000000000003}); // expected result
1958 5 : __ cmpq(r8, r9);
1959 5 : __ j(not_equal, &exit);
1960 :
1961 : __ incq(rax);
1962 5 : __ tzcntl(r8, rcx);
1963 5 : __ movq(r9, uint64_t{0x0000000000000003}); // expected result
1964 5 : __ cmpq(r8, r9);
1965 5 : __ j(not_equal, &exit);
1966 :
1967 : __ incq(rax);
1968 5 : __ tzcntl(r8, Operand(rsp, 0));
1969 5 : __ movq(r9, uint64_t{0x0000000000000003}); // expected result
1970 5 : __ cmpq(r8, r9);
1971 5 : __ j(not_equal, &exit);
1972 :
1973 : __ xorl(rax, rax);
1974 5 : __ bind(&exit);
1975 5 : __ popq(rcx);
1976 5 : __ ret(0);
1977 : }
1978 :
1979 5 : CodeDesc desc;
1980 5 : masm.GetCode(isolate, &desc);
1981 : Handle<Code> code =
1982 10 : isolate->factory()->NewCode(desc, Code::STUB, Handle<Code>());
1983 : #ifdef OBJECT_PRINT
1984 : StdoutStream os;
1985 : code->Print(os);
1986 : #endif
1987 :
1988 : auto f = GeneratedCode<F0>::FromCode(*code);
1989 5 : CHECK_EQ(0, f.Call());
1990 : }
1991 :
1992 :
1993 28342 : TEST(AssemblerX64LZCNT) {
1994 5 : CcTest::InitializeVM();
1995 5 : if (!CpuFeatures::IsSupported(LZCNT)) return;
1996 :
1997 5 : Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
1998 : HandleScope scope(isolate);
1999 : v8::internal::byte buffer[256];
2000 : MacroAssembler masm(isolate, v8::internal::CodeObjectRequired::kYes,
2001 15 : ExternalAssemblerBuffer(buffer, sizeof(buffer)));
2002 : {
2003 : CpuFeatureScope fscope(&masm, LZCNT);
2004 5 : Label exit;
2005 :
2006 5 : __ movq(rcx, uint64_t{0x1122334455667788}); // source operand
2007 5 : __ pushq(rcx); // For memory operand
2008 :
2009 : __ movl(rax, Immediate(1)); // Test number
2010 5 : __ lzcntq(r8, rcx);
2011 5 : __ movq(r9, uint64_t{0x0000000000000003}); // expected result
2012 5 : __ cmpq(r8, r9);
2013 5 : __ j(not_equal, &exit);
2014 :
2015 : __ incq(rax);
2016 5 : __ lzcntq(r8, Operand(rsp, 0));
2017 5 : __ movq(r9, uint64_t{0x0000000000000003}); // expected result
2018 5 : __ cmpq(r8, r9);
2019 5 : __ j(not_equal, &exit);
2020 :
2021 : __ incq(rax);
2022 5 : __ lzcntl(r8, rcx);
2023 5 : __ movq(r9, uint64_t{0x0000000000000001}); // expected result
2024 5 : __ cmpq(r8, r9);
2025 5 : __ j(not_equal, &exit);
2026 :
2027 : __ incq(rax);
2028 5 : __ lzcntl(r8, Operand(rsp, 0));
2029 5 : __ movq(r9, uint64_t{0x0000000000000001}); // expected result
2030 5 : __ cmpq(r8, r9);
2031 5 : __ j(not_equal, &exit);
2032 :
2033 : __ xorl(rax, rax);
2034 5 : __ bind(&exit);
2035 5 : __ popq(rcx);
2036 5 : __ ret(0);
2037 : }
2038 :
2039 5 : CodeDesc desc;
2040 5 : masm.GetCode(isolate, &desc);
2041 : Handle<Code> code =
2042 10 : isolate->factory()->NewCode(desc, Code::STUB, Handle<Code>());
2043 : #ifdef OBJECT_PRINT
2044 : StdoutStream os;
2045 : code->Print(os);
2046 : #endif
2047 :
2048 : auto f = GeneratedCode<F0>::FromCode(*code);
2049 5 : CHECK_EQ(0, f.Call());
2050 : }
2051 :
2052 :
2053 28342 : TEST(AssemblerX64POPCNT) {
2054 5 : CcTest::InitializeVM();
2055 5 : if (!CpuFeatures::IsSupported(POPCNT)) return;
2056 :
2057 5 : Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
2058 : HandleScope scope(isolate);
2059 : v8::internal::byte buffer[256];
2060 : MacroAssembler masm(isolate, v8::internal::CodeObjectRequired::kYes,
2061 15 : ExternalAssemblerBuffer(buffer, sizeof(buffer)));
2062 : {
2063 : CpuFeatureScope fscope(&masm, POPCNT);
2064 5 : Label exit;
2065 :
2066 5 : __ movq(rcx, uint64_t{0x1111111111111100}); // source operand
2067 5 : __ pushq(rcx); // For memory operand
2068 :
2069 : __ movl(rax, Immediate(1)); // Test number
2070 5 : __ popcntq(r8, rcx);
2071 5 : __ movq(r9, uint64_t{0x000000000000000E}); // expected result
2072 5 : __ cmpq(r8, r9);
2073 5 : __ j(not_equal, &exit);
2074 :
2075 : __ incq(rax);
2076 5 : __ popcntq(r8, Operand(rsp, 0));
2077 5 : __ movq(r9, uint64_t{0x000000000000000E}); // expected result
2078 5 : __ cmpq(r8, r9);
2079 5 : __ j(not_equal, &exit);
2080 :
2081 : __ incq(rax);
2082 5 : __ popcntl(r8, rcx);
2083 5 : __ movq(r9, uint64_t{0x0000000000000006}); // expected result
2084 5 : __ cmpq(r8, r9);
2085 5 : __ j(not_equal, &exit);
2086 :
2087 : __ incq(rax);
2088 5 : __ popcntl(r8, Operand(rsp, 0));
2089 5 : __ movq(r9, uint64_t{0x0000000000000006}); // expected result
2090 5 : __ cmpq(r8, r9);
2091 5 : __ j(not_equal, &exit);
2092 :
2093 : __ xorl(rax, rax);
2094 5 : __ bind(&exit);
2095 5 : __ popq(rcx);
2096 5 : __ ret(0);
2097 : }
2098 :
2099 5 : CodeDesc desc;
2100 5 : masm.GetCode(isolate, &desc);
2101 : Handle<Code> code =
2102 10 : isolate->factory()->NewCode(desc, Code::STUB, Handle<Code>());
2103 : #ifdef OBJECT_PRINT
2104 : StdoutStream os;
2105 : code->Print(os);
2106 : #endif
2107 :
2108 : auto f = GeneratedCode<F0>::FromCode(*code);
2109 5 : CHECK_EQ(0, f.Call());
2110 : }
2111 :
2112 :
2113 28342 : TEST(AssemblerX64BMI2) {
2114 5 : CcTest::InitializeVM();
2115 5 : if (!CpuFeatures::IsSupported(BMI2)) return;
2116 :
2117 5 : Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
2118 : HandleScope scope(isolate);
2119 : v8::internal::byte buffer[2048];
2120 : MacroAssembler masm(isolate, v8::internal::CodeObjectRequired::kYes,
2121 15 : ExternalAssemblerBuffer(buffer, sizeof(buffer)));
2122 : {
2123 : CpuFeatureScope fscope(&masm, BMI2);
2124 5 : Label exit;
2125 5 : __ pushq(rbx); // save rbx
2126 5 : __ movq(rcx, uint64_t{0x1122334455667788}); // source operand
2127 5 : __ pushq(rcx); // For memory operand
2128 :
2129 : // bzhi
2130 5 : __ movq(rdx, uint64_t{0x0000000000000009});
2131 :
2132 : __ movl(rax, Immediate(1)); // Test number
2133 : __ bzhiq(r8, rcx, rdx);
2134 5 : __ movq(r9, uint64_t{0x0000000000000188}); // expected result
2135 5 : __ cmpq(r8, r9);
2136 5 : __ j(not_equal, &exit);
2137 :
2138 : __ incq(rax);
2139 10 : __ bzhiq(r8, Operand(rsp, 0), rdx);
2140 5 : __ movq(r9, uint64_t{0x0000000000000188}); // expected result
2141 5 : __ cmpq(r8, r9);
2142 5 : __ j(not_equal, &exit);
2143 :
2144 : __ incq(rax);
2145 : __ bzhil(r8, rcx, rdx);
2146 5 : __ movq(r9, uint64_t{0x0000000000000188}); // expected result
2147 5 : __ cmpq(r8, r9);
2148 5 : __ j(not_equal, &exit);
2149 :
2150 : __ incq(rax);
2151 10 : __ bzhil(r8, Operand(rsp, 0), rdx);
2152 5 : __ movq(r9, uint64_t{0x0000000000000188}); // expected result
2153 5 : __ cmpq(r8, r9);
2154 5 : __ j(not_equal, &exit);
2155 :
2156 : // mulx
2157 5 : __ movq(rdx, uint64_t{0x0000000000001000});
2158 :
2159 : __ incq(rax);
2160 : __ mulxq(r8, r9, rcx);
2161 5 : __ movq(rbx, uint64_t{0x0000000000000112}); // expected result
2162 5 : __ cmpq(r8, rbx);
2163 5 : __ j(not_equal, &exit);
2164 5 : __ movq(rbx, uint64_t{0x2334455667788000}); // expected result
2165 5 : __ cmpq(r9, rbx);
2166 5 : __ j(not_equal, &exit);
2167 :
2168 : __ incq(rax);
2169 10 : __ mulxq(r8, r9, Operand(rsp, 0));
2170 5 : __ movq(rbx, uint64_t{0x0000000000000112}); // expected result
2171 5 : __ cmpq(r8, rbx);
2172 5 : __ j(not_equal, &exit);
2173 5 : __ movq(rbx, uint64_t{0x2334455667788000}); // expected result
2174 5 : __ cmpq(r9, rbx);
2175 5 : __ j(not_equal, &exit);
2176 :
2177 : __ incq(rax);
2178 : __ mulxl(r8, r9, rcx);
2179 5 : __ movq(rbx, uint64_t{0x0000000000000556}); // expected result
2180 5 : __ cmpq(r8, rbx);
2181 5 : __ j(not_equal, &exit);
2182 5 : __ movq(rbx, uint64_t{0x0000000067788000}); // expected result
2183 5 : __ cmpq(r9, rbx);
2184 5 : __ j(not_equal, &exit);
2185 :
2186 : __ incq(rax);
2187 10 : __ mulxl(r8, r9, Operand(rsp, 0));
2188 5 : __ movq(rbx, uint64_t{0x0000000000000556}); // expected result
2189 5 : __ cmpq(r8, rbx);
2190 5 : __ j(not_equal, &exit);
2191 5 : __ movq(rbx, uint64_t{0x0000000067788000}); // expected result
2192 5 : __ cmpq(r9, rbx);
2193 5 : __ j(not_equal, &exit);
2194 :
2195 : // pdep
2196 5 : __ movq(rdx, uint64_t{0xFFFFFFFFFFFFFFF0});
2197 :
2198 : __ incq(rax);
2199 : __ pdepq(r8, rdx, rcx);
2200 5 : __ movq(r9, uint64_t{0x1122334455667400}); // expected result
2201 5 : __ cmpq(r8, r9);
2202 5 : __ j(not_equal, &exit);
2203 :
2204 : __ incq(rax);
2205 10 : __ pdepq(r8, rdx, Operand(rsp, 0));
2206 5 : __ movq(r9, uint64_t{0x1122334455667400}); // expected result
2207 5 : __ cmpq(r8, r9);
2208 5 : __ j(not_equal, &exit);
2209 :
2210 : __ incq(rax);
2211 : __ pdepl(r8, rdx, rcx);
2212 5 : __ movq(r9, uint64_t{0x0000000055667400}); // expected result
2213 5 : __ cmpq(r8, r9);
2214 5 : __ j(not_equal, &exit);
2215 :
2216 : __ incq(rax);
2217 10 : __ pdepl(r8, rdx, Operand(rsp, 0));
2218 5 : __ movq(r9, uint64_t{0x0000000055667400}); // expected result
2219 5 : __ cmpq(r8, r9);
2220 5 : __ j(not_equal, &exit);
2221 :
2222 : // pext
2223 5 : __ movq(rdx, uint64_t{0xFFFFFFFFFFFFFFF0});
2224 :
2225 : __ incq(rax);
2226 : __ pextq(r8, rdx, rcx);
2227 5 : __ movq(r9, uint64_t{0x0000000003FFFFFE}); // expected result
2228 5 : __ cmpq(r8, r9);
2229 5 : __ j(not_equal, &exit);
2230 :
2231 : __ incq(rax);
2232 10 : __ pextq(r8, rdx, Operand(rsp, 0));
2233 5 : __ movq(r9, uint64_t{0x0000000003FFFFFE}); // expected result
2234 5 : __ cmpq(r8, r9);
2235 5 : __ j(not_equal, &exit);
2236 :
2237 : __ incq(rax);
2238 : __ pextl(r8, rdx, rcx);
2239 5 : __ movq(r9, uint64_t{0x000000000000FFFE}); // expected result
2240 5 : __ cmpq(r8, r9);
2241 5 : __ j(not_equal, &exit);
2242 :
2243 : __ incq(rax);
2244 10 : __ pextl(r8, rdx, Operand(rsp, 0));
2245 5 : __ movq(r9, uint64_t{0x000000000000FFFE}); // expected result
2246 5 : __ cmpq(r8, r9);
2247 5 : __ j(not_equal, &exit);
2248 :
2249 : // sarx
2250 5 : __ movq(rdx, uint64_t{0x0000000000000004});
2251 :
2252 : __ incq(rax);
2253 : __ sarxq(r8, rcx, rdx);
2254 5 : __ movq(r9, uint64_t{0x0112233445566778}); // expected result
2255 5 : __ cmpq(r8, r9);
2256 5 : __ j(not_equal, &exit);
2257 :
2258 : __ incq(rax);
2259 10 : __ sarxq(r8, Operand(rsp, 0), rdx);
2260 5 : __ movq(r9, uint64_t{0x0112233445566778}); // expected result
2261 5 : __ cmpq(r8, r9);
2262 5 : __ j(not_equal, &exit);
2263 :
2264 : __ incq(rax);
2265 : __ sarxl(r8, rcx, rdx);
2266 5 : __ movq(r9, uint64_t{0x0000000005566778}); // expected result
2267 5 : __ cmpq(r8, r9);
2268 5 : __ j(not_equal, &exit);
2269 :
2270 : __ incq(rax);
2271 10 : __ sarxl(r8, Operand(rsp, 0), rdx);
2272 5 : __ movq(r9, uint64_t{0x0000000005566778}); // expected result
2273 5 : __ cmpq(r8, r9);
2274 5 : __ j(not_equal, &exit);
2275 :
2276 : // shlx
2277 5 : __ movq(rdx, uint64_t{0x0000000000000004});
2278 :
2279 : __ incq(rax);
2280 : __ shlxq(r8, rcx, rdx);
2281 5 : __ movq(r9, uint64_t{0x1223344556677880}); // expected result
2282 5 : __ cmpq(r8, r9);
2283 5 : __ j(not_equal, &exit);
2284 :
2285 : __ incq(rax);
2286 10 : __ shlxq(r8, Operand(rsp, 0), rdx);
2287 5 : __ movq(r9, uint64_t{0x1223344556677880}); // expected result
2288 5 : __ cmpq(r8, r9);
2289 5 : __ j(not_equal, &exit);
2290 :
2291 : __ incq(rax);
2292 : __ shlxl(r8, rcx, rdx);
2293 5 : __ movq(r9, uint64_t{0x0000000056677880}); // expected result
2294 5 : __ cmpq(r8, r9);
2295 5 : __ j(not_equal, &exit);
2296 :
2297 : __ incq(rax);
2298 10 : __ shlxl(r8, Operand(rsp, 0), rdx);
2299 5 : __ movq(r9, uint64_t{0x0000000056677880}); // expected result
2300 5 : __ cmpq(r8, r9);
2301 5 : __ j(not_equal, &exit);
2302 :
2303 : // shrx
2304 5 : __ movq(rdx, uint64_t{0x0000000000000004});
2305 :
2306 : __ incq(rax);
2307 : __ shrxq(r8, rcx, rdx);
2308 5 : __ movq(r9, uint64_t{0x0112233445566778}); // expected result
2309 5 : __ cmpq(r8, r9);
2310 5 : __ j(not_equal, &exit);
2311 :
2312 : __ incq(rax);
2313 10 : __ shrxq(r8, Operand(rsp, 0), rdx);
2314 5 : __ movq(r9, uint64_t{0x0112233445566778}); // expected result
2315 5 : __ cmpq(r8, r9);
2316 5 : __ j(not_equal, &exit);
2317 :
2318 : __ incq(rax);
2319 : __ shrxl(r8, rcx, rdx);
2320 5 : __ movq(r9, uint64_t{0x0000000005566778}); // expected result
2321 5 : __ cmpq(r8, r9);
2322 5 : __ j(not_equal, &exit);
2323 :
2324 : __ incq(rax);
2325 10 : __ shrxl(r8, Operand(rsp, 0), rdx);
2326 5 : __ movq(r9, uint64_t{0x0000000005566778}); // expected result
2327 5 : __ cmpq(r8, r9);
2328 5 : __ j(not_equal, &exit);
2329 :
2330 : // rorx
2331 : __ incq(rax);
2332 5 : __ rorxq(r8, rcx, 0x4);
2333 5 : __ movq(r9, uint64_t{0x8112233445566778}); // expected result
2334 5 : __ cmpq(r8, r9);
2335 5 : __ j(not_equal, &exit);
2336 :
2337 : __ incq(rax);
2338 5 : __ rorxq(r8, Operand(rsp, 0), 0x4);
2339 5 : __ movq(r9, uint64_t{0x8112233445566778}); // expected result
2340 5 : __ cmpq(r8, r9);
2341 5 : __ j(not_equal, &exit);
2342 :
2343 : __ incq(rax);
2344 5 : __ rorxl(r8, rcx, 0x4);
2345 5 : __ movq(r9, uint64_t{0x0000000085566778}); // expected result
2346 5 : __ cmpq(r8, r9);
2347 5 : __ j(not_equal, &exit);
2348 :
2349 : __ incq(rax);
2350 5 : __ rorxl(r8, Operand(rsp, 0), 0x4);
2351 5 : __ movq(r9, uint64_t{0x0000000085566778}); // expected result
2352 5 : __ cmpq(r8, r9);
2353 5 : __ j(not_equal, &exit);
2354 :
2355 : __ xorl(rax, rax);
2356 5 : __ bind(&exit);
2357 5 : __ popq(rcx);
2358 5 : __ popq(rbx);
2359 5 : __ ret(0);
2360 : }
2361 :
2362 5 : CodeDesc desc;
2363 5 : masm.GetCode(isolate, &desc);
2364 : Handle<Code> code =
2365 10 : isolate->factory()->NewCode(desc, Code::STUB, Handle<Code>());
2366 : #ifdef OBJECT_PRINT
2367 : StdoutStream os;
2368 : code->Print(os);
2369 : #endif
2370 :
2371 : auto f = GeneratedCode<F0>::FromCode(*code);
2372 5 : CHECK_EQ(0, f.Call());
2373 : }
2374 :
2375 :
2376 28342 : TEST(AssemblerX64JumpTables1) {
2377 : // Test jump tables with forward jumps.
2378 5 : CcTest::InitializeVM();
2379 5 : Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
2380 : HandleScope scope(isolate);
2381 10 : MacroAssembler masm(isolate, v8::internal::CodeObjectRequired::kYes);
2382 :
2383 : const int kNumCases = 512;
2384 : int values[kNumCases];
2385 5 : isolate->random_number_generator()->NextBytes(values, sizeof(values));
2386 2565 : Label labels[kNumCases];
2387 :
2388 5 : Label done, table;
2389 10 : __ leaq(arg2, Operand(&table));
2390 5 : __ jmp(Operand(arg2, arg1, times_8, 0));
2391 5 : __ ud2();
2392 5 : __ bind(&table);
2393 2565 : for (int i = 0; i < kNumCases; ++i) {
2394 2560 : __ dq(&labels[i]);
2395 : }
2396 :
2397 2560 : for (int i = 0; i < kNumCases; ++i) {
2398 2560 : __ bind(&labels[i]);
2399 2560 : __ movq(rax, Immediate(values[i]));
2400 2560 : __ jmp(&done);
2401 : }
2402 :
2403 5 : __ bind(&done);
2404 5 : __ ret(0);
2405 :
2406 5 : CodeDesc desc;
2407 5 : masm.GetCode(isolate, &desc);
2408 : Handle<Code> code =
2409 10 : isolate->factory()->NewCode(desc, Code::STUB, Handle<Code>());
2410 : #ifdef OBJECT_PRINT
2411 : code->Print(std::cout);
2412 : #endif
2413 :
2414 : auto f = GeneratedCode<F1>::FromCode(*code);
2415 2565 : for (int i = 0; i < kNumCases; ++i) {
2416 2560 : int res = f.Call(i);
2417 2560 : PrintF("f(%d) = %d\n", i, res);
2418 2560 : CHECK_EQ(values[i], res);
2419 : }
2420 5 : }
2421 :
2422 :
2423 28342 : TEST(AssemblerX64JumpTables2) {
2424 : // Test jump tables with backwards jumps.
2425 5 : CcTest::InitializeVM();
2426 5 : Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
2427 : HandleScope scope(isolate);
2428 10 : MacroAssembler masm(isolate, v8::internal::CodeObjectRequired::kYes);
2429 :
2430 : const int kNumCases = 512;
2431 : int values[kNumCases];
2432 5 : isolate->random_number_generator()->NextBytes(values, sizeof(values));
2433 2565 : Label labels[kNumCases];
2434 :
2435 5 : Label done, table;
2436 10 : __ leaq(arg2, Operand(&table));
2437 5 : __ jmp(Operand(arg2, arg1, times_8, 0));
2438 5 : __ ud2();
2439 :
2440 2565 : for (int i = 0; i < kNumCases; ++i) {
2441 2560 : __ bind(&labels[i]);
2442 2560 : __ movq(rax, Immediate(values[i]));
2443 2560 : __ jmp(&done);
2444 : }
2445 :
2446 5 : __ bind(&done);
2447 5 : __ ret(0);
2448 :
2449 5 : __ bind(&table);
2450 2565 : for (int i = 0; i < kNumCases; ++i) {
2451 2560 : __ dq(&labels[i]);
2452 : }
2453 :
2454 5 : CodeDesc desc;
2455 5 : masm.GetCode(isolate, &desc);
2456 : Handle<Code> code =
2457 10 : isolate->factory()->NewCode(desc, Code::STUB, Handle<Code>());
2458 : #ifdef OBJECT_PRINT
2459 : code->Print(std::cout);
2460 : #endif
2461 :
2462 : auto f = GeneratedCode<F1>::FromCode(*code);
2463 2565 : for (int i = 0; i < kNumCases; ++i) {
2464 2560 : int res = f.Call(i);
2465 2560 : PrintF("f(%d) = %d\n", i, res);
2466 2560 : CHECK_EQ(values[i], res);
2467 : }
2468 5 : }
2469 :
2470 28342 : TEST(AssemblerX64PslldWithXmm15) {
2471 5 : CcTest::InitializeVM();
2472 : auto buffer = AllocateAssemblerBuffer();
2473 25 : Assembler masm(AssemblerOptions{}, buffer->CreateView());
2474 :
2475 5 : __ movq(xmm15, arg1);
2476 5 : __ pslld(xmm15, 1);
2477 5 : __ movq(rax, xmm15);
2478 5 : __ ret(0);
2479 :
2480 5 : CodeDesc desc;
2481 5 : masm.GetCode(CcTest::i_isolate(), &desc);
2482 5 : buffer->MakeExecutable();
2483 5 : auto f = GeneratedCode<F5>::FromBuffer(CcTest::i_isolate(), buffer->start());
2484 : uint64_t result = f.Call(uint64_t{0x1122334455667788});
2485 5 : CHECK_EQ(uint64_t{0x22446688AACCEF10}, result);
2486 5 : }
2487 :
2488 : typedef float(F9)(float x, float y);
2489 28342 : TEST(AssemblerX64vmovups) {
2490 5 : CcTest::InitializeVM();
2491 5 : if (!CpuFeatures::IsSupported(AVX)) return;
2492 :
2493 5 : Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
2494 : HandleScope scope(isolate);
2495 : v8::internal::byte buffer[256];
2496 : MacroAssembler masm(isolate, v8::internal::CodeObjectRequired::kYes,
2497 15 : ExternalAssemblerBuffer(buffer, sizeof(buffer)));
2498 : {
2499 : CpuFeatureScope avx_scope(&masm, AVX);
2500 5 : __ shufps(xmm0, xmm0, 0x0); // brocast first argument
2501 5 : __ shufps(xmm1, xmm1, 0x0); // brocast second argument
2502 : // copy xmm1 to xmm0 through the stack to test the "vmovups reg, mem".
2503 5 : __ subq(rsp, Immediate(kSimd128Size));
2504 10 : __ vmovups(Operand(rsp, 0), xmm1);
2505 10 : __ vmovups(xmm0, Operand(rsp, 0));
2506 5 : __ addq(rsp, Immediate(kSimd128Size));
2507 :
2508 5 : __ ret(0);
2509 : }
2510 :
2511 5 : CodeDesc desc;
2512 5 : masm.GetCode(isolate, &desc);
2513 : Handle<Code> code =
2514 10 : isolate->factory()->NewCode(desc, Code::STUB, Handle<Code>());
2515 : #ifdef OBJECT_PRINT
2516 : StdoutStream os;
2517 : code->Print(os);
2518 : #endif
2519 :
2520 : auto f = GeneratedCode<F9>::FromCode(*code);
2521 5 : CHECK_EQ(-1.5, f.Call(1.5, -1.5));
2522 : }
2523 :
2524 : #undef __
2525 :
2526 : } // namespace internal
2527 85011 : } // namespace v8
|