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 26643 : TEST(AssemblerX64ReturnOperation) {
75 4 : CcTest::InitializeVM();
76 : auto buffer = AllocateAssemblerBuffer();
77 16 : 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 26643 : TEST(AssemblerX64StackOperations) {
95 4 : CcTest::InitializeVM();
96 : auto buffer = AllocateAssemblerBuffer();
97 16 : 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 26643 : TEST(AssemblerX64ArithmeticOperations) {
125 4 : CcTest::InitializeVM();
126 : auto buffer = AllocateAssemblerBuffer();
127 16 : Assembler masm(AssemblerOptions{}, buffer->CreateView());
128 :
129 : // Assemble a simple function that adds arguments returning the sum.
130 : __ movq(rax, arg2);
131 : __ 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 26643 : TEST(AssemblerX64CmpbOperation) {
145 4 : CcTest::InitializeVM();
146 : auto buffer = AllocateAssemblerBuffer();
147 16 : 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 26643 : TEST(AssemblerX64ImulOperation) {
173 4 : CcTest::InitializeVM();
174 : auto buffer = AllocateAssemblerBuffer();
175 16 : 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 26643 : TEST(AssemblerX64testbwqOperation) {
198 4 : CcTest::InitializeVM();
199 8 : v8::HandleScope scope(CcTest::isolate());
200 : auto buffer = AllocateAssemblerBuffer();
201 16 : 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 4 : CHECK_EQ(1, result);
361 4 : }
362 :
363 26643 : TEST(AssemblerX64XchglOperations) {
364 4 : CcTest::InitializeVM();
365 : auto buffer = AllocateAssemblerBuffer();
366 16 : 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 26643 : TEST(AssemblerX64OrlOperations) {
390 4 : CcTest::InitializeVM();
391 : auto buffer = AllocateAssemblerBuffer();
392 16 : 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 26643 : TEST(AssemblerX64RollOperations) {
412 4 : CcTest::InitializeVM();
413 : auto buffer = AllocateAssemblerBuffer();
414 16 : 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 26643 : TEST(AssemblerX64SublOperations) {
432 4 : CcTest::InitializeVM();
433 : auto buffer = AllocateAssemblerBuffer();
434 16 : 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 26643 : TEST(AssemblerX64TestlOperations) {
454 4 : CcTest::InitializeVM();
455 : auto buffer = AllocateAssemblerBuffer();
456 16 : 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 26643 : TEST(AssemblerX64TestwOperations) {
480 : typedef uint16_t(F)(uint16_t * x);
481 4 : CcTest::InitializeVM();
482 : auto buffer = AllocateAssemblerBuffer();
483 16 : 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 26643 : TEST(AssemblerX64XorlOperations) {
505 4 : CcTest::InitializeVM();
506 : auto buffer = AllocateAssemblerBuffer();
507 16 : 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 26643 : TEST(AssemblerX64MemoryOperands) {
527 4 : CcTest::InitializeVM();
528 : auto buffer = AllocateAssemblerBuffer();
529 16 : 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 26643 : TEST(AssemblerX64ControlFlow) {
559 4 : CcTest::InitializeVM();
560 : auto buffer = AllocateAssemblerBuffer();
561 16 : 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 26643 : TEST(AssemblerX64LoopImmediates) {
586 4 : CcTest::InitializeVM();
587 : auto buffer = AllocateAssemblerBuffer();
588 16 : 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 : __ addq(rax, Immediate(7));
598 4 : __ bind(&Loop1_test);
599 : __ cmpq(rax, Immediate(20));
600 4 : __ j(less_equal, &Loop1_body);
601 : // Did the loop terminate with the expected value?
602 : __ 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 : __ addq(rax, Immediate(-0x1100));
611 4 : __ bind(&Loop2_test);
612 : __ cmpq(rax, Immediate(0x11FE8000));
613 4 : __ j(greater, &Loop2_body);
614 : // Did the loop terminate with the expected value?
615 : __ 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 26643 : TEST(OperandRegisterDependency) {
635 4 : int offsets[4] = {0, 1, 0xFED, 0xBEEFCAD};
636 36 : 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 26643 : TEST(AssemblerX64LabelChaining) {
678 : // Test chaining of label usages within instructions (issue 1644).
679 4 : CcTest::InitializeVM();
680 8 : 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 4 : __ nop();
688 4 : }
689 :
690 :
691 26643 : TEST(AssemblerMultiByteNop) {
692 4 : CcTest::InitializeVM();
693 8 : 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 132 : for (int i = 0; i < 16; i++) {
710 : int before = masm.pc_offset();
711 64 : __ Nop(i);
712 64 : CHECK_EQ(masm.pc_offset() - before, i);
713 : }
714 :
715 4 : Label fail;
716 : __ cmpq(rax, Immediate(1));
717 4 : __ j(not_equal, &fail);
718 : __ cmpq(rbx, Immediate(2));
719 4 : __ j(not_equal, &fail);
720 : __ cmpq(rcx, Immediate(3));
721 4 : __ j(not_equal, &fail);
722 : __ cmpq(rdx, Immediate(4));
723 4 : __ j(not_equal, &fail);
724 : __ cmpq(rdi, Immediate(5));
725 4 : __ j(not_equal, &fail);
726 : __ 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 4 : CHECK_EQ(42, res);
752 4 : }
753 :
754 :
755 : #ifdef __GNUC__
756 : #define ELEMENT_COUNT 4u
757 :
758 4 : void DoSSE2(const v8::FunctionCallbackInfo<v8::Value>& args) {
759 8 : 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 20 : for (unsigned i = 0; i < ELEMENT_COUNT; i++) {
776 8 : __ movl(rax, Immediate(vec->Get(context, i)
777 : .ToLocalChecked()
778 16 : ->Int32Value(context)
779 : .FromJust()));
780 : __ shlq(rax, Immediate(0x20));
781 8 : __ orq(rax, Immediate(vec->Get(context, ++i)
782 : .ToLocalChecked()
783 16 : ->Int32Value(context)
784 : .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 : __ 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 4 : args.GetReturnValue().Set(v8::Integer::New(CcTest::isolate(), res));
809 4 : }
810 :
811 :
812 26643 : 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 8 : v8::HandleScope handle_scope(isolate);
818 : v8::Local<v8::ObjectTemplate> global_template =
819 4 : v8::ObjectTemplate::New(isolate);
820 12 : global_template->Set(v8_str("do_sse2"),
821 4 : v8::FunctionTemplate::New(isolate, DoSSE2));
822 :
823 4 : 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 12 : 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 36 : 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 8 : CHECK_EQ(8, result->Int32Value(env.local()).FromJust());
845 4 : }
846 :
847 : #undef ELEMENT_COUNT
848 : #endif // __GNUC__
849 :
850 :
851 26643 : TEST(AssemblerX64Extractps) {
852 4 : CcTest::InitializeVM();
853 4 : if (!CpuFeatures::IsSupported(SSE4_1)) return;
854 :
855 8 : 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 4 : CHECK_EQ(0x87654321u, f.Call(uint64_to_double(value2)));
880 : }
881 :
882 : typedef int(F6)(float x, float y);
883 26643 : 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 8 : 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 : 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 26643 : 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 8 : 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 : 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 26643 : TEST(AssemblerX64FMA_sd) {
949 4 : CcTest::InitializeVM();
950 8 : if (!CpuFeatures::IsSupported(FMA3)) return;
951 :
952 0 : 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 0 : ExternalAssemblerBuffer(buffer, sizeof(buffer)));
957 : {
958 : CpuFeatureScope fscope(&masm, FMA3);
959 0 : Label exit;
960 : // argument in xmm0, xmm1 and xmm2
961 : // xmm0 * xmm1 + xmm2
962 0 : __ movaps(xmm3, xmm0);
963 0 : __ mulsd(xmm3, xmm1);
964 0 : __ addsd(xmm3, xmm2); // Expected result in xmm3
965 :
966 : __ subq(rsp, Immediate(kDoubleSize)); // For memory operand
967 : // vfmadd132sd
968 : __ movl(rax, Immediate(1)); // Test number
969 0 : __ movaps(xmm8, xmm0);
970 : __ vfmadd132sd(xmm8, xmm2, xmm1);
971 0 : __ ucomisd(xmm8, xmm3);
972 0 : __ j(not_equal, &exit);
973 : // vfmadd213sd
974 : __ incq(rax);
975 0 : __ movaps(xmm8, xmm1);
976 : __ vfmadd213sd(xmm8, xmm0, xmm2);
977 0 : __ ucomisd(xmm8, xmm3);
978 0 : __ j(not_equal, &exit);
979 : // vfmadd231sd
980 : __ incq(rax);
981 0 : __ movaps(xmm8, xmm2);
982 : __ vfmadd231sd(xmm8, xmm0, xmm1);
983 0 : __ ucomisd(xmm8, xmm3);
984 0 : __ j(not_equal, &exit);
985 :
986 : // vfmadd132sd
987 : __ incq(rax);
988 0 : __ movaps(xmm8, xmm0);
989 0 : __ movsd(Operand(rsp, 0), xmm1);
990 0 : __ vfmadd132sd(xmm8, xmm2, Operand(rsp, 0));
991 0 : __ ucomisd(xmm8, xmm3);
992 0 : __ j(not_equal, &exit);
993 : // vfmadd213sd
994 : __ incq(rax);
995 0 : __ movaps(xmm8, xmm1);
996 0 : __ movsd(Operand(rsp, 0), xmm2);
997 0 : __ vfmadd213sd(xmm8, xmm0, Operand(rsp, 0));
998 0 : __ ucomisd(xmm8, xmm3);
999 0 : __ j(not_equal, &exit);
1000 : // vfmadd231sd
1001 : __ incq(rax);
1002 0 : __ movaps(xmm8, xmm2);
1003 0 : __ movsd(Operand(rsp, 0), xmm1);
1004 0 : __ vfmadd231sd(xmm8, xmm0, Operand(rsp, 0));
1005 0 : __ ucomisd(xmm8, xmm3);
1006 0 : __ j(not_equal, &exit);
1007 :
1008 : // xmm0 * xmm1 - xmm2
1009 0 : __ movaps(xmm3, xmm0);
1010 0 : __ mulsd(xmm3, xmm1);
1011 0 : __ subsd(xmm3, xmm2); // Expected result in xmm3
1012 :
1013 : // vfmsub132sd
1014 : __ incq(rax);
1015 0 : __ movaps(xmm8, xmm0);
1016 : __ vfmsub132sd(xmm8, xmm2, xmm1);
1017 0 : __ ucomisd(xmm8, xmm3);
1018 0 : __ j(not_equal, &exit);
1019 : // vfmadd213sd
1020 : __ incq(rax);
1021 0 : __ movaps(xmm8, xmm1);
1022 : __ vfmsub213sd(xmm8, xmm0, xmm2);
1023 0 : __ ucomisd(xmm8, xmm3);
1024 0 : __ j(not_equal, &exit);
1025 : // vfmsub231sd
1026 : __ incq(rax);
1027 0 : __ movaps(xmm8, xmm2);
1028 : __ vfmsub231sd(xmm8, xmm0, xmm1);
1029 0 : __ ucomisd(xmm8, xmm3);
1030 0 : __ j(not_equal, &exit);
1031 :
1032 : // vfmsub132sd
1033 : __ incq(rax);
1034 0 : __ movaps(xmm8, xmm0);
1035 0 : __ movsd(Operand(rsp, 0), xmm1);
1036 0 : __ vfmsub132sd(xmm8, xmm2, Operand(rsp, 0));
1037 0 : __ ucomisd(xmm8, xmm3);
1038 0 : __ j(not_equal, &exit);
1039 : // vfmsub213sd
1040 : __ incq(rax);
1041 0 : __ movaps(xmm8, xmm1);
1042 0 : __ movsd(Operand(rsp, 0), xmm2);
1043 0 : __ vfmsub213sd(xmm8, xmm0, Operand(rsp, 0));
1044 0 : __ ucomisd(xmm8, xmm3);
1045 0 : __ j(not_equal, &exit);
1046 : // vfmsub231sd
1047 : __ incq(rax);
1048 0 : __ movaps(xmm8, xmm2);
1049 0 : __ movsd(Operand(rsp, 0), xmm1);
1050 0 : __ vfmsub231sd(xmm8, xmm0, Operand(rsp, 0));
1051 0 : __ ucomisd(xmm8, xmm3);
1052 0 : __ j(not_equal, &exit);
1053 :
1054 :
1055 : // - xmm0 * xmm1 + xmm2
1056 0 : __ movaps(xmm3, xmm0);
1057 0 : __ mulsd(xmm3, xmm1);
1058 0 : __ Move(xmm4, static_cast<uint64_t>(1) << 63);
1059 0 : __ xorpd(xmm3, xmm4);
1060 0 : __ addsd(xmm3, xmm2); // Expected result in xmm3
1061 :
1062 : // vfnmadd132sd
1063 : __ incq(rax);
1064 0 : __ movaps(xmm8, xmm0);
1065 : __ vfnmadd132sd(xmm8, xmm2, xmm1);
1066 0 : __ ucomisd(xmm8, xmm3);
1067 0 : __ j(not_equal, &exit);
1068 : // vfmadd213sd
1069 : __ incq(rax);
1070 0 : __ movaps(xmm8, xmm1);
1071 : __ vfnmadd213sd(xmm8, xmm0, xmm2);
1072 0 : __ ucomisd(xmm8, xmm3);
1073 0 : __ j(not_equal, &exit);
1074 : // vfnmadd231sd
1075 : __ incq(rax);
1076 0 : __ movaps(xmm8, xmm2);
1077 : __ vfnmadd231sd(xmm8, xmm0, xmm1);
1078 0 : __ ucomisd(xmm8, xmm3);
1079 0 : __ j(not_equal, &exit);
1080 :
1081 : // vfnmadd132sd
1082 : __ incq(rax);
1083 0 : __ movaps(xmm8, xmm0);
1084 0 : __ movsd(Operand(rsp, 0), xmm1);
1085 0 : __ vfnmadd132sd(xmm8, xmm2, Operand(rsp, 0));
1086 0 : __ ucomisd(xmm8, xmm3);
1087 0 : __ j(not_equal, &exit);
1088 : // vfnmadd213sd
1089 : __ incq(rax);
1090 0 : __ movaps(xmm8, xmm1);
1091 0 : __ movsd(Operand(rsp, 0), xmm2);
1092 0 : __ vfnmadd213sd(xmm8, xmm0, Operand(rsp, 0));
1093 0 : __ ucomisd(xmm8, xmm3);
1094 0 : __ j(not_equal, &exit);
1095 : // vfnmadd231sd
1096 : __ incq(rax);
1097 0 : __ movaps(xmm8, xmm2);
1098 0 : __ movsd(Operand(rsp, 0), xmm1);
1099 0 : __ vfnmadd231sd(xmm8, xmm0, Operand(rsp, 0));
1100 0 : __ ucomisd(xmm8, xmm3);
1101 0 : __ j(not_equal, &exit);
1102 :
1103 :
1104 : // - xmm0 * xmm1 - xmm2
1105 0 : __ movaps(xmm3, xmm0);
1106 0 : __ mulsd(xmm3, xmm1);
1107 0 : __ Move(xmm4, static_cast<uint64_t>(1) << 63);
1108 0 : __ xorpd(xmm3, xmm4);
1109 0 : __ subsd(xmm3, xmm2); // Expected result in xmm3
1110 :
1111 : // vfnmsub132sd
1112 : __ incq(rax);
1113 0 : __ movaps(xmm8, xmm0);
1114 : __ vfnmsub132sd(xmm8, xmm2, xmm1);
1115 0 : __ ucomisd(xmm8, xmm3);
1116 0 : __ j(not_equal, &exit);
1117 : // vfmsub213sd
1118 : __ incq(rax);
1119 0 : __ movaps(xmm8, xmm1);
1120 : __ vfnmsub213sd(xmm8, xmm0, xmm2);
1121 0 : __ ucomisd(xmm8, xmm3);
1122 0 : __ j(not_equal, &exit);
1123 : // vfnmsub231sd
1124 : __ incq(rax);
1125 0 : __ movaps(xmm8, xmm2);
1126 : __ vfnmsub231sd(xmm8, xmm0, xmm1);
1127 0 : __ ucomisd(xmm8, xmm3);
1128 0 : __ j(not_equal, &exit);
1129 :
1130 : // vfnmsub132sd
1131 : __ incq(rax);
1132 0 : __ movaps(xmm8, xmm0);
1133 0 : __ movsd(Operand(rsp, 0), xmm1);
1134 0 : __ vfnmsub132sd(xmm8, xmm2, Operand(rsp, 0));
1135 0 : __ ucomisd(xmm8, xmm3);
1136 0 : __ j(not_equal, &exit);
1137 : // vfnmsub213sd
1138 : __ incq(rax);
1139 0 : __ movaps(xmm8, xmm1);
1140 0 : __ movsd(Operand(rsp, 0), xmm2);
1141 0 : __ vfnmsub213sd(xmm8, xmm0, Operand(rsp, 0));
1142 0 : __ ucomisd(xmm8, xmm3);
1143 0 : __ j(not_equal, &exit);
1144 : // vfnmsub231sd
1145 : __ incq(rax);
1146 0 : __ movaps(xmm8, xmm2);
1147 0 : __ movsd(Operand(rsp, 0), xmm1);
1148 0 : __ vfnmsub231sd(xmm8, xmm0, Operand(rsp, 0));
1149 0 : __ ucomisd(xmm8, xmm3);
1150 0 : __ j(not_equal, &exit);
1151 :
1152 :
1153 : __ xorl(rax, rax);
1154 0 : __ bind(&exit);
1155 : __ addq(rsp, Immediate(kDoubleSize));
1156 0 : __ ret(0);
1157 : }
1158 :
1159 0 : CodeDesc desc;
1160 : masm.GetCode(isolate, &desc);
1161 : Handle<Code> code =
1162 0 : 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 0 : 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 26643 : TEST(AssemblerX64FMA_ss) {
1175 4 : CcTest::InitializeVM();
1176 8 : if (!CpuFeatures::IsSupported(FMA3)) return;
1177 :
1178 0 : 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 0 : ExternalAssemblerBuffer(buffer, sizeof(buffer)));
1183 : {
1184 : CpuFeatureScope fscope(&masm, FMA3);
1185 0 : Label exit;
1186 : // arguments in xmm0, xmm1 and xmm2
1187 : // xmm0 * xmm1 + xmm2
1188 0 : __ movaps(xmm3, xmm0);
1189 0 : __ mulss(xmm3, xmm1);
1190 0 : __ addss(xmm3, xmm2); // Expected result in xmm3
1191 :
1192 : __ subq(rsp, Immediate(kDoubleSize)); // For memory operand
1193 : // vfmadd132ss
1194 : __ movl(rax, Immediate(1)); // Test number
1195 0 : __ movaps(xmm8, xmm0);
1196 : __ vfmadd132ss(xmm8, xmm2, xmm1);
1197 0 : __ ucomiss(xmm8, xmm3);
1198 0 : __ j(not_equal, &exit);
1199 : // vfmadd213ss
1200 : __ incq(rax);
1201 0 : __ movaps(xmm8, xmm1);
1202 : __ vfmadd213ss(xmm8, xmm0, xmm2);
1203 0 : __ ucomiss(xmm8, xmm3);
1204 0 : __ j(not_equal, &exit);
1205 : // vfmadd231ss
1206 : __ incq(rax);
1207 0 : __ movaps(xmm8, xmm2);
1208 : __ vfmadd231ss(xmm8, xmm0, xmm1);
1209 0 : __ ucomiss(xmm8, xmm3);
1210 0 : __ j(not_equal, &exit);
1211 :
1212 : // vfmadd132ss
1213 : __ incq(rax);
1214 0 : __ movaps(xmm8, xmm0);
1215 0 : __ movss(Operand(rsp, 0), xmm1);
1216 0 : __ vfmadd132ss(xmm8, xmm2, Operand(rsp, 0));
1217 0 : __ ucomiss(xmm8, xmm3);
1218 0 : __ j(not_equal, &exit);
1219 : // vfmadd213ss
1220 : __ incq(rax);
1221 0 : __ movaps(xmm8, xmm1);
1222 0 : __ movss(Operand(rsp, 0), xmm2);
1223 0 : __ vfmadd213ss(xmm8, xmm0, Operand(rsp, 0));
1224 0 : __ ucomiss(xmm8, xmm3);
1225 0 : __ j(not_equal, &exit);
1226 : // vfmadd231ss
1227 : __ incq(rax);
1228 0 : __ movaps(xmm8, xmm2);
1229 0 : __ movss(Operand(rsp, 0), xmm1);
1230 0 : __ vfmadd231ss(xmm8, xmm0, Operand(rsp, 0));
1231 0 : __ ucomiss(xmm8, xmm3);
1232 0 : __ j(not_equal, &exit);
1233 :
1234 : // xmm0 * xmm1 - xmm2
1235 0 : __ movaps(xmm3, xmm0);
1236 0 : __ mulss(xmm3, xmm1);
1237 0 : __ subss(xmm3, xmm2); // Expected result in xmm3
1238 :
1239 : // vfmsub132ss
1240 : __ incq(rax);
1241 0 : __ movaps(xmm8, xmm0);
1242 : __ vfmsub132ss(xmm8, xmm2, xmm1);
1243 0 : __ ucomiss(xmm8, xmm3);
1244 0 : __ j(not_equal, &exit);
1245 : // vfmadd213ss
1246 : __ incq(rax);
1247 0 : __ movaps(xmm8, xmm1);
1248 : __ vfmsub213ss(xmm8, xmm0, xmm2);
1249 0 : __ ucomiss(xmm8, xmm3);
1250 0 : __ j(not_equal, &exit);
1251 : // vfmsub231ss
1252 : __ incq(rax);
1253 0 : __ movaps(xmm8, xmm2);
1254 : __ vfmsub231ss(xmm8, xmm0, xmm1);
1255 0 : __ ucomiss(xmm8, xmm3);
1256 0 : __ j(not_equal, &exit);
1257 :
1258 : // vfmsub132ss
1259 : __ incq(rax);
1260 0 : __ movaps(xmm8, xmm0);
1261 0 : __ movss(Operand(rsp, 0), xmm1);
1262 0 : __ vfmsub132ss(xmm8, xmm2, Operand(rsp, 0));
1263 0 : __ ucomiss(xmm8, xmm3);
1264 0 : __ j(not_equal, &exit);
1265 : // vfmsub213ss
1266 : __ incq(rax);
1267 0 : __ movaps(xmm8, xmm1);
1268 0 : __ movss(Operand(rsp, 0), xmm2);
1269 0 : __ vfmsub213ss(xmm8, xmm0, Operand(rsp, 0));
1270 0 : __ ucomiss(xmm8, xmm3);
1271 0 : __ j(not_equal, &exit);
1272 : // vfmsub231ss
1273 : __ incq(rax);
1274 0 : __ movaps(xmm8, xmm2);
1275 0 : __ movss(Operand(rsp, 0), xmm1);
1276 0 : __ vfmsub231ss(xmm8, xmm0, Operand(rsp, 0));
1277 0 : __ ucomiss(xmm8, xmm3);
1278 0 : __ j(not_equal, &exit);
1279 :
1280 :
1281 : // - xmm0 * xmm1 + xmm2
1282 0 : __ movaps(xmm3, xmm0);
1283 0 : __ mulss(xmm3, xmm1);
1284 0 : __ Move(xmm4, static_cast<uint32_t>(1) << 31);
1285 0 : __ xorps(xmm3, xmm4);
1286 0 : __ addss(xmm3, xmm2); // Expected result in xmm3
1287 :
1288 : // vfnmadd132ss
1289 : __ incq(rax);
1290 0 : __ movaps(xmm8, xmm0);
1291 : __ vfnmadd132ss(xmm8, xmm2, xmm1);
1292 0 : __ ucomiss(xmm8, xmm3);
1293 0 : __ j(not_equal, &exit);
1294 : // vfmadd213ss
1295 : __ incq(rax);
1296 0 : __ movaps(xmm8, xmm1);
1297 : __ vfnmadd213ss(xmm8, xmm0, xmm2);
1298 0 : __ ucomiss(xmm8, xmm3);
1299 0 : __ j(not_equal, &exit);
1300 : // vfnmadd231ss
1301 : __ incq(rax);
1302 0 : __ movaps(xmm8, xmm2);
1303 : __ vfnmadd231ss(xmm8, xmm0, xmm1);
1304 0 : __ ucomiss(xmm8, xmm3);
1305 0 : __ j(not_equal, &exit);
1306 :
1307 : // vfnmadd132ss
1308 : __ incq(rax);
1309 0 : __ movaps(xmm8, xmm0);
1310 0 : __ movss(Operand(rsp, 0), xmm1);
1311 0 : __ vfnmadd132ss(xmm8, xmm2, Operand(rsp, 0));
1312 0 : __ ucomiss(xmm8, xmm3);
1313 0 : __ j(not_equal, &exit);
1314 : // vfnmadd213ss
1315 : __ incq(rax);
1316 0 : __ movaps(xmm8, xmm1);
1317 0 : __ movss(Operand(rsp, 0), xmm2);
1318 0 : __ vfnmadd213ss(xmm8, xmm0, Operand(rsp, 0));
1319 0 : __ ucomiss(xmm8, xmm3);
1320 0 : __ j(not_equal, &exit);
1321 : // vfnmadd231ss
1322 : __ incq(rax);
1323 0 : __ movaps(xmm8, xmm2);
1324 0 : __ movss(Operand(rsp, 0), xmm1);
1325 0 : __ vfnmadd231ss(xmm8, xmm0, Operand(rsp, 0));
1326 0 : __ ucomiss(xmm8, xmm3);
1327 0 : __ j(not_equal, &exit);
1328 :
1329 :
1330 : // - xmm0 * xmm1 - xmm2
1331 0 : __ movaps(xmm3, xmm0);
1332 0 : __ mulss(xmm3, xmm1);
1333 0 : __ Move(xmm4, static_cast<uint32_t>(1) << 31);
1334 0 : __ xorps(xmm3, xmm4);
1335 0 : __ subss(xmm3, xmm2); // Expected result in xmm3
1336 :
1337 : // vfnmsub132ss
1338 : __ incq(rax);
1339 0 : __ movaps(xmm8, xmm0);
1340 : __ vfnmsub132ss(xmm8, xmm2, xmm1);
1341 0 : __ ucomiss(xmm8, xmm3);
1342 0 : __ j(not_equal, &exit);
1343 : // vfmsub213ss
1344 : __ incq(rax);
1345 0 : __ movaps(xmm8, xmm1);
1346 : __ vfnmsub213ss(xmm8, xmm0, xmm2);
1347 0 : __ ucomiss(xmm8, xmm3);
1348 0 : __ j(not_equal, &exit);
1349 : // vfnmsub231ss
1350 : __ incq(rax);
1351 0 : __ movaps(xmm8, xmm2);
1352 : __ vfnmsub231ss(xmm8, xmm0, xmm1);
1353 0 : __ ucomiss(xmm8, xmm3);
1354 0 : __ j(not_equal, &exit);
1355 :
1356 : // vfnmsub132ss
1357 : __ incq(rax);
1358 0 : __ movaps(xmm8, xmm0);
1359 0 : __ movss(Operand(rsp, 0), xmm1);
1360 0 : __ vfnmsub132ss(xmm8, xmm2, Operand(rsp, 0));
1361 0 : __ ucomiss(xmm8, xmm3);
1362 0 : __ j(not_equal, &exit);
1363 : // vfnmsub213ss
1364 : __ incq(rax);
1365 0 : __ movaps(xmm8, xmm1);
1366 0 : __ movss(Operand(rsp, 0), xmm2);
1367 0 : __ vfnmsub213ss(xmm8, xmm0, Operand(rsp, 0));
1368 0 : __ ucomiss(xmm8, xmm3);
1369 0 : __ j(not_equal, &exit);
1370 : // vfnmsub231ss
1371 : __ incq(rax);
1372 0 : __ movaps(xmm8, xmm2);
1373 0 : __ movss(Operand(rsp, 0), xmm1);
1374 0 : __ vfnmsub231ss(xmm8, xmm0, Operand(rsp, 0));
1375 0 : __ ucomiss(xmm8, xmm3);
1376 0 : __ j(not_equal, &exit);
1377 :
1378 :
1379 : __ xorl(rax, rax);
1380 0 : __ bind(&exit);
1381 : __ addq(rsp, Immediate(kDoubleSize));
1382 0 : __ ret(0);
1383 : }
1384 :
1385 0 : CodeDesc desc;
1386 : masm.GetCode(isolate, &desc);
1387 : Handle<Code> code =
1388 0 : 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 0 : CHECK_EQ(0, f.Call(9.26621069e-05f, -2.4607749f, -1.09587872f));
1396 : }
1397 :
1398 :
1399 26643 : 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 26643 : 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 : __ 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 : __ 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 : __ 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 26643 : 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 : __ 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 : __ 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 : __ 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 : __ vcvttsd2si(rcx, xmm6);
1603 : __ cmpl(rcx, rdx);
1604 4 : __ j(not_equal, &exit);
1605 : __ xorl(rcx, rcx);
1606 4 : __ vmovsd(Operand(rsp, 0), xmm6);
1607 8 : __ vcvttsd2si(rcx, Operand(rsp, 0));
1608 : __ cmpl(rcx, rdx);
1609 4 : __ j(not_equal, &exit);
1610 :
1611 : // Test vcvttsd2siq
1612 : __ movl(rax, Immediate(11));
1613 : __ movq(rdx, uint64_t{0x426D1A94A2000000}); // 1.0e12
1614 4 : __ vmovq(xmm6, rdx);
1615 : __ vcvttsd2siq(rcx, xmm6);
1616 : __ movq(rdx, uint64_t{1000000000000});
1617 : __ cmpq(rcx, rdx);
1618 4 : __ j(not_equal, &exit);
1619 : __ xorq(rcx, rcx);
1620 4 : __ vmovsd(Operand(rsp, 0), xmm6);
1621 8 : __ vcvttsd2siq(rcx, Operand(rsp, 0));
1622 : __ cmpq(rcx, rdx);
1623 4 : __ j(not_equal, &exit);
1624 :
1625 : // Test vmovmskpd
1626 : __ movl(rax, Immediate(12));
1627 : __ movq(rdx, uint64_t{0x426D1A94A2000000}); // 1.0e12
1628 4 : __ vmovq(xmm6, rdx);
1629 : __ movq(rdx, uint64_t{0xC26D1A94A2000000}); // -1.0e12
1630 4 : __ vmovq(xmm7, rdx);
1631 4 : __ shufps(xmm6, xmm7, 0x44);
1632 : __ vmovmskpd(rdx, xmm6);
1633 : __ cmpl(rdx, Immediate(2));
1634 4 : __ j(not_equal, &exit);
1635 :
1636 : // Test vpcmpeqd
1637 : __ movq(rdx, uint64_t{0x0123456789ABCDEF});
1638 : __ 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 : __ movq(rcx, uint64_t{0xFFFFFFFF00000000});
1644 : __ 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 : __ movq(rdx, uint64_t{0x0123456789ABCDEF});
1651 4 : __ vmovq(xmm6, rdx);
1652 : __ vpsrlq(xmm7, xmm6, 4);
1653 4 : __ vmovq(rdx, xmm7);
1654 : __ movq(rcx, uint64_t{0x00123456789ABCDE});
1655 : __ cmpq(rdx, rcx);
1656 4 : __ j(not_equal, &exit);
1657 : __ vpsllq(xmm7, xmm6, 12);
1658 4 : __ vmovq(rdx, xmm7);
1659 : __ movq(rcx, uint64_t{0x3456789ABCDEF000});
1660 : __ 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 : __ cmpl(rdx, Immediate(0x000F000F));
1672 4 : __ j(not_equal, &exit);
1673 : __ vorpd(xmm6, xmm4, xmm5);
1674 4 : __ vmovd(rdx, xmm6);
1675 : __ cmpl(rdx, Immediate(0x0FFF0FFF));
1676 4 : __ j(not_equal, &exit);
1677 : __ vxorpd(xmm6, xmm4, xmm5);
1678 4 : __ vmovd(rdx, xmm6);
1679 : __ cmpl(rdx, Immediate(0x0FF00FF0));
1680 4 : __ j(not_equal, &exit);
1681 :
1682 : // Test vsqrtsd
1683 : __ movl(rax, Immediate(15));
1684 : __ 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 : __ cmpq(rcx, rdx);
1691 4 : __ j(not_equal, &exit);
1692 4 : __ vsqrtsd(xmm7, xmm7, Operand(rsp, 0));
1693 4 : __ vmovq(rcx, xmm7);
1694 : __ cmpq(rcx, rdx);
1695 4 : __ j(not_equal, &exit);
1696 :
1697 : // Test vroundsd
1698 : __ movl(rax, Immediate(16));
1699 : __ movq(rdx, uint64_t{0x4002000000000000}); // 2.25
1700 4 : __ vmovq(xmm4, rdx);
1701 : __ vroundsd(xmm5, xmm4, xmm4, kRoundUp);
1702 : __ 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 : __ 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 : __ movq(rdx, uint64_t{0x2000000000000000}); // 2 << 0x3C
1723 : __ 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 : __ movq(rdx, uint64_t{0x4018000000000000}); // 6.0
1732 4 : __ vmovq(xmm5, rdx);
1733 : __ vcvtsd2si(rcx, xmm5);
1734 : __ cmpl(rcx, Immediate(6));
1735 4 : __ j(not_equal, &exit);
1736 :
1737 : __ 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 : __ 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 26643 : TEST(AssemblerX64BMI1) {
1804 4 : CcTest::InitializeVM();
1805 8 : if (!CpuFeatures::IsSupported(BMI1)) return;
1806 :
1807 0 : 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 0 : ExternalAssemblerBuffer(buffer, sizeof(buffer)));
1812 : {
1813 : CpuFeatureScope fscope(&masm, BMI1);
1814 0 : Label exit;
1815 :
1816 : __ movq(rcx, uint64_t{0x1122334455667788}); // source operand
1817 0 : __ pushq(rcx); // For memory operand
1818 :
1819 : // andn
1820 : __ movq(rdx, uint64_t{0x1000000020000000});
1821 :
1822 : __ movl(rax, Immediate(1)); // Test number
1823 : __ andnq(r8, rdx, rcx);
1824 : __ movq(r9, uint64_t{0x0122334455667788}); // expected result
1825 : __ cmpq(r8, r9);
1826 0 : __ j(not_equal, &exit);
1827 :
1828 : __ incq(rax);
1829 0 : __ andnq(r8, rdx, Operand(rsp, 0));
1830 : __ movq(r9, uint64_t{0x0122334455667788}); // expected result
1831 : __ cmpq(r8, r9);
1832 0 : __ j(not_equal, &exit);
1833 :
1834 : __ incq(rax);
1835 : __ andnl(r8, rdx, rcx);
1836 : __ movq(r9, uint64_t{0x0000000055667788}); // expected result
1837 : __ cmpq(r8, r9);
1838 0 : __ j(not_equal, &exit);
1839 :
1840 : __ incq(rax);
1841 0 : __ andnl(r8, rdx, Operand(rsp, 0));
1842 : __ movq(r9, uint64_t{0x0000000055667788}); // expected result
1843 : __ cmpq(r8, r9);
1844 0 : __ j(not_equal, &exit);
1845 :
1846 : // bextr
1847 : __ movq(rdx, uint64_t{0x0000000000002808});
1848 :
1849 : __ incq(rax);
1850 : __ bextrq(r8, rcx, rdx);
1851 : __ movq(r9, uint64_t{0x0000003344556677}); // expected result
1852 : __ cmpq(r8, r9);
1853 0 : __ j(not_equal, &exit);
1854 :
1855 : __ incq(rax);
1856 0 : __ bextrq(r8, Operand(rsp, 0), rdx);
1857 : __ movq(r9, uint64_t{0x0000003344556677}); // expected result
1858 : __ cmpq(r8, r9);
1859 0 : __ j(not_equal, &exit);
1860 :
1861 : __ incq(rax);
1862 : __ bextrl(r8, rcx, rdx);
1863 : __ movq(r9, uint64_t{0x0000000000556677}); // expected result
1864 : __ cmpq(r8, r9);
1865 0 : __ j(not_equal, &exit);
1866 :
1867 : __ incq(rax);
1868 0 : __ bextrl(r8, Operand(rsp, 0), rdx);
1869 : __ movq(r9, uint64_t{0x0000000000556677}); // expected result
1870 : __ cmpq(r8, r9);
1871 0 : __ j(not_equal, &exit);
1872 :
1873 : // blsi
1874 : __ incq(rax);
1875 : __ blsiq(r8, rcx);
1876 : __ movq(r9, uint64_t{0x0000000000000008}); // expected result
1877 : __ cmpq(r8, r9);
1878 0 : __ j(not_equal, &exit);
1879 :
1880 : __ incq(rax);
1881 0 : __ blsiq(r8, Operand(rsp, 0));
1882 : __ movq(r9, uint64_t{0x0000000000000008}); // expected result
1883 : __ cmpq(r8, r9);
1884 0 : __ j(not_equal, &exit);
1885 :
1886 : __ incq(rax);
1887 : __ blsil(r8, rcx);
1888 : __ movq(r9, uint64_t{0x0000000000000008}); // expected result
1889 : __ cmpq(r8, r9);
1890 0 : __ j(not_equal, &exit);
1891 :
1892 : __ incq(rax);
1893 0 : __ blsil(r8, Operand(rsp, 0));
1894 : __ movq(r9, uint64_t{0x0000000000000008}); // expected result
1895 : __ cmpq(r8, r9);
1896 0 : __ j(not_equal, &exit);
1897 :
1898 : // blsmsk
1899 : __ incq(rax);
1900 : __ blsmskq(r8, rcx);
1901 : __ movq(r9, uint64_t{0x000000000000000F}); // expected result
1902 : __ cmpq(r8, r9);
1903 0 : __ j(not_equal, &exit);
1904 :
1905 : __ incq(rax);
1906 0 : __ blsmskq(r8, Operand(rsp, 0));
1907 : __ movq(r9, uint64_t{0x000000000000000F}); // expected result
1908 : __ cmpq(r8, r9);
1909 0 : __ j(not_equal, &exit);
1910 :
1911 : __ incq(rax);
1912 : __ blsmskl(r8, rcx);
1913 : __ movq(r9, uint64_t{0x000000000000000F}); // expected result
1914 : __ cmpq(r8, r9);
1915 0 : __ j(not_equal, &exit);
1916 :
1917 : __ incq(rax);
1918 0 : __ blsmskl(r8, Operand(rsp, 0));
1919 : __ movq(r9, uint64_t{0x000000000000000F}); // expected result
1920 : __ cmpq(r8, r9);
1921 0 : __ j(not_equal, &exit);
1922 :
1923 : // blsr
1924 : __ incq(rax);
1925 : __ blsrq(r8, rcx);
1926 : __ movq(r9, uint64_t{0x1122334455667780}); // expected result
1927 : __ cmpq(r8, r9);
1928 0 : __ j(not_equal, &exit);
1929 :
1930 : __ incq(rax);
1931 0 : __ blsrq(r8, Operand(rsp, 0));
1932 : __ movq(r9, uint64_t{0x1122334455667780}); // expected result
1933 : __ cmpq(r8, r9);
1934 0 : __ j(not_equal, &exit);
1935 :
1936 : __ incq(rax);
1937 : __ blsrl(r8, rcx);
1938 : __ movq(r9, uint64_t{0x0000000055667780}); // expected result
1939 : __ cmpq(r8, r9);
1940 0 : __ j(not_equal, &exit);
1941 :
1942 : __ incq(rax);
1943 0 : __ blsrl(r8, Operand(rsp, 0));
1944 : __ movq(r9, uint64_t{0x0000000055667780}); // expected result
1945 : __ cmpq(r8, r9);
1946 0 : __ j(not_equal, &exit);
1947 :
1948 : // tzcnt
1949 : __ incq(rax);
1950 0 : __ tzcntq(r8, rcx);
1951 : __ movq(r9, uint64_t{0x0000000000000003}); // expected result
1952 : __ cmpq(r8, r9);
1953 0 : __ j(not_equal, &exit);
1954 :
1955 : __ incq(rax);
1956 0 : __ tzcntq(r8, Operand(rsp, 0));
1957 : __ movq(r9, uint64_t{0x0000000000000003}); // expected result
1958 : __ cmpq(r8, r9);
1959 0 : __ j(not_equal, &exit);
1960 :
1961 : __ incq(rax);
1962 0 : __ tzcntl(r8, rcx);
1963 : __ movq(r9, uint64_t{0x0000000000000003}); // expected result
1964 : __ cmpq(r8, r9);
1965 0 : __ j(not_equal, &exit);
1966 :
1967 : __ incq(rax);
1968 0 : __ tzcntl(r8, Operand(rsp, 0));
1969 : __ movq(r9, uint64_t{0x0000000000000003}); // expected result
1970 : __ cmpq(r8, r9);
1971 0 : __ j(not_equal, &exit);
1972 :
1973 : __ xorl(rax, rax);
1974 0 : __ bind(&exit);
1975 0 : __ popq(rcx);
1976 0 : __ ret(0);
1977 : }
1978 :
1979 0 : CodeDesc desc;
1980 : masm.GetCode(isolate, &desc);
1981 : Handle<Code> code =
1982 0 : 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 0 : CHECK_EQ(0, f.Call());
1990 : }
1991 :
1992 :
1993 26643 : TEST(AssemblerX64LZCNT) {
1994 4 : CcTest::InitializeVM();
1995 8 : if (!CpuFeatures::IsSupported(LZCNT)) return;
1996 :
1997 0 : 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 0 : ExternalAssemblerBuffer(buffer, sizeof(buffer)));
2002 : {
2003 : CpuFeatureScope fscope(&masm, LZCNT);
2004 0 : Label exit;
2005 :
2006 : __ movq(rcx, uint64_t{0x1122334455667788}); // source operand
2007 0 : __ pushq(rcx); // For memory operand
2008 :
2009 : __ movl(rax, Immediate(1)); // Test number
2010 0 : __ lzcntq(r8, rcx);
2011 : __ movq(r9, uint64_t{0x0000000000000003}); // expected result
2012 : __ cmpq(r8, r9);
2013 0 : __ j(not_equal, &exit);
2014 :
2015 : __ incq(rax);
2016 0 : __ lzcntq(r8, Operand(rsp, 0));
2017 : __ movq(r9, uint64_t{0x0000000000000003}); // expected result
2018 : __ cmpq(r8, r9);
2019 0 : __ j(not_equal, &exit);
2020 :
2021 : __ incq(rax);
2022 0 : __ lzcntl(r8, rcx);
2023 : __ movq(r9, uint64_t{0x0000000000000001}); // expected result
2024 : __ cmpq(r8, r9);
2025 0 : __ j(not_equal, &exit);
2026 :
2027 : __ incq(rax);
2028 0 : __ lzcntl(r8, Operand(rsp, 0));
2029 : __ movq(r9, uint64_t{0x0000000000000001}); // expected result
2030 : __ cmpq(r8, r9);
2031 0 : __ j(not_equal, &exit);
2032 :
2033 : __ xorl(rax, rax);
2034 0 : __ bind(&exit);
2035 0 : __ popq(rcx);
2036 0 : __ ret(0);
2037 : }
2038 :
2039 0 : CodeDesc desc;
2040 : masm.GetCode(isolate, &desc);
2041 : Handle<Code> code =
2042 0 : 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 0 : CHECK_EQ(0, f.Call());
2050 : }
2051 :
2052 :
2053 26643 : 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 8 : ExternalAssemblerBuffer(buffer, sizeof(buffer)));
2062 : {
2063 : CpuFeatureScope fscope(&masm, POPCNT);
2064 4 : Label exit;
2065 :
2066 : __ 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 : __ movq(r9, uint64_t{0x000000000000000E}); // expected result
2072 : __ cmpq(r8, r9);
2073 4 : __ j(not_equal, &exit);
2074 :
2075 : __ incq(rax);
2076 4 : __ popcntq(r8, Operand(rsp, 0));
2077 : __ movq(r9, uint64_t{0x000000000000000E}); // expected result
2078 : __ cmpq(r8, r9);
2079 4 : __ j(not_equal, &exit);
2080 :
2081 : __ incq(rax);
2082 4 : __ popcntl(r8, rcx);
2083 : __ movq(r9, uint64_t{0x0000000000000006}); // expected result
2084 : __ cmpq(r8, r9);
2085 4 : __ j(not_equal, &exit);
2086 :
2087 : __ incq(rax);
2088 4 : __ popcntl(r8, Operand(rsp, 0));
2089 : __ movq(r9, uint64_t{0x0000000000000006}); // expected result
2090 : __ 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 : 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 26643 : TEST(AssemblerX64BMI2) {
2114 4 : CcTest::InitializeVM();
2115 8 : if (!CpuFeatures::IsSupported(BMI2)) return;
2116 :
2117 0 : 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 0 : ExternalAssemblerBuffer(buffer, sizeof(buffer)));
2122 : {
2123 : CpuFeatureScope fscope(&masm, BMI2);
2124 0 : Label exit;
2125 0 : __ pushq(rbx); // save rbx
2126 : __ movq(rcx, uint64_t{0x1122334455667788}); // source operand
2127 0 : __ pushq(rcx); // For memory operand
2128 :
2129 : // bzhi
2130 : __ movq(rdx, uint64_t{0x0000000000000009});
2131 :
2132 : __ movl(rax, Immediate(1)); // Test number
2133 : __ bzhiq(r8, rcx, rdx);
2134 : __ movq(r9, uint64_t{0x0000000000000188}); // expected result
2135 : __ cmpq(r8, r9);
2136 0 : __ j(not_equal, &exit);
2137 :
2138 : __ incq(rax);
2139 0 : __ bzhiq(r8, Operand(rsp, 0), rdx);
2140 : __ movq(r9, uint64_t{0x0000000000000188}); // expected result
2141 : __ cmpq(r8, r9);
2142 0 : __ j(not_equal, &exit);
2143 :
2144 : __ incq(rax);
2145 : __ bzhil(r8, rcx, rdx);
2146 : __ movq(r9, uint64_t{0x0000000000000188}); // expected result
2147 : __ cmpq(r8, r9);
2148 0 : __ j(not_equal, &exit);
2149 :
2150 : __ incq(rax);
2151 0 : __ bzhil(r8, Operand(rsp, 0), rdx);
2152 : __ movq(r9, uint64_t{0x0000000000000188}); // expected result
2153 : __ cmpq(r8, r9);
2154 0 : __ j(not_equal, &exit);
2155 :
2156 : // mulx
2157 : __ movq(rdx, uint64_t{0x0000000000001000});
2158 :
2159 : __ incq(rax);
2160 : __ mulxq(r8, r9, rcx);
2161 : __ movq(rbx, uint64_t{0x0000000000000112}); // expected result
2162 : __ cmpq(r8, rbx);
2163 0 : __ j(not_equal, &exit);
2164 : __ movq(rbx, uint64_t{0x2334455667788000}); // expected result
2165 : __ cmpq(r9, rbx);
2166 0 : __ j(not_equal, &exit);
2167 :
2168 : __ incq(rax);
2169 0 : __ mulxq(r8, r9, Operand(rsp, 0));
2170 : __ movq(rbx, uint64_t{0x0000000000000112}); // expected result
2171 : __ cmpq(r8, rbx);
2172 0 : __ j(not_equal, &exit);
2173 : __ movq(rbx, uint64_t{0x2334455667788000}); // expected result
2174 : __ cmpq(r9, rbx);
2175 0 : __ j(not_equal, &exit);
2176 :
2177 : __ incq(rax);
2178 : __ mulxl(r8, r9, rcx);
2179 : __ movq(rbx, uint64_t{0x0000000000000556}); // expected result
2180 : __ cmpq(r8, rbx);
2181 0 : __ j(not_equal, &exit);
2182 : __ movq(rbx, uint64_t{0x0000000067788000}); // expected result
2183 : __ cmpq(r9, rbx);
2184 0 : __ j(not_equal, &exit);
2185 :
2186 : __ incq(rax);
2187 0 : __ mulxl(r8, r9, Operand(rsp, 0));
2188 : __ movq(rbx, uint64_t{0x0000000000000556}); // expected result
2189 : __ cmpq(r8, rbx);
2190 0 : __ j(not_equal, &exit);
2191 : __ movq(rbx, uint64_t{0x0000000067788000}); // expected result
2192 : __ cmpq(r9, rbx);
2193 0 : __ j(not_equal, &exit);
2194 :
2195 : // pdep
2196 : __ movq(rdx, uint64_t{0xFFFFFFFFFFFFFFF0});
2197 :
2198 : __ incq(rax);
2199 : __ pdepq(r8, rdx, rcx);
2200 : __ movq(r9, uint64_t{0x1122334455667400}); // expected result
2201 : __ cmpq(r8, r9);
2202 0 : __ j(not_equal, &exit);
2203 :
2204 : __ incq(rax);
2205 0 : __ pdepq(r8, rdx, Operand(rsp, 0));
2206 : __ movq(r9, uint64_t{0x1122334455667400}); // expected result
2207 : __ cmpq(r8, r9);
2208 0 : __ j(not_equal, &exit);
2209 :
2210 : __ incq(rax);
2211 : __ pdepl(r8, rdx, rcx);
2212 : __ movq(r9, uint64_t{0x0000000055667400}); // expected result
2213 : __ cmpq(r8, r9);
2214 0 : __ j(not_equal, &exit);
2215 :
2216 : __ incq(rax);
2217 0 : __ pdepl(r8, rdx, Operand(rsp, 0));
2218 : __ movq(r9, uint64_t{0x0000000055667400}); // expected result
2219 : __ cmpq(r8, r9);
2220 0 : __ j(not_equal, &exit);
2221 :
2222 : // pext
2223 : __ movq(rdx, uint64_t{0xFFFFFFFFFFFFFFF0});
2224 :
2225 : __ incq(rax);
2226 : __ pextq(r8, rdx, rcx);
2227 : __ movq(r9, uint64_t{0x0000000003FFFFFE}); // expected result
2228 : __ cmpq(r8, r9);
2229 0 : __ j(not_equal, &exit);
2230 :
2231 : __ incq(rax);
2232 0 : __ pextq(r8, rdx, Operand(rsp, 0));
2233 : __ movq(r9, uint64_t{0x0000000003FFFFFE}); // expected result
2234 : __ cmpq(r8, r9);
2235 0 : __ j(not_equal, &exit);
2236 :
2237 : __ incq(rax);
2238 : __ pextl(r8, rdx, rcx);
2239 : __ movq(r9, uint64_t{0x000000000000FFFE}); // expected result
2240 : __ cmpq(r8, r9);
2241 0 : __ j(not_equal, &exit);
2242 :
2243 : __ incq(rax);
2244 0 : __ pextl(r8, rdx, Operand(rsp, 0));
2245 : __ movq(r9, uint64_t{0x000000000000FFFE}); // expected result
2246 : __ cmpq(r8, r9);
2247 0 : __ j(not_equal, &exit);
2248 :
2249 : // sarx
2250 : __ movq(rdx, uint64_t{0x0000000000000004});
2251 :
2252 : __ incq(rax);
2253 : __ sarxq(r8, rcx, rdx);
2254 : __ movq(r9, uint64_t{0x0112233445566778}); // expected result
2255 : __ cmpq(r8, r9);
2256 0 : __ j(not_equal, &exit);
2257 :
2258 : __ incq(rax);
2259 0 : __ sarxq(r8, Operand(rsp, 0), rdx);
2260 : __ movq(r9, uint64_t{0x0112233445566778}); // expected result
2261 : __ cmpq(r8, r9);
2262 0 : __ j(not_equal, &exit);
2263 :
2264 : __ incq(rax);
2265 : __ sarxl(r8, rcx, rdx);
2266 : __ movq(r9, uint64_t{0x0000000005566778}); // expected result
2267 : __ cmpq(r8, r9);
2268 0 : __ j(not_equal, &exit);
2269 :
2270 : __ incq(rax);
2271 0 : __ sarxl(r8, Operand(rsp, 0), rdx);
2272 : __ movq(r9, uint64_t{0x0000000005566778}); // expected result
2273 : __ cmpq(r8, r9);
2274 0 : __ j(not_equal, &exit);
2275 :
2276 : // shlx
2277 : __ movq(rdx, uint64_t{0x0000000000000004});
2278 :
2279 : __ incq(rax);
2280 : __ shlxq(r8, rcx, rdx);
2281 : __ movq(r9, uint64_t{0x1223344556677880}); // expected result
2282 : __ cmpq(r8, r9);
2283 0 : __ j(not_equal, &exit);
2284 :
2285 : __ incq(rax);
2286 0 : __ shlxq(r8, Operand(rsp, 0), rdx);
2287 : __ movq(r9, uint64_t{0x1223344556677880}); // expected result
2288 : __ cmpq(r8, r9);
2289 0 : __ j(not_equal, &exit);
2290 :
2291 : __ incq(rax);
2292 : __ shlxl(r8, rcx, rdx);
2293 : __ movq(r9, uint64_t{0x0000000056677880}); // expected result
2294 : __ cmpq(r8, r9);
2295 0 : __ j(not_equal, &exit);
2296 :
2297 : __ incq(rax);
2298 0 : __ shlxl(r8, Operand(rsp, 0), rdx);
2299 : __ movq(r9, uint64_t{0x0000000056677880}); // expected result
2300 : __ cmpq(r8, r9);
2301 0 : __ j(not_equal, &exit);
2302 :
2303 : // shrx
2304 : __ movq(rdx, uint64_t{0x0000000000000004});
2305 :
2306 : __ incq(rax);
2307 : __ shrxq(r8, rcx, rdx);
2308 : __ movq(r9, uint64_t{0x0112233445566778}); // expected result
2309 : __ cmpq(r8, r9);
2310 0 : __ j(not_equal, &exit);
2311 :
2312 : __ incq(rax);
2313 0 : __ shrxq(r8, Operand(rsp, 0), rdx);
2314 : __ movq(r9, uint64_t{0x0112233445566778}); // expected result
2315 : __ cmpq(r8, r9);
2316 0 : __ j(not_equal, &exit);
2317 :
2318 : __ incq(rax);
2319 : __ shrxl(r8, rcx, rdx);
2320 : __ movq(r9, uint64_t{0x0000000005566778}); // expected result
2321 : __ cmpq(r8, r9);
2322 0 : __ j(not_equal, &exit);
2323 :
2324 : __ incq(rax);
2325 0 : __ shrxl(r8, Operand(rsp, 0), rdx);
2326 : __ movq(r9, uint64_t{0x0000000005566778}); // expected result
2327 : __ cmpq(r8, r9);
2328 0 : __ j(not_equal, &exit);
2329 :
2330 : // rorx
2331 : __ incq(rax);
2332 0 : __ rorxq(r8, rcx, 0x4);
2333 : __ movq(r9, uint64_t{0x8112233445566778}); // expected result
2334 : __ cmpq(r8, r9);
2335 0 : __ j(not_equal, &exit);
2336 :
2337 : __ incq(rax);
2338 0 : __ rorxq(r8, Operand(rsp, 0), 0x4);
2339 : __ movq(r9, uint64_t{0x8112233445566778}); // expected result
2340 : __ cmpq(r8, r9);
2341 0 : __ j(not_equal, &exit);
2342 :
2343 : __ incq(rax);
2344 0 : __ rorxl(r8, rcx, 0x4);
2345 : __ movq(r9, uint64_t{0x0000000085566778}); // expected result
2346 : __ cmpq(r8, r9);
2347 0 : __ j(not_equal, &exit);
2348 :
2349 : __ incq(rax);
2350 0 : __ rorxl(r8, Operand(rsp, 0), 0x4);
2351 : __ movq(r9, uint64_t{0x0000000085566778}); // expected result
2352 : __ cmpq(r8, r9);
2353 0 : __ j(not_equal, &exit);
2354 :
2355 : __ xorl(rax, rax);
2356 0 : __ bind(&exit);
2357 0 : __ popq(rcx);
2358 0 : __ popq(rbx);
2359 0 : __ ret(0);
2360 : }
2361 :
2362 0 : CodeDesc desc;
2363 : masm.GetCode(isolate, &desc);
2364 : Handle<Code> code =
2365 0 : 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 0 : CHECK_EQ(0, f.Call());
2373 : }
2374 :
2375 :
2376 26643 : 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 : 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 4 : 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 4100 : for (int i = 0; i < kNumCases; ++i) {
2394 2048 : __ dq(&labels[i]);
2395 : }
2396 :
2397 4100 : 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 : 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 4100 : 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 26643 : 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 : 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 4 : 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 4100 : 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 4100 : for (int i = 0; i < kNumCases; ++i) {
2451 2048 : __ dq(&labels[i]);
2452 : }
2453 :
2454 4 : CodeDesc desc;
2455 : 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 4100 : 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 26643 : TEST(AssemblerX64PslldWithXmm15) {
2471 4 : CcTest::InitializeVM();
2472 : auto buffer = AllocateAssemblerBuffer();
2473 16 : 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 26643 : 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 8 : 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 : __ subq(rsp, Immediate(kSimd128Size));
2504 8 : __ vmovups(Operand(rsp, 0), xmm1);
2505 8 : __ vmovups(xmm0, Operand(rsp, 0));
2506 : __ addq(rsp, Immediate(kSimd128Size));
2507 :
2508 4 : __ ret(0);
2509 : }
2510 :
2511 4 : CodeDesc desc;
2512 : 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 79917 : } // namespace v8
|