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 <stdlib.h>
29
30#include "v8.h"
31
32#include "macro-assembler.h"
33#include "factory.h"
34#include "platform.h"
35#include "serialize.h"
36#include "cctest.h"
37
38using namespace v8::internal;
39
40// Test the x64 assembler by compiling some simple functions into
41// a buffer and executing them.  These tests do not initialize the
42// V8 library, create a context, or use any V8 objects.
43// The AMD64 calling convention is used, with the first six arguments
44// in RDI, RSI, RDX, RCX, R8, and R9, and floating point arguments in
45// the XMM registers.  The return value is in RAX.
46// This calling convention is used on Linux, with GCC, and on Mac OS,
47// with GCC.  A different convention is used on 64-bit windows,
48// where the first four integer arguments are passed in RCX, RDX, R8 and R9.
49
50typedef int (*F0)();
51typedef int (*F1)(int64_t x);
52typedef int (*F2)(int64_t x, int64_t y);
53typedef int (*F3)(double x);
54typedef int64_t (*F4)(int64_t* x, int64_t* y);
55typedef int64_t (*F5)(int64_t x);
56
57#ifdef _WIN64
58static const Register arg1 = rcx;
59static const Register arg2 = rdx;
60#else
61static const Register arg1 = rdi;
62static const Register arg2 = rsi;
63#endif
64
65#define __ assm.
66
67
68TEST(AssemblerX64ReturnOperation) {
69  // Allocate an executable page of memory.
70  size_t actual_size;
71  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
72                                                 &actual_size,
73                                                 true));
74  CHECK(buffer);
75  Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
76
77  // Assemble a simple function that copies argument 2 and returns it.
78  __ movq(rax, arg2);
79  __ nop();
80  __ ret(0);
81
82  CodeDesc desc;
83  assm.GetCode(&desc);
84  // Call the function from C++.
85  int result =  FUNCTION_CAST<F2>(buffer)(3, 2);
86  CHECK_EQ(2, result);
87}
88
89
90TEST(AssemblerX64StackOperations) {
91  // Allocate an executable page of memory.
92  size_t actual_size;
93  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
94                                                 &actual_size,
95                                                 true));
96  CHECK(buffer);
97  Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
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  __ push(rbp);
103  __ movq(rbp, rsp);
104  __ push(arg2);  // Value at (rbp - 8)
105  __ push(arg2);  // Value at (rbp - 16)
106  __ push(arg1);  // Value at (rbp - 24)
107  __ pop(rax);
108  __ pop(rax);
109  __ pop(rax);
110  __ pop(rbp);
111  __ nop();
112  __ ret(0);
113
114  CodeDesc desc;
115  assm.GetCode(&desc);
116  // Call the function from C++.
117  int result =  FUNCTION_CAST<F2>(buffer)(3, 2);
118  CHECK_EQ(2, result);
119}
120
121
122TEST(AssemblerX64ArithmeticOperations) {
123  // Allocate an executable page of memory.
124  size_t actual_size;
125  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
126                                                 &actual_size,
127                                                 true));
128  CHECK(buffer);
129  Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
130
131  // Assemble a simple function that adds arguments returning the sum.
132  __ movq(rax, arg2);
133  __ addq(rax, arg1);
134  __ ret(0);
135
136  CodeDesc desc;
137  assm.GetCode(&desc);
138  // Call the function from C++.
139  int result =  FUNCTION_CAST<F2>(buffer)(3, 2);
140  CHECK_EQ(5, result);
141}
142
143
144TEST(AssemblerX64ImulOperation) {
145  // Allocate an executable page of memory.
146  size_t actual_size;
147  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
148                                                 &actual_size,
149                                                 true));
150  CHECK(buffer);
151  Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
152
153  // Assemble a simple function that multiplies arguments returning the high
154  // word.
155  __ movq(rax, arg2);
156  __ imul(arg1);
157  __ movq(rax, rdx);
158  __ ret(0);
159
160  CodeDesc desc;
161  assm.GetCode(&desc);
162  // Call the function from C++.
163  int result =  FUNCTION_CAST<F2>(buffer)(3, 2);
164  CHECK_EQ(0, result);
165  result =  FUNCTION_CAST<F2>(buffer)(0x100000000l, 0x100000000l);
166  CHECK_EQ(1, result);
167  result =  FUNCTION_CAST<F2>(buffer)(-0x100000000l, 0x100000000l);
168  CHECK_EQ(-1, result);
169}
170
171
172TEST(AssemblerX64XchglOperations) {
173  // Allocate an executable page of memory.
174  size_t actual_size;
175  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
176                                                 &actual_size,
177                                                 true));
178  CHECK(buffer);
179  Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
180
181  __ movq(rax, Operand(arg1, 0));
182  __ movq(rbx, Operand(arg2, 0));
183  __ xchgl(rax, rbx);
184  __ movq(Operand(arg1, 0), rax);
185  __ movq(Operand(arg2, 0), rbx);
186  __ ret(0);
187
188  CodeDesc desc;
189  assm.GetCode(&desc);
190  // Call the function from C++.
191  int64_t left   = V8_2PART_UINT64_C(0x10000000, 20000000);
192  int64_t right  = V8_2PART_UINT64_C(0x30000000, 40000000);
193  int64_t result = FUNCTION_CAST<F4>(buffer)(&left, &right);
194  CHECK_EQ(V8_2PART_UINT64_C(0x00000000, 40000000), left);
195  CHECK_EQ(V8_2PART_UINT64_C(0x00000000, 20000000), right);
196  USE(result);
197}
198
199
200TEST(AssemblerX64OrlOperations) {
201  // Allocate an executable page of memory.
202  size_t actual_size;
203  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
204                                                 &actual_size,
205                                                 true));
206  CHECK(buffer);
207  Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
208
209  __ movq(rax, Operand(arg2, 0));
210  __ orl(Operand(arg1, 0), rax);
211  __ ret(0);
212
213  CodeDesc desc;
214  assm.GetCode(&desc);
215  // Call the function from C++.
216  int64_t left   = V8_2PART_UINT64_C(0x10000000, 20000000);
217  int64_t right  = V8_2PART_UINT64_C(0x30000000, 40000000);
218  int64_t result = FUNCTION_CAST<F4>(buffer)(&left, &right);
219  CHECK_EQ(V8_2PART_UINT64_C(0x10000000, 60000000), left);
220  USE(result);
221}
222
223
224TEST(AssemblerX64RollOperations) {
225  // Allocate an executable page of memory.
226  size_t actual_size;
227  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
228                                                 &actual_size,
229                                                 true));
230  CHECK(buffer);
231  Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
232
233  __ movq(rax, arg1);
234  __ roll(rax, Immediate(1));
235  __ ret(0);
236
237  CodeDesc desc;
238  assm.GetCode(&desc);
239  // Call the function from C++.
240  int64_t src    = V8_2PART_UINT64_C(0x10000000, C0000000);
241  int64_t result = FUNCTION_CAST<F5>(buffer)(src);
242  CHECK_EQ(V8_2PART_UINT64_C(0x00000000, 80000001), result);
243}
244
245
246TEST(AssemblerX64SublOperations) {
247  // Allocate an executable page of memory.
248  size_t actual_size;
249  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
250                                                 &actual_size,
251                                                 true));
252  CHECK(buffer);
253  Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
254
255  __ movq(rax, Operand(arg2, 0));
256  __ subl(Operand(arg1, 0), rax);
257  __ ret(0);
258
259  CodeDesc desc;
260  assm.GetCode(&desc);
261  // Call the function from C++.
262  int64_t left   = V8_2PART_UINT64_C(0x10000000, 20000000);
263  int64_t right  = V8_2PART_UINT64_C(0x30000000, 40000000);
264  int64_t result = FUNCTION_CAST<F4>(buffer)(&left, &right);
265  CHECK_EQ(V8_2PART_UINT64_C(0x10000000, e0000000), left);
266  USE(result);
267}
268
269
270TEST(AssemblerX64TestlOperations) {
271  // Allocate an executable page of memory.
272  size_t actual_size;
273  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
274                                                 &actual_size,
275                                                 true));
276  CHECK(buffer);
277  Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
278
279  // Set rax with the ZF flag of the testl instruction.
280  Label done;
281  __ movq(rax, Immediate(1));
282  __ movq(rbx, Operand(arg2, 0));
283  __ testl(Operand(arg1, 0), rbx);
284  __ j(zero, &done, Label::kNear);
285  __ movq(rax, Immediate(0));
286  __ bind(&done);
287  __ ret(0);
288
289  CodeDesc desc;
290  assm.GetCode(&desc);
291  // Call the function from C++.
292  int64_t left   = V8_2PART_UINT64_C(0x10000000, 20000000);
293  int64_t right  = V8_2PART_UINT64_C(0x30000000, 00000000);
294  int64_t result = FUNCTION_CAST<F4>(buffer)(&left, &right);
295  CHECK_EQ(static_cast<int64_t>(1), result);
296}
297
298
299TEST(AssemblerX64XorlOperations) {
300  // Allocate an executable page of memory.
301  size_t actual_size;
302  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
303                                                 &actual_size,
304                                                 true));
305  CHECK(buffer);
306  Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
307
308  __ movq(rax, Operand(arg2, 0));
309  __ xorl(Operand(arg1, 0), rax);
310  __ ret(0);
311
312  CodeDesc desc;
313  assm.GetCode(&desc);
314  // Call the function from C++.
315  int64_t left   = V8_2PART_UINT64_C(0x10000000, 20000000);
316  int64_t right  = V8_2PART_UINT64_C(0x30000000, 60000000);
317  int64_t result = FUNCTION_CAST<F4>(buffer)(&left, &right);
318  CHECK_EQ(V8_2PART_UINT64_C(0x10000000, 40000000), left);
319  USE(result);
320}
321
322
323TEST(AssemblerX64MemoryOperands) {
324  // Allocate an executable page of memory.
325  size_t actual_size;
326  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
327                                                 &actual_size,
328                                                 true));
329  CHECK(buffer);
330  Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
331
332  // Assemble a simple function that copies argument 2 and returns it.
333  __ push(rbp);
334  __ movq(rbp, rsp);
335
336  __ push(arg2);  // Value at (rbp - 8)
337  __ push(arg2);  // Value at (rbp - 16)
338  __ push(arg1);  // Value at (rbp - 24)
339
340  const int kStackElementSize = 8;
341  __ movq(rax, Operand(rbp, -3 * kStackElementSize));
342  __ pop(arg2);
343  __ pop(arg2);
344  __ pop(arg2);
345  __ pop(rbp);
346  __ nop();
347  __ ret(0);
348
349  CodeDesc desc;
350  assm.GetCode(&desc);
351  // Call the function from C++.
352  int result =  FUNCTION_CAST<F2>(buffer)(3, 2);
353  CHECK_EQ(3, result);
354}
355
356
357TEST(AssemblerX64ControlFlow) {
358  // Allocate an executable page of memory.
359  size_t actual_size;
360  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
361                                                 &actual_size,
362                                                 true));
363  CHECK(buffer);
364  Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
365
366  // Assemble a simple function that copies argument 1 and returns it.
367  __ push(rbp);
368
369  __ movq(rbp, rsp);
370  __ movq(rax, arg1);
371  Label target;
372  __ jmp(&target);
373  __ movq(rax, arg2);
374  __ bind(&target);
375  __ pop(rbp);
376  __ ret(0);
377
378  CodeDesc desc;
379  assm.GetCode(&desc);
380  // Call the function from C++.
381  int result =  FUNCTION_CAST<F2>(buffer)(3, 2);
382  CHECK_EQ(3, result);
383}
384
385
386TEST(AssemblerX64LoopImmediates) {
387  // Allocate an executable page of memory.
388  size_t actual_size;
389  byte* buffer = static_cast<byte*>(OS::Allocate(Assembler::kMinimalBufferSize,
390                                                 &actual_size,
391                                                 true));
392  CHECK(buffer);
393  Assembler assm(CcTest::i_isolate(), buffer, static_cast<int>(actual_size));
394  // Assemble two loops using rax as counter, and verify the ending counts.
395  Label Fail;
396  __ movq(rax, Immediate(-3));
397  Label Loop1_test;
398  Label Loop1_body;
399  __ jmp(&Loop1_test);
400  __ bind(&Loop1_body);
401  __ addq(rax, Immediate(7));
402  __ bind(&Loop1_test);
403  __ cmpq(rax, Immediate(20));
404  __ j(less_equal, &Loop1_body);
405  // Did the loop terminate with the expected value?
406  __ cmpq(rax, Immediate(25));
407  __ j(not_equal, &Fail);
408
409  Label Loop2_test;
410  Label Loop2_body;
411  __ movq(rax, Immediate(0x11FEED00));
412  __ jmp(&Loop2_test);
413  __ bind(&Loop2_body);
414  __ addq(rax, Immediate(-0x1100));
415  __ bind(&Loop2_test);
416  __ cmpq(rax, Immediate(0x11FE8000));
417  __ j(greater, &Loop2_body);
418  // Did the loop terminate with the expected value?
419  __ cmpq(rax, Immediate(0x11FE7600));
420  __ j(not_equal, &Fail);
421
422  __ movq(rax, Immediate(1));
423  __ ret(0);
424  __ bind(&Fail);
425  __ movq(rax, Immediate(0));
426  __ ret(0);
427
428  CodeDesc desc;
429  assm.GetCode(&desc);
430  // Call the function from C++.
431  int result =  FUNCTION_CAST<F0>(buffer)();
432  CHECK_EQ(1, result);
433}
434
435
436TEST(OperandRegisterDependency) {
437  int offsets[4] = {0, 1, 0xfed, 0xbeefcad};
438  for (int i = 0; i < 4; i++) {
439    int offset = offsets[i];
440    CHECK(Operand(rax, offset).AddressUsesRegister(rax));
441    CHECK(!Operand(rax, offset).AddressUsesRegister(r8));
442    CHECK(!Operand(rax, offset).AddressUsesRegister(rcx));
443
444    CHECK(Operand(rax, rax, times_1, offset).AddressUsesRegister(rax));
445    CHECK(!Operand(rax, rax, times_1, offset).AddressUsesRegister(r8));
446    CHECK(!Operand(rax, rax, times_1, offset).AddressUsesRegister(rcx));
447
448    CHECK(Operand(rax, rcx, times_1, offset).AddressUsesRegister(rax));
449    CHECK(Operand(rax, rcx, times_1, offset).AddressUsesRegister(rcx));
450    CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(r8));
451    CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(r9));
452    CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(rdx));
453    CHECK(!Operand(rax, rcx, times_1, offset).AddressUsesRegister(rsp));
454
455    CHECK(Operand(rsp, offset).AddressUsesRegister(rsp));
456    CHECK(!Operand(rsp, offset).AddressUsesRegister(rax));
457    CHECK(!Operand(rsp, offset).AddressUsesRegister(r15));
458
459    CHECK(Operand(rbp, offset).AddressUsesRegister(rbp));
460    CHECK(!Operand(rbp, offset).AddressUsesRegister(rax));
461    CHECK(!Operand(rbp, offset).AddressUsesRegister(r13));
462
463    CHECK(Operand(rbp, rax, times_1, offset).AddressUsesRegister(rbp));
464    CHECK(Operand(rbp, rax, times_1, offset).AddressUsesRegister(rax));
465    CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(rcx));
466    CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(r13));
467    CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(r8));
468    CHECK(!Operand(rbp, rax, times_1, offset).AddressUsesRegister(rsp));
469
470    CHECK(Operand(rsp, rbp, times_1, offset).AddressUsesRegister(rsp));
471    CHECK(Operand(rsp, rbp, times_1, offset).AddressUsesRegister(rbp));
472    CHECK(!Operand(rsp, rbp, times_1, offset).AddressUsesRegister(rax));
473    CHECK(!Operand(rsp, rbp, times_1, offset).AddressUsesRegister(r15));
474    CHECK(!Operand(rsp, rbp, times_1, offset).AddressUsesRegister(r13));
475  }
476}
477
478
479TEST(AssemblerX64LabelChaining) {
480  // Test chaining of label usages within instructions (issue 1644).
481  CcTest::InitializeVM();
482  v8::HandleScope scope(CcTest::isolate());
483  Assembler assm(CcTest::i_isolate(), NULL, 0);
484
485  Label target;
486  __ j(equal, &target);
487  __ j(not_equal, &target);
488  __ bind(&target);
489  __ nop();
490}
491
492
493TEST(AssemblerMultiByteNop) {
494  CcTest::InitializeVM();
495  v8::HandleScope scope(CcTest::isolate());
496  byte buffer[1024];
497  Isolate* isolate = CcTest::i_isolate();
498  Assembler assm(isolate, buffer, sizeof(buffer));
499  __ push(rbx);
500  __ push(rcx);
501  __ push(rdx);
502  __ push(rdi);
503  __ push(rsi);
504  __ movq(rax, Immediate(1));
505  __ movq(rbx, Immediate(2));
506  __ movq(rcx, Immediate(3));
507  __ movq(rdx, Immediate(4));
508  __ movq(rdi, Immediate(5));
509  __ movq(rsi, Immediate(6));
510  for (int i = 0; i < 16; i++) {
511    int before = assm.pc_offset();
512    __ Nop(i);
513    CHECK_EQ(assm.pc_offset() - before, i);
514  }
515
516  Label fail;
517  __ cmpq(rax, Immediate(1));
518  __ j(not_equal, &fail);
519  __ cmpq(rbx, Immediate(2));
520  __ j(not_equal, &fail);
521  __ cmpq(rcx, Immediate(3));
522  __ j(not_equal, &fail);
523  __ cmpq(rdx, Immediate(4));
524  __ j(not_equal, &fail);
525  __ cmpq(rdi, Immediate(5));
526  __ j(not_equal, &fail);
527  __ cmpq(rsi, Immediate(6));
528  __ j(not_equal, &fail);
529  __ movq(rax, Immediate(42));
530  __ pop(rsi);
531  __ pop(rdi);
532  __ pop(rdx);
533  __ pop(rcx);
534  __ pop(rbx);
535  __ ret(0);
536  __ bind(&fail);
537  __ movq(rax, Immediate(13));
538  __ pop(rsi);
539  __ pop(rdi);
540  __ pop(rdx);
541  __ pop(rcx);
542  __ pop(rbx);
543  __ ret(0);
544
545  CodeDesc desc;
546  assm.GetCode(&desc);
547  Code* code = Code::cast(isolate->heap()->CreateCode(
548      desc,
549      Code::ComputeFlags(Code::STUB),
550      Handle<Code>())->ToObjectChecked());
551  CHECK(code->IsCode());
552
553  F0 f = FUNCTION_CAST<F0>(code->entry());
554  int res = f();
555  CHECK_EQ(42, res);
556}
557
558
559#ifdef __GNUC__
560#define ELEMENT_COUNT 4
561
562void DoSSE2(const v8::FunctionCallbackInfo<v8::Value>& args) {
563  v8::HandleScope scope(CcTest::isolate());
564  byte buffer[1024];
565
566  CHECK(args[0]->IsArray());
567  v8::Local<v8::Array> vec = v8::Local<v8::Array>::Cast(args[0]);
568  CHECK_EQ(ELEMENT_COUNT, vec->Length());
569
570  Isolate* isolate = CcTest::i_isolate();
571  Assembler assm(isolate, buffer, sizeof(buffer));
572
573  // Remove return address from the stack for fix stack frame alignment.
574  __ pop(rcx);
575
576  // Store input vector on the stack.
577  for (int i = 0; i < ELEMENT_COUNT; i++) {
578    __ movl(rax, Immediate(vec->Get(i)->Int32Value()));
579    __ shl(rax, Immediate(0x20));
580    __ or_(rax, Immediate(vec->Get(++i)->Int32Value()));
581    __ push(rax);
582  }
583
584  // Read vector into a xmm register.
585  __ xorps(xmm0, xmm0);
586  __ movdqa(xmm0, Operand(rsp, 0));
587  // Create mask and store it in the return register.
588  __ movmskps(rax, xmm0);
589
590  // Remove unused data from the stack.
591  __ addq(rsp, Immediate(ELEMENT_COUNT * sizeof(int32_t)));
592  // Restore return address.
593  __ push(rcx);
594
595  __ ret(0);
596
597  CodeDesc desc;
598  assm.GetCode(&desc);
599  Code* code = Code::cast(isolate->heap()->CreateCode(
600      desc,
601      Code::ComputeFlags(Code::STUB),
602      Handle<Code>())->ToObjectChecked());
603  CHECK(code->IsCode());
604
605  F0 f = FUNCTION_CAST<F0>(code->entry());
606  int res = f();
607  args.GetReturnValue().Set(v8::Integer::New(res));
608}
609
610
611TEST(StackAlignmentForSSE2) {
612  CcTest::InitializeVM();
613  CHECK_EQ(0, OS::ActivationFrameAlignment() % 16);
614
615  v8::Isolate* isolate = CcTest::isolate();
616  v8::HandleScope handle_scope(isolate);
617  v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
618  global_template->Set(v8_str("do_sse2"), v8::FunctionTemplate::New(DoSSE2));
619
620  LocalContext env(NULL, global_template);
621  CompileRun(
622      "function foo(vec) {"
623      "  return do_sse2(vec);"
624      "}");
625
626  v8::Local<v8::Object> global_object = env->Global();
627  v8::Local<v8::Function> foo =
628      v8::Local<v8::Function>::Cast(global_object->Get(v8_str("foo")));
629
630  int32_t vec[ELEMENT_COUNT] = { -1, 1, 1, 1 };
631  v8::Local<v8::Array> v8_vec = v8::Array::New(isolate, ELEMENT_COUNT);
632  for (int i = 0; i < ELEMENT_COUNT; i++) {
633    v8_vec->Set(i, v8_num(vec[i]));
634  }
635
636  v8::Local<v8::Value> args[] = { v8_vec };
637  v8::Local<v8::Value> result = foo->Call(global_object, 1, args);
638
639  // The mask should be 0b1000.
640  CHECK_EQ(8, result->Int32Value());
641}
642
643#undef ELEMENT_COUNT
644#endif  // __GNUC__
645
646
647TEST(AssemblerX64Extractps) {
648  CcTest::InitializeVM();
649  if (!CpuFeatures::IsSupported(SSE4_1)) return;
650
651  v8::HandleScope scope(CcTest::isolate());
652  byte buffer[256];
653  Isolate* isolate = CcTest::i_isolate();
654  Assembler assm(isolate, buffer, sizeof(buffer));
655  { CpuFeatureScope fscope2(&assm, SSE4_1);
656    __ extractps(rax, xmm0, 0x1);
657    __ ret(0);
658  }
659
660  CodeDesc desc;
661  assm.GetCode(&desc);
662  Code* code = Code::cast(isolate->heap()->CreateCode(
663      desc,
664      Code::ComputeFlags(Code::STUB),
665      Handle<Code>())->ToObjectChecked());
666  CHECK(code->IsCode());
667#ifdef OBJECT_PRINT
668  Code::cast(code)->Print();
669#endif
670
671  F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
672  uint64_t value1 = V8_2PART_UINT64_C(0x12345678, 87654321);
673  CHECK_EQ(0x12345678, f(uint64_to_double(value1)));
674  uint64_t value2 = V8_2PART_UINT64_C(0x87654321, 12345678);
675  CHECK_EQ(0x87654321, f(uint64_to_double(value2)));
676}
677
678
679typedef int (*F6)(float x, float y);
680TEST(AssemblerX64SSE) {
681  CcTest::InitializeVM();
682
683  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
684  HandleScope scope(isolate);
685  v8::internal::byte buffer[256];
686  MacroAssembler assm(isolate, buffer, sizeof buffer);
687  {
688    __ shufps(xmm0, xmm0, 0x0);  // brocast first argument
689    __ shufps(xmm1, xmm1, 0x0);  // brocast second argument
690    __ movaps(xmm2, xmm1);
691    __ addps(xmm2, xmm0);
692    __ mulps(xmm2, xmm1);
693    __ subps(xmm2, xmm0);
694    __ divps(xmm2, xmm1);
695    __ cvttss2si(rax, xmm2);
696    __ ret(0);
697  }
698
699  CodeDesc desc;
700  assm.GetCode(&desc);
701  Code* code = Code::cast(isolate->heap()->CreateCode(
702      desc,
703      Code::ComputeFlags(Code::STUB),
704      Handle<Code>())->ToObjectChecked());
705  CHECK(code->IsCode());
706#ifdef OBJECT_PRINT
707  Code::cast(code)->Print();
708#endif
709
710  F6 f = FUNCTION_CAST<F6>(Code::cast(code)->entry());
711  CHECK_EQ(2, f(1.0, 2.0));
712}
713#undef __
714