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