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