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
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.
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.
33 #include "src/base/platform/platform.h"
34 #include "src/factory.h"
35 #include "src/macro-assembler.h"
36 #include "src/ostreams.h"
37 #include "src/serialize.h"
38 #include "test/cctest/cctest.h"
40 using namespace v8::internal;
42 // Test the x64 assembler by compiling some simple functions into
43 // a buffer and executing them. These tests do not initialize the
44 // V8 library, create a context, or use any V8 objects.
45 // The AMD64 calling convention is used, with the first six arguments
46 // in RDI, RSI, RDX, RCX, R8, and R9, and floating point arguments in
47 // the XMM registers. The return value is in RAX.
48 // This calling convention is used on Linux, with GCC, and on Mac OS,
49 // with GCC. A different convention is used on 64-bit windows,
50 // where the first four integer arguments are passed in RCX, RDX, R8 and R9.
53 typedef int (*F1)(int64_t x);
54 typedef int (*F2)(int64_t x, int64_t y);
55 typedef unsigned (*F3)(double x);
56 typedef uint64_t (*F4)(uint64_t* x, uint64_t* y);
57 typedef uint64_t (*F5)(uint64_t x);
60 static const Register arg1 = rcx;
61 static const Register arg2 = rdx;
63 static const Register arg1 = rdi;
64 static const Register arg2 = rsi;
70 TEST(AssemblerX64ReturnOperation) {
71 CcTest::InitializeVM();
72 // Allocate an executable page of memory.
74 byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
75 Assembler::kMinimalBufferSize, &actual_size, true));
77 Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
79 // Assemble a simple function that copies argument 2 and returns it.
86 // Call the function from C++.
87 int result = FUNCTION_CAST<F2>(buffer)(3, 2);
92 TEST(AssemblerX64StackOperations) {
93 CcTest::InitializeVM();
94 // Allocate an executable page of memory.
96 byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
97 Assembler::kMinimalBufferSize, &actual_size, true));
99 Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
101 // Assemble a simple function that copies argument 2 and returns it.
102 // We compile without stack frame pointers, so the gdb debugger shows
103 // incorrect stack frames when debugging this function (which has them).
106 __ pushq(arg2); // Value at (rbp - 8)
107 __ pushq(arg2); // Value at (rbp - 16)
108 __ pushq(arg1); // Value at (rbp - 24)
118 // Call the function from C++.
119 int result = FUNCTION_CAST<F2>(buffer)(3, 2);
124 TEST(AssemblerX64ArithmeticOperations) {
125 CcTest::InitializeVM();
126 // Allocate an executable page of memory.
128 byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
129 Assembler::kMinimalBufferSize, &actual_size, true));
131 Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
133 // Assemble a simple function that adds arguments returning the sum.
140 // Call the function from C++.
141 int result = FUNCTION_CAST<F2>(buffer)(3, 2);
146 TEST(AssemblerX64CmpbOperation) {
147 CcTest::InitializeVM();
148 // Allocate an executable page of memory.
150 byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
151 Assembler::kMinimalBufferSize, &actual_size, true));
153 Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
155 // Assemble a function that compare argument byte returing 1 if equal else 0.
156 // On Windows, it compares rcx with rdx which does not require REX prefix;
157 // on Linux, it compares rdi with rsi which requires REX prefix.
160 __ movq(rax, Immediate(1));
163 __ movq(rax, Immediate(0));
169 // Call the function from C++.
170 int result = FUNCTION_CAST<F2>(buffer)(0x1002, 0x2002);
172 result = FUNCTION_CAST<F2>(buffer)(0x1002, 0x2003);
177 TEST(AssemblerX64ImulOperation) {
178 CcTest::InitializeVM();
179 // Allocate an executable page of memory.
181 byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
182 Assembler::kMinimalBufferSize, &actual_size, true));
184 Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
186 // Assemble a simple function that multiplies arguments returning the high
195 // Call the function from C++.
196 int result = FUNCTION_CAST<F2>(buffer)(3, 2);
198 result = FUNCTION_CAST<F2>(buffer)(0x100000000l, 0x100000000l);
200 result = FUNCTION_CAST<F2>(buffer)(-0x100000000l, 0x100000000l);
201 CHECK_EQ(-1, result);
205 TEST(AssemblerX64XchglOperations) {
206 CcTest::InitializeVM();
207 // Allocate an executable page of memory.
209 byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
210 Assembler::kMinimalBufferSize, &actual_size, true));
212 Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
214 __ movq(rax, Operand(arg1, 0));
215 __ movq(r11, Operand(arg2, 0));
217 __ movq(Operand(arg1, 0), rax);
218 __ movq(Operand(arg2, 0), r11);
223 // Call the function from C++.
224 uint64_t left = V8_2PART_UINT64_C(0x10000000, 20000000);
225 uint64_t right = V8_2PART_UINT64_C(0x30000000, 40000000);
226 uint64_t result = FUNCTION_CAST<F4>(buffer)(&left, &right);
227 CHECK_EQ(V8_2PART_UINT64_C(0x00000000, 40000000), left);
228 CHECK_EQ(V8_2PART_UINT64_C(0x00000000, 20000000), right);
233 TEST(AssemblerX64OrlOperations) {
234 CcTest::InitializeVM();
235 // Allocate an executable page of memory.
237 byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
238 Assembler::kMinimalBufferSize, &actual_size, true));
240 Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
242 __ movq(rax, Operand(arg2, 0));
243 __ orl(Operand(arg1, 0), rax);
248 // Call the function from C++.
249 uint64_t left = V8_2PART_UINT64_C(0x10000000, 20000000);
250 uint64_t right = V8_2PART_UINT64_C(0x30000000, 40000000);
251 uint64_t result = FUNCTION_CAST<F4>(buffer)(&left, &right);
252 CHECK_EQ(V8_2PART_UINT64_C(0x10000000, 60000000), left);
257 TEST(AssemblerX64RollOperations) {
258 CcTest::InitializeVM();
259 // Allocate an executable page of memory.
261 byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
262 Assembler::kMinimalBufferSize, &actual_size, true));
264 Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
267 __ roll(rax, Immediate(1));
272 // Call the function from C++.
273 uint64_t src = V8_2PART_UINT64_C(0x10000000, C0000000);
274 uint64_t result = FUNCTION_CAST<F5>(buffer)(src);
275 CHECK_EQ(V8_2PART_UINT64_C(0x00000000, 80000001), result);
279 TEST(AssemblerX64SublOperations) {
280 CcTest::InitializeVM();
281 // Allocate an executable page of memory.
283 byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
284 Assembler::kMinimalBufferSize, &actual_size, true));
286 Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
288 __ movq(rax, Operand(arg2, 0));
289 __ subl(Operand(arg1, 0), rax);
294 // Call the function from C++.
295 uint64_t left = V8_2PART_UINT64_C(0x10000000, 20000000);
296 uint64_t right = V8_2PART_UINT64_C(0x30000000, 40000000);
297 uint64_t result = FUNCTION_CAST<F4>(buffer)(&left, &right);
298 CHECK_EQ(V8_2PART_UINT64_C(0x10000000, e0000000), left);
303 TEST(AssemblerX64TestlOperations) {
304 CcTest::InitializeVM();
305 // Allocate an executable page of memory.
307 byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
308 Assembler::kMinimalBufferSize, &actual_size, true));
310 Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
312 // Set rax with the ZF flag of the testl instruction.
314 __ movq(rax, Immediate(1));
315 __ movq(r11, Operand(arg2, 0));
316 __ testl(Operand(arg1, 0), r11);
317 __ j(zero, &done, Label::kNear);
318 __ movq(rax, Immediate(0));
324 // Call the function from C++.
325 uint64_t left = V8_2PART_UINT64_C(0x10000000, 20000000);
326 uint64_t right = V8_2PART_UINT64_C(0x30000000, 00000000);
327 uint64_t result = FUNCTION_CAST<F4>(buffer)(&left, &right);
328 CHECK_EQ(1u, result);
332 TEST(AssemblerX64XorlOperations) {
333 CcTest::InitializeVM();
334 // Allocate an executable page of memory.
336 byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
337 Assembler::kMinimalBufferSize, &actual_size, true));
339 Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
341 __ movq(rax, Operand(arg2, 0));
342 __ xorl(Operand(arg1, 0), rax);
347 // Call the function from C++.
348 uint64_t left = V8_2PART_UINT64_C(0x10000000, 20000000);
349 uint64_t right = V8_2PART_UINT64_C(0x30000000, 60000000);
350 uint64_t result = FUNCTION_CAST<F4>(buffer)(&left, &right);
351 CHECK_EQ(V8_2PART_UINT64_C(0x10000000, 40000000), left);
356 TEST(AssemblerX64MemoryOperands) {
357 CcTest::InitializeVM();
358 // Allocate an executable page of memory.
360 byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
361 Assembler::kMinimalBufferSize, &actual_size, true));
363 Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
365 // Assemble a simple function that copies argument 2 and returns it.
369 __ pushq(arg2); // Value at (rbp - 8)
370 __ pushq(arg2); // Value at (rbp - 16)
371 __ pushq(arg1); // Value at (rbp - 24)
373 const int kStackElementSize = 8;
374 __ movq(rax, Operand(rbp, -3 * kStackElementSize));
384 // Call the function from C++.
385 int result = FUNCTION_CAST<F2>(buffer)(3, 2);
390 TEST(AssemblerX64ControlFlow) {
391 CcTest::InitializeVM();
392 // Allocate an executable page of memory.
394 byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
395 Assembler::kMinimalBufferSize, &actual_size, true));
397 Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
399 // Assemble a simple function that copies argument 1 and returns it.
413 // Call the function from C++.
414 int result = FUNCTION_CAST<F2>(buffer)(3, 2);
419 TEST(AssemblerX64LoopImmediates) {
420 CcTest::InitializeVM();
421 // Allocate an executable page of memory.
423 byte* buffer = static_cast<byte*>(v8::base::OS::Allocate(
424 Assembler::kMinimalBufferSize, &actual_size, true));
426 Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
427 // Assemble two loops using rax as counter, and verify the ending counts.
429 __ movq(rax, Immediate(-3));
433 __ bind(&Loop1_body);
434 __ addq(rax, Immediate(7));
435 __ bind(&Loop1_test);
436 __ cmpq(rax, Immediate(20));
437 __ j(less_equal, &Loop1_body);
438 // Did the loop terminate with the expected value?
439 __ cmpq(rax, Immediate(25));
440 __ j(not_equal, &Fail);
444 __ movq(rax, Immediate(0x11FEED00));
446 __ bind(&Loop2_body);
447 __ addq(rax, Immediate(-0x1100));
448 __ bind(&Loop2_test);
449 __ cmpq(rax, Immediate(0x11FE8000));
450 __ j(greater, &Loop2_body);
451 // Did the loop terminate with the expected value?
452 __ cmpq(rax, Immediate(0x11FE7600));
453 __ j(not_equal, &Fail);
455 __ movq(rax, Immediate(1));
458 __ movq(rax, Immediate(0));
463 // Call the function from C++.
464 int result = FUNCTION_CAST<F0>(buffer)();
469 TEST(OperandRegisterDependency) {
470 int offsets[4] = {0, 1, 0xfed, 0xbeefcad};
471 for (int i = 0; i < 4; i++) {
472 int offset = offsets[i];
473 CHECK(Operand(rax, offset).AddressUsesRegister(rax));
474 CHECK(!Operand(rax, offset).AddressUsesRegister(r8));
475 CHECK(!Operand(rax, offset).AddressUsesRegister(rcx));
477 CHECK(Operand(rax, rax, times_1, offset).AddressUsesRegister(rax));
478 CHECK(!Operand(rax, rax, times_1, offset).AddressUsesRegister(r8));
479 CHECK(!Operand(rax, rax, times_1, offset).AddressUsesRegister(rcx));
481 CHECK(Operand(rax, rcx, times_1, offset).AddressUsesRegister(rax));
482 CHECK(Operand(rax, rcx, times_1, offset).AddressUsesRegister(rcx));
483 CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(r8));
484 CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(r9));
485 CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(rdx));
486 CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(rsp));
488 CHECK(Operand(rsp, offset).AddressUsesRegister(rsp));
489 CHECK(!Operand(rsp, offset).AddressUsesRegister(rax));
490 CHECK(!Operand(rsp, offset).AddressUsesRegister(r15));
492 CHECK(Operand(rbp, offset).AddressUsesRegister(rbp));
493 CHECK(!Operand(rbp, offset).AddressUsesRegister(rax));
494 CHECK(!Operand(rbp, offset).AddressUsesRegister(r13));
496 CHECK(Operand(rbp, rax, times_1, offset).AddressUsesRegister(rbp));
497 CHECK(Operand(rbp, rax, times_1, offset).AddressUsesRegister(rax));
498 CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(rcx));
499 CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(r13));
500 CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(r8));
501 CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(rsp));
503 CHECK(Operand(rsp, rbp, times_1, offset).AddressUsesRegister(rsp));
504 CHECK(Operand(rsp, rbp, times_1, offset).AddressUsesRegister(rbp));
505 CHECK(!Operand(rsp, rbp, times_1, offset).AddressUsesRegister(rax));
506 CHECK(!Operand(rsp, rbp, times_1, offset).AddressUsesRegister(r15));
507 CHECK(!Operand(rsp, rbp, times_1, offset).AddressUsesRegister(r13));
512 TEST(AssemblerX64LabelChaining) {
513 // Test chaining of label usages within instructions (issue 1644).
514 CcTest::InitializeVM();
515 v8::HandleScope scope(CcTest::isolate());
516 Assembler assm(CcTest::i_isolate(), NULL, 0);
519 __ j(equal, &target);
520 __ j(not_equal, &target);
526 TEST(AssemblerMultiByteNop) {
527 CcTest::InitializeVM();
528 v8::HandleScope scope(CcTest::isolate());
530 Isolate* isolate = CcTest::i_isolate();
531 Assembler assm(isolate, buffer, sizeof(buffer));
537 __ movq(rax, Immediate(1));
538 __ movq(rbx, Immediate(2));
539 __ movq(rcx, Immediate(3));
540 __ movq(rdx, Immediate(4));
541 __ movq(rdi, Immediate(5));
542 __ movq(rsi, Immediate(6));
543 for (int i = 0; i < 16; i++) {
544 int before = assm.pc_offset();
546 CHECK_EQ(assm.pc_offset() - before, i);
550 __ cmpq(rax, Immediate(1));
551 __ j(not_equal, &fail);
552 __ cmpq(rbx, Immediate(2));
553 __ j(not_equal, &fail);
554 __ cmpq(rcx, Immediate(3));
555 __ j(not_equal, &fail);
556 __ cmpq(rdx, Immediate(4));
557 __ j(not_equal, &fail);
558 __ cmpq(rdi, Immediate(5));
559 __ j(not_equal, &fail);
560 __ cmpq(rsi, Immediate(6));
561 __ j(not_equal, &fail);
562 __ movq(rax, Immediate(42));
570 __ movq(rax, Immediate(13));
580 Handle<Code> code = isolate->factory()->NewCode(
581 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
583 F0 f = FUNCTION_CAST<F0>(code->entry());
590 #define ELEMENT_COUNT 4u
592 void DoSSE2(const v8::FunctionCallbackInfo<v8::Value>& args) {
593 v8::HandleScope scope(CcTest::isolate());
596 CHECK(args[0]->IsArray());
597 v8::Local<v8::Array> vec = v8::Local<v8::Array>::Cast(args[0]);
598 CHECK_EQ(ELEMENT_COUNT, vec->Length());
600 Isolate* isolate = CcTest::i_isolate();
601 Assembler assm(isolate, buffer, sizeof(buffer));
603 // Remove return address from the stack for fix stack frame alignment.
606 // Store input vector on the stack.
607 for (unsigned i = 0; i < ELEMENT_COUNT; i++) {
608 __ movl(rax, Immediate(vec->Get(i)->Int32Value()));
609 __ shlq(rax, Immediate(0x20));
610 __ orq(rax, Immediate(vec->Get(++i)->Int32Value()));
614 // Read vector into a xmm register.
615 __ xorps(xmm0, xmm0);
616 __ movdqa(xmm0, Operand(rsp, 0));
617 // Create mask and store it in the return register.
618 __ movmskps(rax, xmm0);
620 // Remove unused data from the stack.
621 __ addq(rsp, Immediate(ELEMENT_COUNT * sizeof(int32_t)));
622 // Restore return address.
629 Handle<Code> code = isolate->factory()->NewCode(
630 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
632 F0 f = FUNCTION_CAST<F0>(code->entry());
634 args.GetReturnValue().Set(v8::Integer::New(CcTest::isolate(), res));
638 TEST(StackAlignmentForSSE2) {
639 CcTest::InitializeVM();
640 CHECK_EQ(0, v8::base::OS::ActivationFrameAlignment() % 16);
642 v8::Isolate* isolate = CcTest::isolate();
643 v8::HandleScope handle_scope(isolate);
644 v8::Handle<v8::ObjectTemplate> global_template =
645 v8::ObjectTemplate::New(isolate);
646 global_template->Set(v8_str("do_sse2"),
647 v8::FunctionTemplate::New(isolate, DoSSE2));
649 LocalContext env(NULL, global_template);
651 "function foo(vec) {"
652 " return do_sse2(vec);"
655 v8::Local<v8::Object> global_object = env->Global();
656 v8::Local<v8::Function> foo =
657 v8::Local<v8::Function>::Cast(global_object->Get(v8_str("foo")));
659 int32_t vec[ELEMENT_COUNT] = { -1, 1, 1, 1 };
660 v8::Local<v8::Array> v8_vec = v8::Array::New(isolate, ELEMENT_COUNT);
661 for (unsigned i = 0; i < ELEMENT_COUNT; i++) {
662 v8_vec->Set(i, v8_num(vec[i]));
665 v8::Local<v8::Value> args[] = { v8_vec };
666 v8::Local<v8::Value> result = foo->Call(global_object, 1, args);
668 // The mask should be 0b1000.
669 CHECK_EQ(8, result->Int32Value());
676 TEST(AssemblerX64Extractps) {
677 CcTest::InitializeVM();
678 if (!CpuFeatures::IsSupported(SSE4_1)) return;
680 v8::HandleScope scope(CcTest::isolate());
682 Isolate* isolate = CcTest::i_isolate();
683 Assembler assm(isolate, buffer, sizeof(buffer));
684 { CpuFeatureScope fscope2(&assm, SSE4_1);
685 __ extractps(rax, xmm0, 0x1);
691 Handle<Code> code = isolate->factory()->NewCode(
692 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
698 F3 f = FUNCTION_CAST<F3>(code->entry());
699 uint64_t value1 = V8_2PART_UINT64_C(0x12345678, 87654321);
700 CHECK_EQ(0x12345678u, f(uint64_to_double(value1)));
701 uint64_t value2 = V8_2PART_UINT64_C(0x87654321, 12345678);
702 CHECK_EQ(0x87654321u, f(uint64_to_double(value2)));
706 typedef int (*F6)(float x, float y);
707 TEST(AssemblerX64SSE) {
708 CcTest::InitializeVM();
710 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
711 HandleScope scope(isolate);
712 v8::internal::byte buffer[256];
713 MacroAssembler assm(isolate, buffer, sizeof buffer);
715 __ shufps(xmm0, xmm0, 0x0); // brocast first argument
716 __ shufps(xmm1, xmm1, 0x0); // brocast second argument
717 __ movaps(xmm2, xmm1);
718 __ addps(xmm2, xmm0);
719 __ mulps(xmm2, xmm1);
720 __ subps(xmm2, xmm0);
721 __ divps(xmm2, xmm1);
722 __ cvttss2si(rax, xmm2);
728 Handle<Code> code = isolate->factory()->NewCode(
730 Code::ComputeFlags(Code::STUB),
737 F6 f = FUNCTION_CAST<F6>(code->entry());
738 CHECK_EQ(2, f(1.0, 2.0));
742 typedef int (*F7)(double x, double y, double z);
743 TEST(AssemblerX64FMA_sd) {
744 CcTest::InitializeVM();
745 if (!CpuFeatures::IsSupported(FMA3)) return;
747 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
748 HandleScope scope(isolate);
749 v8::internal::byte buffer[1024];
750 MacroAssembler assm(isolate, buffer, sizeof buffer);
752 CpuFeatureScope fscope(&assm, FMA3);
754 // argument in xmm0, xmm1 and xmm2
755 // xmm0 * xmm1 + xmm2
756 __ movaps(xmm3, xmm0);
757 __ mulsd(xmm3, xmm1);
758 __ addsd(xmm3, xmm2); // Expected result in xmm3
760 __ subq(rsp, Immediate(kDoubleSize)); // For memory operand
762 __ movl(rax, Immediate(1)); // Test number
763 __ movaps(xmm8, xmm0);
764 __ vfmadd132sd(xmm8, xmm2, xmm1);
765 __ ucomisd(xmm8, xmm3);
766 __ j(not_equal, &exit);
769 __ movaps(xmm8, xmm1);
770 __ vfmadd213sd(xmm8, xmm0, xmm2);
771 __ ucomisd(xmm8, xmm3);
772 __ j(not_equal, &exit);
775 __ movaps(xmm8, xmm2);
776 __ vfmadd231sd(xmm8, xmm0, xmm1);
777 __ ucomisd(xmm8, xmm3);
778 __ j(not_equal, &exit);
782 __ movaps(xmm8, xmm0);
783 __ movsd(Operand(rsp, 0), xmm1);
784 __ vfmadd132sd(xmm8, xmm2, Operand(rsp, 0));
785 __ ucomisd(xmm8, xmm3);
786 __ j(not_equal, &exit);
789 __ movaps(xmm8, xmm1);
790 __ movsd(Operand(rsp, 0), xmm2);
791 __ vfmadd213sd(xmm8, xmm0, Operand(rsp, 0));
792 __ ucomisd(xmm8, xmm3);
793 __ j(not_equal, &exit);
796 __ movaps(xmm8, xmm2);
797 __ movsd(Operand(rsp, 0), xmm1);
798 __ vfmadd231sd(xmm8, xmm0, Operand(rsp, 0));
799 __ ucomisd(xmm8, xmm3);
800 __ j(not_equal, &exit);
802 // xmm0 * xmm1 - xmm2
803 __ movaps(xmm3, xmm0);
804 __ mulsd(xmm3, xmm1);
805 __ subsd(xmm3, xmm2); // Expected result in xmm3
809 __ movaps(xmm8, xmm0);
810 __ vfmsub132sd(xmm8, xmm2, xmm1);
811 __ ucomisd(xmm8, xmm3);
812 __ j(not_equal, &exit);
815 __ movaps(xmm8, xmm1);
816 __ vfmsub213sd(xmm8, xmm0, xmm2);
817 __ ucomisd(xmm8, xmm3);
818 __ j(not_equal, &exit);
821 __ movaps(xmm8, xmm2);
822 __ vfmsub231sd(xmm8, xmm0, xmm1);
823 __ ucomisd(xmm8, xmm3);
824 __ j(not_equal, &exit);
828 __ movaps(xmm8, xmm0);
829 __ movsd(Operand(rsp, 0), xmm1);
830 __ vfmsub132sd(xmm8, xmm2, Operand(rsp, 0));
831 __ ucomisd(xmm8, xmm3);
832 __ j(not_equal, &exit);
835 __ movaps(xmm8, xmm1);
836 __ movsd(Operand(rsp, 0), xmm2);
837 __ vfmsub213sd(xmm8, xmm0, Operand(rsp, 0));
838 __ ucomisd(xmm8, xmm3);
839 __ j(not_equal, &exit);
842 __ movaps(xmm8, xmm2);
843 __ movsd(Operand(rsp, 0), xmm1);
844 __ vfmsub231sd(xmm8, xmm0, Operand(rsp, 0));
845 __ ucomisd(xmm8, xmm3);
846 __ j(not_equal, &exit);
849 // - xmm0 * xmm1 + xmm2
850 __ movaps(xmm3, xmm0);
851 __ mulsd(xmm3, xmm1);
852 __ Move(xmm4, (uint64_t)1 << 63);
853 __ xorpd(xmm3, xmm4);
854 __ addsd(xmm3, xmm2); // Expected result in xmm3
858 __ movaps(xmm8, xmm0);
859 __ vfnmadd132sd(xmm8, xmm2, xmm1);
860 __ ucomisd(xmm8, xmm3);
861 __ j(not_equal, &exit);
864 __ movaps(xmm8, xmm1);
865 __ vfnmadd213sd(xmm8, xmm0, xmm2);
866 __ ucomisd(xmm8, xmm3);
867 __ j(not_equal, &exit);
870 __ movaps(xmm8, xmm2);
871 __ vfnmadd231sd(xmm8, xmm0, xmm1);
872 __ ucomisd(xmm8, xmm3);
873 __ j(not_equal, &exit);
877 __ movaps(xmm8, xmm0);
878 __ movsd(Operand(rsp, 0), xmm1);
879 __ vfnmadd132sd(xmm8, xmm2, Operand(rsp, 0));
880 __ ucomisd(xmm8, xmm3);
881 __ j(not_equal, &exit);
884 __ movaps(xmm8, xmm1);
885 __ movsd(Operand(rsp, 0), xmm2);
886 __ vfnmadd213sd(xmm8, xmm0, Operand(rsp, 0));
887 __ ucomisd(xmm8, xmm3);
888 __ j(not_equal, &exit);
891 __ movaps(xmm8, xmm2);
892 __ movsd(Operand(rsp, 0), xmm1);
893 __ vfnmadd231sd(xmm8, xmm0, Operand(rsp, 0));
894 __ ucomisd(xmm8, xmm3);
895 __ j(not_equal, &exit);
898 // - xmm0 * xmm1 - xmm2
899 __ movaps(xmm3, xmm0);
900 __ mulsd(xmm3, xmm1);
901 __ Move(xmm4, (uint64_t)1 << 63);
902 __ xorpd(xmm3, xmm4);
903 __ subsd(xmm3, xmm2); // Expected result in xmm3
907 __ movaps(xmm8, xmm0);
908 __ vfnmsub132sd(xmm8, xmm2, xmm1);
909 __ ucomisd(xmm8, xmm3);
910 __ j(not_equal, &exit);
913 __ movaps(xmm8, xmm1);
914 __ vfnmsub213sd(xmm8, xmm0, xmm2);
915 __ ucomisd(xmm8, xmm3);
916 __ j(not_equal, &exit);
919 __ movaps(xmm8, xmm2);
920 __ vfnmsub231sd(xmm8, xmm0, xmm1);
921 __ ucomisd(xmm8, xmm3);
922 __ j(not_equal, &exit);
926 __ movaps(xmm8, xmm0);
927 __ movsd(Operand(rsp, 0), xmm1);
928 __ vfnmsub132sd(xmm8, xmm2, Operand(rsp, 0));
929 __ ucomisd(xmm8, xmm3);
930 __ j(not_equal, &exit);
933 __ movaps(xmm8, xmm1);
934 __ movsd(Operand(rsp, 0), xmm2);
935 __ vfnmsub213sd(xmm8, xmm0, Operand(rsp, 0));
936 __ ucomisd(xmm8, xmm3);
937 __ j(not_equal, &exit);
940 __ movaps(xmm8, xmm2);
941 __ movsd(Operand(rsp, 0), xmm1);
942 __ vfnmsub231sd(xmm8, xmm0, Operand(rsp, 0));
943 __ ucomisd(xmm8, xmm3);
944 __ j(not_equal, &exit);
949 __ addq(rsp, Immediate(kDoubleSize));
955 Handle<Code> code = isolate->factory()->NewCode(
956 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
962 F7 f = FUNCTION_CAST<F7>(code->entry());
963 CHECK_EQ(0, f(0.000092662107262076, -2.460774966188315, -1.0958787393627414));
967 typedef int (*F8)(float x, float y, float z);
968 TEST(AssemblerX64FMA_ss) {
969 CcTest::InitializeVM();
970 if (!CpuFeatures::IsSupported(FMA3)) return;
972 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
973 HandleScope scope(isolate);
974 v8::internal::byte buffer[1024];
975 MacroAssembler assm(isolate, buffer, sizeof buffer);
977 CpuFeatureScope fscope(&assm, FMA3);
979 // arguments in xmm0, xmm1 and xmm2
980 // xmm0 * xmm1 + xmm2
981 __ movaps(xmm3, xmm0);
982 __ mulss(xmm3, xmm1);
983 __ addss(xmm3, xmm2); // Expected result in xmm3
985 __ subq(rsp, Immediate(kDoubleSize)); // For memory operand
987 __ movl(rax, Immediate(1)); // Test number
988 __ movaps(xmm8, xmm0);
989 __ vfmadd132ss(xmm8, xmm2, xmm1);
990 __ ucomiss(xmm8, xmm3);
991 __ j(not_equal, &exit);
994 __ movaps(xmm8, xmm1);
995 __ vfmadd213ss(xmm8, xmm0, xmm2);
996 __ ucomiss(xmm8, xmm3);
997 __ j(not_equal, &exit);
1000 __ movaps(xmm8, xmm2);
1001 __ vfmadd231ss(xmm8, xmm0, xmm1);
1002 __ ucomiss(xmm8, xmm3);
1003 __ j(not_equal, &exit);
1007 __ movaps(xmm8, xmm0);
1008 __ movss(Operand(rsp, 0), xmm1);
1009 __ vfmadd132ss(xmm8, xmm2, Operand(rsp, 0));
1010 __ ucomiss(xmm8, xmm3);
1011 __ j(not_equal, &exit);
1014 __ movaps(xmm8, xmm1);
1015 __ movss(Operand(rsp, 0), xmm2);
1016 __ vfmadd213ss(xmm8, xmm0, Operand(rsp, 0));
1017 __ ucomiss(xmm8, xmm3);
1018 __ j(not_equal, &exit);
1021 __ movaps(xmm8, xmm2);
1022 __ movss(Operand(rsp, 0), xmm1);
1023 __ vfmadd231ss(xmm8, xmm0, Operand(rsp, 0));
1024 __ ucomiss(xmm8, xmm3);
1025 __ j(not_equal, &exit);
1027 // xmm0 * xmm1 - xmm2
1028 __ movaps(xmm3, xmm0);
1029 __ mulss(xmm3, xmm1);
1030 __ subss(xmm3, xmm2); // Expected result in xmm3
1034 __ movaps(xmm8, xmm0);
1035 __ vfmsub132ss(xmm8, xmm2, xmm1);
1036 __ ucomiss(xmm8, xmm3);
1037 __ j(not_equal, &exit);
1040 __ movaps(xmm8, xmm1);
1041 __ vfmsub213ss(xmm8, xmm0, xmm2);
1042 __ ucomiss(xmm8, xmm3);
1043 __ j(not_equal, &exit);
1046 __ movaps(xmm8, xmm2);
1047 __ vfmsub231ss(xmm8, xmm0, xmm1);
1048 __ ucomiss(xmm8, xmm3);
1049 __ j(not_equal, &exit);
1053 __ movaps(xmm8, xmm0);
1054 __ movss(Operand(rsp, 0), xmm1);
1055 __ vfmsub132ss(xmm8, xmm2, Operand(rsp, 0));
1056 __ ucomiss(xmm8, xmm3);
1057 __ j(not_equal, &exit);
1060 __ movaps(xmm8, xmm1);
1061 __ movss(Operand(rsp, 0), xmm2);
1062 __ vfmsub213ss(xmm8, xmm0, Operand(rsp, 0));
1063 __ ucomiss(xmm8, xmm3);
1064 __ j(not_equal, &exit);
1067 __ movaps(xmm8, xmm2);
1068 __ movss(Operand(rsp, 0), xmm1);
1069 __ vfmsub231ss(xmm8, xmm0, Operand(rsp, 0));
1070 __ ucomiss(xmm8, xmm3);
1071 __ j(not_equal, &exit);
1074 // - xmm0 * xmm1 + xmm2
1075 __ movaps(xmm3, xmm0);
1076 __ mulss(xmm3, xmm1);
1077 __ Move(xmm4, (uint32_t)1 << 31);
1078 __ xorps(xmm3, xmm4);
1079 __ addss(xmm3, xmm2); // Expected result in xmm3
1083 __ movaps(xmm8, xmm0);
1084 __ vfnmadd132ss(xmm8, xmm2, xmm1);
1085 __ ucomiss(xmm8, xmm3);
1086 __ j(not_equal, &exit);
1089 __ movaps(xmm8, xmm1);
1090 __ vfnmadd213ss(xmm8, xmm0, xmm2);
1091 __ ucomiss(xmm8, xmm3);
1092 __ j(not_equal, &exit);
1095 __ movaps(xmm8, xmm2);
1096 __ vfnmadd231ss(xmm8, xmm0, xmm1);
1097 __ ucomiss(xmm8, xmm3);
1098 __ j(not_equal, &exit);
1102 __ movaps(xmm8, xmm0);
1103 __ movss(Operand(rsp, 0), xmm1);
1104 __ vfnmadd132ss(xmm8, xmm2, Operand(rsp, 0));
1105 __ ucomiss(xmm8, xmm3);
1106 __ j(not_equal, &exit);
1109 __ movaps(xmm8, xmm1);
1110 __ movss(Operand(rsp, 0), xmm2);
1111 __ vfnmadd213ss(xmm8, xmm0, Operand(rsp, 0));
1112 __ ucomiss(xmm8, xmm3);
1113 __ j(not_equal, &exit);
1116 __ movaps(xmm8, xmm2);
1117 __ movss(Operand(rsp, 0), xmm1);
1118 __ vfnmadd231ss(xmm8, xmm0, Operand(rsp, 0));
1119 __ ucomiss(xmm8, xmm3);
1120 __ j(not_equal, &exit);
1123 // - xmm0 * xmm1 - xmm2
1124 __ movaps(xmm3, xmm0);
1125 __ mulss(xmm3, xmm1);
1126 __ Move(xmm4, (uint32_t)1 << 31);
1127 __ xorps(xmm3, xmm4);
1128 __ subss(xmm3, xmm2); // Expected result in xmm3
1132 __ movaps(xmm8, xmm0);
1133 __ vfnmsub132ss(xmm8, xmm2, xmm1);
1134 __ ucomiss(xmm8, xmm3);
1135 __ j(not_equal, &exit);
1138 __ movaps(xmm8, xmm1);
1139 __ vfnmsub213ss(xmm8, xmm0, xmm2);
1140 __ ucomiss(xmm8, xmm3);
1141 __ j(not_equal, &exit);
1144 __ movaps(xmm8, xmm2);
1145 __ vfnmsub231ss(xmm8, xmm0, xmm1);
1146 __ ucomiss(xmm8, xmm3);
1147 __ j(not_equal, &exit);
1151 __ movaps(xmm8, xmm0);
1152 __ movss(Operand(rsp, 0), xmm1);
1153 __ vfnmsub132ss(xmm8, xmm2, Operand(rsp, 0));
1154 __ ucomiss(xmm8, xmm3);
1155 __ j(not_equal, &exit);
1158 __ movaps(xmm8, xmm1);
1159 __ movss(Operand(rsp, 0), xmm2);
1160 __ vfnmsub213ss(xmm8, xmm0, Operand(rsp, 0));
1161 __ ucomiss(xmm8, xmm3);
1162 __ j(not_equal, &exit);
1165 __ movaps(xmm8, xmm2);
1166 __ movss(Operand(rsp, 0), xmm1);
1167 __ vfnmsub231ss(xmm8, xmm0, Operand(rsp, 0));
1168 __ ucomiss(xmm8, xmm3);
1169 __ j(not_equal, &exit);
1174 __ addq(rsp, Immediate(kDoubleSize));
1179 assm.GetCode(&desc);
1180 Handle<Code> code = isolate->factory()->NewCode(
1181 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
1183 OFStream os(stdout);
1187 F8 f = FUNCTION_CAST<F8>(code->entry());
1188 CHECK_EQ(0, f(9.26621069e-05f, -2.4607749f, -1.09587872f));
1192 TEST(AssemblerX64JumpTables1) {
1193 // Test jump tables with forward jumps.
1194 CcTest::InitializeVM();
1195 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
1196 HandleScope scope(isolate);
1197 MacroAssembler assm(isolate, nullptr, 0);
1199 const int kNumCases = 512;
1200 int values[kNumCases];
1201 isolate->random_number_generator()->NextBytes(values, sizeof(values));
1202 Label labels[kNumCases];
1205 __ leaq(arg2, Operand(&table));
1206 __ jmp(Operand(arg2, arg1, times_8, 0));
1209 for (int i = 0; i < kNumCases; ++i) {
1213 for (int i = 0; i < kNumCases; ++i) {
1214 __ bind(&labels[i]);
1215 __ movq(rax, Immediate(values[i]));
1223 assm.GetCode(&desc);
1224 Handle<Code> code = isolate->factory()->NewCode(
1225 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
1227 code->Print(std::cout);
1230 F1 f = FUNCTION_CAST<F1>(code->entry());
1231 for (int i = 0; i < kNumCases; ++i) {
1233 PrintF("f(%d) = %d\n", i, res);
1234 CHECK_EQ(values[i], res);
1239 TEST(AssemblerX64JumpTables2) {
1240 // Test jump tables with backwards jumps.
1241 CcTest::InitializeVM();
1242 Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
1243 HandleScope scope(isolate);
1244 MacroAssembler assm(isolate, nullptr, 0);
1246 const int kNumCases = 512;
1247 int values[kNumCases];
1248 isolate->random_number_generator()->NextBytes(values, sizeof(values));
1249 Label labels[kNumCases];
1252 __ leaq(arg2, Operand(&table));
1253 __ jmp(Operand(arg2, arg1, times_8, 0));
1256 for (int i = 0; i < kNumCases; ++i) {
1257 __ bind(&labels[i]);
1258 __ movq(rax, Immediate(values[i]));
1266 for (int i = 0; i < kNumCases; ++i) {
1271 assm.GetCode(&desc);
1272 Handle<Code> code = isolate->factory()->NewCode(
1273 desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
1275 code->Print(std::cout);
1278 F1 f = FUNCTION_CAST<F1>(code->entry());
1279 for (int i = 0; i < kNumCases; ++i) {
1281 PrintF("f(%d) = %d\n", i, res);
1282 CHECK_EQ(values[i], res);