Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / v8 / test / cctest / test-assembler-x64.cc
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
38 using 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
50 typedef int (*F0)();
51 typedef int (*F1)(int64_t x);
52 typedef int (*F2)(int64_t x, int64_t y);
53 typedef int (*F3)(double x);
54 typedef int64_t (*F4)(int64_t* x, int64_t* y);
55 typedef int64_t (*F5)(int64_t x);
56
57 #ifdef _WIN64
58 static const Register arg1 = rcx;
59 static const Register arg2 = rdx;
60 #else
61 static const Register arg1 = rdi;
62 static const Register arg2 = rsi;
63 #endif
64
65 #define __ assm.
66
67
68 TEST(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
90 TEST(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
122 TEST(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
144 TEST(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
172 TEST(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(r11, Operand(arg2, 0));
183   __ xchgl(rax, r11);
184   __ movq(Operand(arg1, 0), rax);
185   __ movq(Operand(arg2, 0), r11);
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
200 TEST(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
224 TEST(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
246 TEST(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
270 TEST(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(r11, Operand(arg2, 0));
283   __ testl(Operand(arg1, 0), r11);
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
299 TEST(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
323 TEST(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
357 TEST(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
386 TEST(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
436 TEST(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
479 TEST(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
493 TEST(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
562 void 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(CcTest::isolate(), res));
608 }
609
610
611 TEST(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 =
618       v8::ObjectTemplate::New(isolate);
619   global_template->Set(v8_str("do_sse2"),
620                        v8::FunctionTemplate::New(isolate, DoSSE2));
621
622   LocalContext env(NULL, global_template);
623   CompileRun(
624       "function foo(vec) {"
625       "  return do_sse2(vec);"
626       "}");
627
628   v8::Local<v8::Object> global_object = env->Global();
629   v8::Local<v8::Function> foo =
630       v8::Local<v8::Function>::Cast(global_object->Get(v8_str("foo")));
631
632   int32_t vec[ELEMENT_COUNT] = { -1, 1, 1, 1 };
633   v8::Local<v8::Array> v8_vec = v8::Array::New(isolate, ELEMENT_COUNT);
634   for (int i = 0; i < ELEMENT_COUNT; i++) {
635     v8_vec->Set(i, v8_num(vec[i]));
636   }
637
638   v8::Local<v8::Value> args[] = { v8_vec };
639   v8::Local<v8::Value> result = foo->Call(global_object, 1, args);
640
641   // The mask should be 0b1000.
642   CHECK_EQ(8, result->Int32Value());
643 }
644
645 #undef ELEMENT_COUNT
646 #endif  // __GNUC__
647
648
649 TEST(AssemblerX64Extractps) {
650   CcTest::InitializeVM();
651   if (!CpuFeatures::IsSupported(SSE4_1)) return;
652
653   v8::HandleScope scope(CcTest::isolate());
654   byte buffer[256];
655   Isolate* isolate = CcTest::i_isolate();
656   Assembler assm(isolate, buffer, sizeof(buffer));
657   { CpuFeatureScope fscope2(&assm, SSE4_1);
658     __ extractps(rax, xmm0, 0x1);
659     __ ret(0);
660   }
661
662   CodeDesc desc;
663   assm.GetCode(&desc);
664   Code* code = Code::cast(isolate->heap()->CreateCode(
665       desc,
666       Code::ComputeFlags(Code::STUB),
667       Handle<Code>())->ToObjectChecked());
668   CHECK(code->IsCode());
669 #ifdef OBJECT_PRINT
670   Code::cast(code)->Print();
671 #endif
672
673   F3 f = FUNCTION_CAST<F3>(Code::cast(code)->entry());
674   uint64_t value1 = V8_2PART_UINT64_C(0x12345678, 87654321);
675   CHECK_EQ(0x12345678, f(uint64_to_double(value1)));
676   uint64_t value2 = V8_2PART_UINT64_C(0x87654321, 12345678);
677   CHECK_EQ(0x87654321, f(uint64_to_double(value2)));
678 }
679
680
681 typedef int (*F6)(float x, float y);
682 TEST(AssemblerX64SSE) {
683   CcTest::InitializeVM();
684
685   Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
686   HandleScope scope(isolate);
687   v8::internal::byte buffer[256];
688   MacroAssembler assm(isolate, buffer, sizeof buffer);
689   {
690     __ shufps(xmm0, xmm0, 0x0);  // brocast first argument
691     __ shufps(xmm1, xmm1, 0x0);  // brocast second argument
692     __ movaps(xmm2, xmm1);
693     __ addps(xmm2, xmm0);
694     __ mulps(xmm2, xmm1);
695     __ subps(xmm2, xmm0);
696     __ divps(xmm2, xmm1);
697     __ cvttss2si(rax, xmm2);
698     __ ret(0);
699   }
700
701   CodeDesc desc;
702   assm.GetCode(&desc);
703   Code* code = Code::cast(isolate->heap()->CreateCode(
704       desc,
705       Code::ComputeFlags(Code::STUB),
706       Handle<Code>())->ToObjectChecked());
707   CHECK(code->IsCode());
708 #ifdef OBJECT_PRINT
709   Code::cast(code)->Print();
710 #endif
711
712   F6 f = FUNCTION_CAST<F6>(Code::cast(code)->entry());
713   CHECK_EQ(2, f(1.0, 2.0));
714 }
715 #undef __