The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / test / cctest / test-assembler-x64.cc @ f230a1cf

History | View | Annotate | Download (21.1 KB)

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(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

    
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(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

    
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(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 = 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(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

    
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
#undef __