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
TEST(AssemblerX64ReturnOperation)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
TEST(AssemblerX64StackOperations)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
TEST(AssemblerX64ArithmeticOperations)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
TEST(AssemblerX64ImulOperation)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
TEST(AssemblerX64XchglOperations)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(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
TEST(AssemblerX64OrlOperations)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
TEST(AssemblerX64RollOperations)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
TEST(AssemblerX64SublOperations)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
TEST(AssemblerX64TestlOperations)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(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
TEST(AssemblerX64XorlOperations)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
TEST(AssemblerX64MemoryOperands)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
TEST(AssemblerX64ControlFlow)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
TEST(AssemblerX64LoopImmediates)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
TEST(OperandRegisterDependency)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
TEST(AssemblerX64LabelChaining)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
TEST(AssemblerMultiByteNop)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
DoSSE2(const v8::FunctionCallbackInfo<v8::Value> & args)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(res));
608 }
609
610
TEST(StackAlignmentForSSE2)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 = 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
TEST(AssemblerX64Extractps)647 TEST(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
679 typedef int (*F6)(float x, float y);
TEST(AssemblerX64SSE)680 TEST(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