test-assembler-ppc.cc 28.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

28
#include "src/init/v8.h"
29

30
#include "src/codegen/ppc/assembler-ppc-inl.h"
31
#include "src/diagnostics/disassembler.h"
32
#include "src/execution/simulator.h"
33
#include "src/heap/factory.h"
34
#include "test/cctest/cctest.h"
35
#include "test/common/assembler-tester.h"
36

37 38
namespace v8 {
namespace internal {
39

40 41
// TODO(ppc): Refine these signatures per test case, they can have arbitrary
// return and argument types and arbitrary number of arguments.
42 43 44 45 46
using F_iiiii = void*(int x, int p1, int p2, int p3, int p4);
using F_piiii = void*(void* p0, int p1, int p2, int p3, int p4);
using F_ppiii = void*(void* p0, void* p1, int p2, int p3, int p4);
using F_pppii = void*(void* p0, void* p1, void* p2, int p3, int p4);
using F_ippii = void*(int p0, void* p1, void* p2, int p3, int p4);
47 48 49 50 51 52

#define __ assm.

// Simple add parameter 1 to parameter 2 and return
TEST(0) {
  CcTest::InitializeVM();
53
  Isolate* isolate = CcTest::i_isolate();
54 55
  HandleScope scope(isolate);

56
  Assembler assm(AssemblerOptions{});
57 58 59 60 61

  __ add(r3, r3, r4);
  __ blr();

  CodeDesc desc;
62
  assm.GetCode(isolate, &desc);
63 64
  Handle<Code> code =
      Factory::CodeBuilder(isolate, desc, CodeKind::FOR_TESTING).Build();
65
#ifdef DEBUG
66
  code->Print();
67
#endif
68 69
  auto f = GeneratedCode<F_iiiii>::FromCode(*code);
  intptr_t res = reinterpret_cast<intptr_t>(f.Call(3, 4, 0, 0, 0));
70 71 72 73 74 75 76 77
  ::printf("f() = %" V8PRIdPTR "\n", res);
  CHECK_EQ(7, static_cast<int>(res));
}


// Loop 100 times, adding loop counter to result
TEST(1) {
  CcTest::InitializeVM();
78
  Isolate* isolate = CcTest::i_isolate();
79 80
  HandleScope scope(isolate);

81
  Assembler assm(AssemblerOptions{});
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
  Label L, C;

  __ mr(r4, r3);
  __ li(r3, Operand::Zero());
  __ b(&C);

  __ bind(&L);
  __ add(r3, r3, r4);
  __ subi(r4, r4, Operand(1));

  __ bind(&C);
  __ cmpi(r4, Operand::Zero());
  __ bne(&L);
  __ blr();

  CodeDesc desc;
98
  assm.GetCode(isolate, &desc);
99 100
  Handle<Code> code =
      Factory::CodeBuilder(isolate, desc, CodeKind::FOR_TESTING).Build();
101
#ifdef DEBUG
102
  code->Print();
103
#endif
104 105
  auto f = GeneratedCode<F_iiiii>::FromCode(*code);
  intptr_t res = reinterpret_cast<intptr_t>(f.Call(100, 0, 0, 0, 0));
106 107 108 109 110 111 112
  ::printf("f() = %" V8PRIdPTR "\n", res);
  CHECK_EQ(5050, static_cast<int>(res));
}


TEST(2) {
  CcTest::InitializeVM();
113
  Isolate* isolate = CcTest::i_isolate();
114 115
  HandleScope scope(isolate);

116
  Assembler assm(AssemblerOptions{});
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
  Label L, C;

  __ mr(r4, r3);
  __ li(r3, Operand(1));
  __ b(&C);

  __ bind(&L);
#if defined(V8_TARGET_ARCH_PPC64)
  __ mulld(r3, r4, r3);
#else
  __ mullw(r3, r4, r3);
#endif
  __ subi(r4, r4, Operand(1));

  __ bind(&C);
  __ cmpi(r4, Operand::Zero());
  __ bne(&L);
  __ blr();

  // some relocated stuff here, not executed
  __ RecordComment("dead code, just testing relocations");
  __ mov(r0, Operand(isolate->factory()->true_value()));
  __ RecordComment("dead code, just testing immediate operands");
  __ mov(r0, Operand(-1));
  __ mov(r0, Operand(0xFF000000));
  __ mov(r0, Operand(0xF0F0F0F0));
  __ mov(r0, Operand(0xFFF0FFFF));

  CodeDesc desc;
146
  assm.GetCode(isolate, &desc);
147 148
  Handle<Code> code =
      Factory::CodeBuilder(isolate, desc, CodeKind::FOR_TESTING).Build();
149
#ifdef DEBUG
150
  code->Print();
151
#endif
152 153
  auto f = GeneratedCode<F_iiiii>::FromCode(*code);
  intptr_t res = reinterpret_cast<intptr_t>(f.Call(10, 0, 0, 0, 0));
154 155 156 157 158 159 160
  ::printf("f() = %" V8PRIdPTR "\n", res);
  CHECK_EQ(3628800, static_cast<int>(res));
}


TEST(3) {
  CcTest::InitializeVM();
161
  Isolate* isolate = CcTest::i_isolate();
162 163
  HandleScope scope(isolate);

164
  struct T {
165 166 167
    int i;
    char c;
    int16_t s;
168
  };
169 170
  T t;

171
  Assembler assm(AssemblerOptions{});
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

// build a frame
#if V8_TARGET_ARCH_PPC64
  __ stdu(sp, MemOperand(sp, -32));
  __ std(fp, MemOperand(sp, 24));
#else
  __ stwu(sp, MemOperand(sp, -16));
  __ stw(fp, MemOperand(sp, 12));
#endif
  __ mr(fp, sp);

  // r4 points to our struct
  __ mr(r4, r3);

  // modify field int i of struct
187
  __ lwz(r3, MemOperand(r4, offsetof(T, i)));
188
  __ srwi(r5, r3, Operand(1));
189
  __ stw(r5, MemOperand(r4, offsetof(T, i)));
190 191

  // modify field char c of struct
192
  __ lbz(r5, MemOperand(r4, offsetof(T, c)));
193 194
  __ add(r3, r5, r3);
  __ slwi(r5, r5, Operand(2));
195
  __ stb(r5, MemOperand(r4, offsetof(T, c)));
196 197

  // modify field int16_t s of struct
198
  __ lhz(r5, MemOperand(r4, offsetof(T, s)));
199 200
  __ add(r3, r5, r3);
  __ srwi(r5, r5, Operand(3));
201
  __ sth(r5, MemOperand(r4, offsetof(T, s)));
202 203 204 205 206 207 208 209 210 211 212 213 214

// restore frame
#if V8_TARGET_ARCH_PPC64
  __ addi(r11, fp, Operand(32));
  __ ld(fp, MemOperand(r11, -8));
#else
  __ addi(r11, fp, Operand(16));
  __ lwz(fp, MemOperand(r11, -4));
#endif
  __ mr(sp, r11);
  __ blr();

  CodeDesc desc;
215
  assm.GetCode(isolate, &desc);
216 217
  Handle<Code> code =
      Factory::CodeBuilder(isolate, desc, CodeKind::FOR_TESTING).Build();
218
#ifdef DEBUG
219
  code->Print();
220
#endif
221
  auto f = GeneratedCode<F_piiii>::FromCode(*code);
222 223 224
  t.i = 100000;
  t.c = 10;
  t.s = 1000;
225
  intptr_t res = reinterpret_cast<intptr_t>(f.Call(&t, 0, 0, 0, 0));
226 227 228 229 230 231 232 233 234 235 236
  ::printf("f() = %" V8PRIdPTR "\n", res);
  CHECK_EQ(101010, static_cast<int>(res));
  CHECK_EQ(100000 / 2, t.i);
  CHECK_EQ(10 * 4, t.c);
  CHECK_EQ(1000 / 8, t.s);
}

#if 0
TEST(4) {
  // Test the VFP floating point instructions.
  CcTest::InitializeVM();
237
  Isolate* isolate = CcTest::i_isolate();
238 239
  HandleScope scope(isolate);

240
  struct T {
241 242 243 244 245 246 247 248 249 250 251 252 253
    double a;
    double b;
    double c;
    double d;
    double e;
    double f;
    double g;
    double h;
    int i;
    double m;
    double n;
    float x;
    float y;
254
  };
255 256 257 258
  T t;

  // Create a function that accepts &t, and loads, manipulates, and stores
  // the doubles and floats.
259
  Assembler assm(AssemblerOptions{});
260 261 262 263 264 265
  Label L, C;

  if (CpuFeatures::IsSupported(VFP3)) {
    CpuFeatures::Scope scope(VFP3);

    __ mov(ip, Operand(sp));
266
    __ stm(db_w, sp, {r4, fp, lr});
267 268 269
    __ sub(fp, ip, Operand(4));

    __ mov(r4, Operand(r0));
270 271
    __ vldr(d6, r4, offsetof(T, a));
    __ vldr(d7, r4, offsetof(T, b));
272
    __ vadd(d5, d6, d7);
273
    __ vstr(d5, r4, offsetof(T, c));
274 275 276

    __ vmov(r2, r3, d5);
    __ vmov(d4, r2, r3);
277
    __ vstr(d4, r4, offsetof(T, b));
278 279

    // Load t.x and t.y, switch values, and store back to the struct.
280 281
    __ vldr(s0, r4, offsetof(T, x));
    __ vldr(s31, r4, offsetof(T, y));
282 283 284
    __ vmov(s16, s0);
    __ vmov(s0, s31);
    __ vmov(s31, s16);
285 286
    __ vstr(s0, r4, offsetof(T, x));
    __ vstr(s31, r4, offsetof(T, y));
287 288 289

    // Move a literal into a register that can be encoded in the instruction.
    __ vmov(d4, 1.0);
290
    __ vstr(d4, r4, offsetof(T, e));
291 292

    // Move a literal into a register that requires 64 bits to encode.
293
    // 0x3FF0000010000000 = 1.000000059604644775390625
294
    __ vmov(d4, 1.000000059604644775390625);
295
    __ vstr(d4, r4, offsetof(T, d));
296 297 298 299

    // Convert from floating point to integer.
    __ vmov(d4, 2.0);
    __ vcvt_s32_f64(s31, d4);
300
    __ vstr(s31, r4, offsetof(T, i));
301 302 303 304 305

    // Convert from integer to floating point.
    __ mov(lr, Operand(42));
    __ vmov(s31, lr);
    __ vcvt_f64_s32(d4, s31);
306
    __ vstr(d4, r4, offsetof(T, f));
307 308

    // Test vabs.
309
    __ vldr(d1, r4, offsetof(T, g));
310
    __ vabs(d0, d1);
311 312
    __ vstr(d0, r4, offsetof(T, g));
    __ vldr(d2, r4, offsetof(T, h));
313
    __ vabs(d0, d2);
314
    __ vstr(d0, r4, offsetof(T, h));
315 316

    // Test vneg.
317
    __ vldr(d1, r4, offsetof(T, m));
318
    __ vneg(d0, d1);
319 320
    __ vstr(d0, r4, offsetof(T, m));
    __ vldr(d1, r4, offsetof(T, n));
321
    __ vneg(d0, d1);
322
    __ vstr(d0, r4, offsetof(T, n));
323

324
    __ ldm(ia_w, sp, {r4, fp, pc});
325 326

    CodeDesc desc;
327
    assm.GetCode(isolate, &desc);
328
    Object code = isolate->heap()->CreateCode(
329
        desc,
330
        CodeKind::FOR_TESTING,
331 332 333
        Handle<Code>())->ToObjectChecked();
    CHECK(code->IsCode());
#ifdef DEBUG
334
    Code::cast(code)->Print();
335
#endif
336
    auto f = GeneratedCode<F_piiii>::FromCode(*code);
337 338 339 340 341 342 343 344 345 346 347 348 349
    t.a = 1.5;
    t.b = 2.75;
    t.c = 17.17;
    t.d = 0.0;
    t.e = 0.0;
    t.f = 0.0;
    t.g = -2718.2818;
    t.h = 31415926.5;
    t.i = 0;
    t.m = -2718.2818;
    t.n = 123.456;
    t.x = 4.5;
    t.y = 9.0;
350
    f.Call(&t, 0, 0, 0, 0);
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
    CHECK_EQ(4.5, t.y);
    CHECK_EQ(9.0, t.x);
    CHECK_EQ(-123.456, t.n);
    CHECK_EQ(2718.2818, t.m);
    CHECK_EQ(2, t.i);
    CHECK_EQ(2718.2818, t.g);
    CHECK_EQ(31415926.5, t.h);
    CHECK_EQ(42.0, t.f);
    CHECK_EQ(1.0, t.e);
    CHECK_EQ(1.000000059604644775390625, t.d);
    CHECK_EQ(4.25, t.c);
    CHECK_EQ(4.25, t.b);
    CHECK_EQ(1.5, t.a);
  }
}


TEST(5) {
  // Test the ARMv7 bitfield instructions.
  CcTest::InitializeVM();
371
  Isolate* isolate = CcTest::i_isolate();
372 373
  HandleScope scope(isolate);

374
  Assembler assm(AssemblerOptions{});
375 376 377 378 379 380 381 382 383 384 385 386

  if (CpuFeatures::IsSupported(ARMv7)) {
    CpuFeatures::Scope scope(ARMv7);
    // On entry, r0 = 0xAAAAAAAA = 0b10..10101010.
    __ ubfx(r0, r0, 1, 12);  // 0b00..010101010101 = 0x555
    __ sbfx(r0, r0, 0, 5);   // 0b11..111111110101 = -11
    __ bfc(r0, 1, 3);        // 0b11..111111110001 = -15
    __ mov(r1, Operand(7));
    __ bfi(r0, r1, 3, 3);    // 0b11..111111111001 = -7
    __ mov(pc, Operand(lr));

    CodeDesc desc;
387
    assm.GetCode(isolate, &desc);
388
    Object code = isolate->heap()->CreateCode(
389
        desc,
390
        CodeKind::FOR_TESTING,
391 392 393
        Handle<Code>())->ToObjectChecked();
    CHECK(code->IsCode());
#ifdef DEBUG
394
    Code::cast(code)->Print();
395
#endif
396 397
    auto f = GeneratedCode<F_iiiii>::FromCode(*code);
    int res = reinterpret_cast<int>(f.Call(0xAAAAAAAA, 0, 0, 0, 0));
398 399 400 401 402 403 404 405 406
    ::printf("f() = %d\n", res);
    CHECK_EQ(-7, res);
  }
}


TEST(6) {
  // Test saturating instructions.
  CcTest::InitializeVM();
407
  Isolate* isolate = CcTest::i_isolate();
408 409
  HandleScope scope(isolate);

410
  Assembler assm(AssemblerOptions{});
411 412 413 414 415 416 417 418 419 420 421

  if (CpuFeatures::IsSupported(ARMv7)) {
    CpuFeatures::Scope scope(ARMv7);
    __ usat(r1, 8, Operand(r0));           // Sat 0xFFFF to 0-255 = 0xFF.
    __ usat(r2, 12, Operand(r0, ASR, 9));  // Sat (0xFFFF>>9) to 0-4095 = 0x7F.
    __ usat(r3, 1, Operand(r0, LSL, 16));  // Sat (0xFFFF<<16) to 0-1 = 0x0.
    __ addi(r0, r1, Operand(r2));
    __ addi(r0, r0, Operand(r3));
    __ mov(pc, Operand(lr));

    CodeDesc desc;
422
    assm.GetCode(isolate, &desc);
423
    Object code = isolate->heap()->CreateCode(
424
        desc,
425
        CodeKind::FOR_TESTING,
426 427 428
        Handle<Code>())->ToObjectChecked();
    CHECK(code->IsCode());
#ifdef DEBUG
429
    Code::cast(code)->Print();
430
#endif
431 432
    auto f = GeneratedCode<F_iiiii>::FromCode(*code);
    int res = reinterpret_cast<int>(f.Call(0xFFFF, 0, 0, 0, 0));
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
    ::printf("f() = %d\n", res);
    CHECK_EQ(382, res);
  }
}

enum VCVTTypes {
  s32_f64,
  u32_f64
};

static void TestRoundingMode(VCVTTypes types,
                             VFPRoundingMode mode,
                             double value,
                             int expected,
                             bool expected_exception = false) {
  CcTest::InitializeVM();
449
  Isolate* isolate = CcTest::i_isolate();
450 451
  HandleScope scope(isolate);

452
  Assembler assm(AssemblerOptions{});
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496

  if (CpuFeatures::IsSupported(VFP3)) {
    CpuFeatures::Scope scope(VFP3);

    Label wrong_exception;

    __ vmrs(r1);
    // Set custom FPSCR.
    __ bic(r2, r1, Operand(kVFPRoundingModeMask | kVFPExceptionMask));
    __ orr(r2, r2, Operand(mode));
    __ vmsr(r2);

    // Load value, convert, and move back result to r0 if everything went well.
    __ vmov(d1, value);
    switch (types) {
      case s32_f64:
        __ vcvt_s32_f64(s0, d1, kFPSCRRounding);
        break;

      case u32_f64:
        __ vcvt_u32_f64(s0, d1, kFPSCRRounding);
        break;

      default:
        UNREACHABLE();
        break;
    }
    // Check for vfp exceptions
    __ vmrs(r2);
    __ tst(r2, Operand(kVFPExceptionMask));
    // Check that we behaved as expected.
    __ b(&wrong_exception,
         expected_exception ? eq : ne);
    // There was no exception. Retrieve the result and return.
    __ vmov(r0, s0);
    __ mov(pc, Operand(lr));

    // The exception behaviour is not what we expected.
    // Load a special value and return.
    __ bind(&wrong_exception);
    __ mov(r0, Operand(11223344));
    __ mov(pc, Operand(lr));

    CodeDesc desc;
497
    assm.GetCode(isolate, &desc);
498
    Object code = isolate->heap()->CreateCode(
499
        desc,
500
        CodeKind::FOR_TESTING,
501 502 503
        Handle<Code>())->ToObjectChecked();
    CHECK(code->IsCode());
#ifdef DEBUG
504
    Code::cast(code)->Print();
505
#endif
506 507
    auto f = GeneratedCode<F_iiiii>::FromCode(*code);
    int res = reinterpret_cast<int>(f.Call(0, 0, 0, 0, 0));
508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584
    ::printf("res = %d\n", res);
    CHECK_EQ(expected, res);
  }
}


TEST(7) {
  // Test vfp rounding modes.

  // s32_f64 (double to integer).

  TestRoundingMode(s32_f64, RN,  0, 0);
  TestRoundingMode(s32_f64, RN,  0.5, 0);
  TestRoundingMode(s32_f64, RN, -0.5, 0);
  TestRoundingMode(s32_f64, RN,  1.5, 2);
  TestRoundingMode(s32_f64, RN, -1.5, -2);
  TestRoundingMode(s32_f64, RN,  123.7, 124);
  TestRoundingMode(s32_f64, RN, -123.7, -124);
  TestRoundingMode(s32_f64, RN,  123456.2,  123456);
  TestRoundingMode(s32_f64, RN, -123456.2, -123456);
  TestRoundingMode(s32_f64, RN, static_cast<double>(kMaxInt), kMaxInt);
  TestRoundingMode(s32_f64, RN, (kMaxInt + 0.49), kMaxInt);
  TestRoundingMode(s32_f64, RN, (kMaxInt + 1.0), kMaxInt, true);
  TestRoundingMode(s32_f64, RN, (kMaxInt + 0.5), kMaxInt, true);
  TestRoundingMode(s32_f64, RN, static_cast<double>(kMinInt), kMinInt);
  TestRoundingMode(s32_f64, RN, (kMinInt - 0.5), kMinInt);
  TestRoundingMode(s32_f64, RN, (kMinInt - 1.0), kMinInt, true);
  TestRoundingMode(s32_f64, RN, (kMinInt - 0.51), kMinInt, true);

  TestRoundingMode(s32_f64, RM,  0, 0);
  TestRoundingMode(s32_f64, RM,  0.5, 0);
  TestRoundingMode(s32_f64, RM, -0.5, -1);
  TestRoundingMode(s32_f64, RM,  123.7, 123);
  TestRoundingMode(s32_f64, RM, -123.7, -124);
  TestRoundingMode(s32_f64, RM,  123456.2,  123456);
  TestRoundingMode(s32_f64, RM, -123456.2, -123457);
  TestRoundingMode(s32_f64, RM, static_cast<double>(kMaxInt), kMaxInt);
  TestRoundingMode(s32_f64, RM, (kMaxInt + 0.5), kMaxInt);
  TestRoundingMode(s32_f64, RM, (kMaxInt + 1.0), kMaxInt, true);
  TestRoundingMode(s32_f64, RM, static_cast<double>(kMinInt), kMinInt);
  TestRoundingMode(s32_f64, RM, (kMinInt - 0.5), kMinInt, true);
  TestRoundingMode(s32_f64, RM, (kMinInt + 0.5), kMinInt);

  TestRoundingMode(s32_f64, RZ,  0, 0);
  TestRoundingMode(s32_f64, RZ,  0.5, 0);
  TestRoundingMode(s32_f64, RZ, -0.5, 0);
  TestRoundingMode(s32_f64, RZ,  123.7,  123);
  TestRoundingMode(s32_f64, RZ, -123.7, -123);
  TestRoundingMode(s32_f64, RZ,  123456.2,  123456);
  TestRoundingMode(s32_f64, RZ, -123456.2, -123456);
  TestRoundingMode(s32_f64, RZ, static_cast<double>(kMaxInt), kMaxInt);
  TestRoundingMode(s32_f64, RZ, (kMaxInt + 0.5), kMaxInt);
  TestRoundingMode(s32_f64, RZ, (kMaxInt + 1.0), kMaxInt, true);
  TestRoundingMode(s32_f64, RZ, static_cast<double>(kMinInt), kMinInt);
  TestRoundingMode(s32_f64, RZ, (kMinInt - 0.5), kMinInt);
  TestRoundingMode(s32_f64, RZ, (kMinInt - 1.0), kMinInt, true);


  // u32_f64 (double to integer).

  // Negative values.
  TestRoundingMode(u32_f64, RN, -0.5, 0);
  TestRoundingMode(u32_f64, RN, -123456.7, 0, true);
  TestRoundingMode(u32_f64, RN, static_cast<double>(kMinInt), 0, true);
  TestRoundingMode(u32_f64, RN, kMinInt - 1.0, 0, true);

  TestRoundingMode(u32_f64, RM, -0.5, 0, true);
  TestRoundingMode(u32_f64, RM, -123456.7, 0, true);
  TestRoundingMode(u32_f64, RM, static_cast<double>(kMinInt), 0, true);
  TestRoundingMode(u32_f64, RM, kMinInt - 1.0, 0, true);

  TestRoundingMode(u32_f64, RZ, -0.5, 0);
  TestRoundingMode(u32_f64, RZ, -123456.7, 0, true);
  TestRoundingMode(u32_f64, RZ, static_cast<double>(kMinInt), 0, true);
  TestRoundingMode(u32_f64, RZ, kMinInt - 1.0, 0, true);

  // Positive values.
585 586
  // kMaxInt is the maximum *signed* integer: 0x7FFFFFFF.
  static const uint32_t kMaxUInt = 0xFFFFFFFFu;
587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626
  TestRoundingMode(u32_f64, RZ,  0, 0);
  TestRoundingMode(u32_f64, RZ,  0.5, 0);
  TestRoundingMode(u32_f64, RZ,  123.7,  123);
  TestRoundingMode(u32_f64, RZ,  123456.2,  123456);
  TestRoundingMode(u32_f64, RZ, static_cast<double>(kMaxInt), kMaxInt);
  TestRoundingMode(u32_f64, RZ, (kMaxInt + 0.5), kMaxInt);
  TestRoundingMode(u32_f64, RZ, (kMaxInt + 1.0),
                                static_cast<uint32_t>(kMaxInt) + 1);
  TestRoundingMode(u32_f64, RZ, (kMaxUInt + 0.5), kMaxUInt);
  TestRoundingMode(u32_f64, RZ, (kMaxUInt + 1.0), kMaxUInt, true);

  TestRoundingMode(u32_f64, RM,  0, 0);
  TestRoundingMode(u32_f64, RM,  0.5, 0);
  TestRoundingMode(u32_f64, RM,  123.7, 123);
  TestRoundingMode(u32_f64, RM,  123456.2,  123456);
  TestRoundingMode(u32_f64, RM, static_cast<double>(kMaxInt), kMaxInt);
  TestRoundingMode(u32_f64, RM, (kMaxInt + 0.5), kMaxInt);
  TestRoundingMode(u32_f64, RM, (kMaxInt + 1.0),
                                static_cast<uint32_t>(kMaxInt) + 1);
  TestRoundingMode(u32_f64, RM, (kMaxUInt + 0.5), kMaxUInt);
  TestRoundingMode(u32_f64, RM, (kMaxUInt + 1.0), kMaxUInt, true);

  TestRoundingMode(u32_f64, RN,  0, 0);
  TestRoundingMode(u32_f64, RN,  0.5, 0);
  TestRoundingMode(u32_f64, RN,  1.5, 2);
  TestRoundingMode(u32_f64, RN,  123.7, 124);
  TestRoundingMode(u32_f64, RN,  123456.2,  123456);
  TestRoundingMode(u32_f64, RN, static_cast<double>(kMaxInt), kMaxInt);
  TestRoundingMode(u32_f64, RN, (kMaxInt + 0.49), kMaxInt);
  TestRoundingMode(u32_f64, RN, (kMaxInt + 0.5),
                                static_cast<uint32_t>(kMaxInt) + 1);
  TestRoundingMode(u32_f64, RN, (kMaxUInt + 0.49), kMaxUInt);
  TestRoundingMode(u32_f64, RN, (kMaxUInt + 0.5), kMaxUInt, true);
  TestRoundingMode(u32_f64, RN, (kMaxUInt + 1.0), kMaxUInt, true);
}


TEST(8) {
  // Test VFP multi load/store with ia_w.
  CcTest::InitializeVM();
627
  Isolate* isolate = CcTest::i_isolate();
628 629
  HandleScope scope(isolate);

630
  struct D {
631 632 633 634 635 636 637 638
    double a;
    double b;
    double c;
    double d;
    double e;
    double f;
    double g;
    double h;
639
  };
640 641
  D d;

642
  struct F {
643 644 645 646 647 648 649 650
    float a;
    float b;
    float c;
    float d;
    float e;
    float f;
    float g;
    float h;
651
  };
652 653 654 655
  F f;

  // Create a function that uses vldm/vstm to move some double and
  // single precision values around in memory.
656
  Assembler assm(AssemblerOptions{});
657 658 659 660 661

  if (CpuFeatures::IsSupported(VFP2)) {
    CpuFeatures::Scope scope(VFP2);

    __ mov(ip, Operand(sp));
662
    __ stm(db_w, sp, {r4, fp, lr});
663 664
    __ sub(fp, ip, Operand(4));

665
    __ addi(r4, r0, Operand(offsetof(D, a)));
666 667 668
    __ vldm(ia_w, r4, d0, d3);
    __ vldm(ia_w, r4, d4, d7);

669
    __ addi(r4, r0, Operand(offsetof(D, a)));
670 671 672
    __ vstm(ia_w, r4, d6, d7);
    __ vstm(ia_w, r4, d0, d5);

673
    __ addi(r4, r1, Operand(offsetof(F, a)));
674 675 676
    __ vldm(ia_w, r4, s0, s3);
    __ vldm(ia_w, r4, s4, s7);

677
    __ addi(r4, r1, Operand(offsetof(F, a)));
678 679 680
    __ vstm(ia_w, r4, s6, s7);
    __ vstm(ia_w, r4, s0, s5);

681
    __ ldm(ia_w, sp, {r4, fp, pc});
682 683

    CodeDesc desc;
684
    assm.GetCode(isolate, &desc);
685
    Object code = isolate->heap()->CreateCode(
686
        desc,
687
        CodeKind::FOR_TESTING,
688 689 690
        Handle<Code>())->ToObjectChecked();
    CHECK(code->IsCode());
#ifdef DEBUG
691
    Code::cast(code)->Print();
692
#endif
693
    auto fn = GeneratedCode<F_ppiii>::FromCode(*code);
694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711
    d.a = 1.1;
    d.b = 2.2;
    d.c = 3.3;
    d.d = 4.4;
    d.e = 5.5;
    d.f = 6.6;
    d.g = 7.7;
    d.h = 8.8;

    f.a = 1.0;
    f.b = 2.0;
    f.c = 3.0;
    f.d = 4.0;
    f.e = 5.0;
    f.f = 6.0;
    f.g = 7.0;
    f.h = 8.0;

712
    fn.Call(&d, &f, 0, 0, 0);
713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737

    CHECK_EQ(7.7, d.a);
    CHECK_EQ(8.8, d.b);
    CHECK_EQ(1.1, d.c);
    CHECK_EQ(2.2, d.d);
    CHECK_EQ(3.3, d.e);
    CHECK_EQ(4.4, d.f);
    CHECK_EQ(5.5, d.g);
    CHECK_EQ(6.6, d.h);

    CHECK_EQ(7.0, f.a);
    CHECK_EQ(8.0, f.b);
    CHECK_EQ(1.0, f.c);
    CHECK_EQ(2.0, f.d);
    CHECK_EQ(3.0, f.e);
    CHECK_EQ(4.0, f.f);
    CHECK_EQ(5.0, f.g);
    CHECK_EQ(6.0, f.h);
  }
}


TEST(9) {
  // Test VFP multi load/store with ia.
  CcTest::InitializeVM();
738
  Isolate* isolate = CcTest::i_isolate();
739 740
  HandleScope scope(isolate);

741
  struct D {
742 743 744 745 746 747 748 749
    double a;
    double b;
    double c;
    double d;
    double e;
    double f;
    double g;
    double h;
750
  };
751 752
  D d;

753
  struct F {
754 755 756 757 758 759 760 761
    float a;
    float b;
    float c;
    float d;
    float e;
    float f;
    float g;
    float h;
762
  };
763 764 765 766
  F f;

  // Create a function that uses vldm/vstm to move some double and
  // single precision values around in memory.
767
  Assembler assm(AssemblerOptions{});
768 769 770 771 772

  if (CpuFeatures::IsSupported(VFP2)) {
    CpuFeatures::Scope scope(VFP2);

    __ mov(ip, Operand(sp));
773
    __ stm(db_w, sp, {r4, fp, lr});
774 775
    __ sub(fp, ip, Operand(4));

776
    __ addi(r4, r0, Operand(offsetof(D, a)));
777 778 779 780
    __ vldm(ia, r4, d0, d3);
    __ addi(r4, r4, Operand(4 * 8));
    __ vldm(ia, r4, d4, d7);

781
    __ addi(r4, r0, Operand(offsetof(D, a)));
782 783 784 785
    __ vstm(ia, r4, d6, d7);
    __ addi(r4, r4, Operand(2 * 8));
    __ vstm(ia, r4, d0, d5);

786
    __ addi(r4, r1, Operand(offsetof(F, a)));
787 788 789 790
    __ vldm(ia, r4, s0, s3);
    __ addi(r4, r4, Operand(4 * 4));
    __ vldm(ia, r4, s4, s7);

791
    __ addi(r4, r1, Operand(offsetof(F, a)));
792 793 794 795
    __ vstm(ia, r4, s6, s7);
    __ addi(r4, r4, Operand(2 * 4));
    __ vstm(ia, r4, s0, s5);

796
    __ ldm(ia_w, sp, {r4, fp, pc});
797 798

    CodeDesc desc;
799
    assm.GetCode(isolate, &desc);
800
    Object code = isolate->heap()->CreateCode(
801
        desc,
802
        CodeKind::FOR_TESTING,
803 804 805
        Handle<Code>())->ToObjectChecked();
    CHECK(code->IsCode());
#ifdef DEBUG
806
    Code::cast(code)->Print();
807
#endif
808
    auto fn = GeneratedCode<F_ppiii>::FromCode(*code);
809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826
    d.a = 1.1;
    d.b = 2.2;
    d.c = 3.3;
    d.d = 4.4;
    d.e = 5.5;
    d.f = 6.6;
    d.g = 7.7;
    d.h = 8.8;

    f.a = 1.0;
    f.b = 2.0;
    f.c = 3.0;
    f.d = 4.0;
    f.e = 5.0;
    f.f = 6.0;
    f.g = 7.0;
    f.h = 8.0;

827
    fn.Call(&d, &f, 0, 0, 0);
828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852

    CHECK_EQ(7.7, d.a);
    CHECK_EQ(8.8, d.b);
    CHECK_EQ(1.1, d.c);
    CHECK_EQ(2.2, d.d);
    CHECK_EQ(3.3, d.e);
    CHECK_EQ(4.4, d.f);
    CHECK_EQ(5.5, d.g);
    CHECK_EQ(6.6, d.h);

    CHECK_EQ(7.0, f.a);
    CHECK_EQ(8.0, f.b);
    CHECK_EQ(1.0, f.c);
    CHECK_EQ(2.0, f.d);
    CHECK_EQ(3.0, f.e);
    CHECK_EQ(4.0, f.f);
    CHECK_EQ(5.0, f.g);
    CHECK_EQ(6.0, f.h);
  }
}


TEST(10) {
  // Test VFP multi load/store with db_w.
  CcTest::InitializeVM();
853
  Isolate* isolate = CcTest::i_isolate();
854 855
  HandleScope scope(isolate);

856
  struct D {
857 858 859 860 861 862 863 864
    double a;
    double b;
    double c;
    double d;
    double e;
    double f;
    double g;
    double h;
865
  };
866 867
  D d;

868
  struct F {
869 870 871 872 873 874 875 876
    float a;
    float b;
    float c;
    float d;
    float e;
    float f;
    float g;
    float h;
877
  };
878 879 880 881
  F f;

  // Create a function that uses vldm/vstm to move some double and
  // single precision values around in memory.
882
  Assembler assm(AssemblerOptions{});
883 884 885 886 887

  if (CpuFeatures::IsSupported(VFP2)) {
    CpuFeatures::Scope scope(VFP2);

    __ mov(ip, Operand(sp));
888
    __ stm(db_w, sp, {r4, fp, lr});
889 890
    __ sub(fp, ip, Operand(4));

891
    __ addi(r4, r0, Operand(offsetof(D, h) + 8));
892 893 894
    __ vldm(db_w, r4, d4, d7);
    __ vldm(db_w, r4, d0, d3);

895
    __ addi(r4, r0, Operand(offsetof(D, h) + 8));
896 897 898
    __ vstm(db_w, r4, d0, d5);
    __ vstm(db_w, r4, d6, d7);

899
    __ addi(r4, r1, Operand(offsetof(F, h) + 4));
900 901 902
    __ vldm(db_w, r4, s4, s7);
    __ vldm(db_w, r4, s0, s3);

903
    __ addi(r4, r1, Operand(offsetof(F, h) + 4));
904 905 906
    __ vstm(db_w, r4, s0, s5);
    __ vstm(db_w, r4, s6, s7);

907
    __ ldm(ia_w, sp, {r4, fp, pc});
908 909

    CodeDesc desc;
910
    assm.GetCode(isolate, &desc);
911
    Object code = isolate->heap()->CreateCode(
912
        desc,
913
        CodeKind::FOR_TESTING,
914 915 916
        Handle<Code>())->ToObjectChecked();
    CHECK(code->IsCode());
#ifdef DEBUG
917
    Code::cast(code)->Print();
918
#endif
919
    auto fn = GeneratedCode<F_ppiii>::FromCode(*code);
920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937
    d.a = 1.1;
    d.b = 2.2;
    d.c = 3.3;
    d.d = 4.4;
    d.e = 5.5;
    d.f = 6.6;
    d.g = 7.7;
    d.h = 8.8;

    f.a = 1.0;
    f.b = 2.0;
    f.c = 3.0;
    f.d = 4.0;
    f.e = 5.0;
    f.f = 6.0;
    f.g = 7.0;
    f.h = 8.0;

938
    fn.Call(&d, &f, 0, 0, 0);
939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963

    CHECK_EQ(7.7, d.a);
    CHECK_EQ(8.8, d.b);
    CHECK_EQ(1.1, d.c);
    CHECK_EQ(2.2, d.d);
    CHECK_EQ(3.3, d.e);
    CHECK_EQ(4.4, d.f);
    CHECK_EQ(5.5, d.g);
    CHECK_EQ(6.6, d.h);

    CHECK_EQ(7.0, f.a);
    CHECK_EQ(8.0, f.b);
    CHECK_EQ(1.0, f.c);
    CHECK_EQ(2.0, f.d);
    CHECK_EQ(3.0, f.e);
    CHECK_EQ(4.0, f.f);
    CHECK_EQ(5.0, f.g);
    CHECK_EQ(6.0, f.h);
  }
}


TEST(11) {
  // Test instructions using the carry flag.
  CcTest::InitializeVM();
964
  Isolate* isolate = CcTest::i_isolate();
965 966
  HandleScope scope(isolate);

967
  struct I {
968 969 970 971
    int32_t a;
    int32_t b;
    int32_t c;
    int32_t d;
972
  };
973 974
  I i;

975 976
  i.a = 0xABCD0001;
  i.b = 0xABCD0000;
977

978
  Assembler assm(AssemblerOptions{});
979 980

  // Test HeapObject untagging.
981
  __ ldr(r1, MemOperand(r0, offsetof(I, a)));
982 983
  __ mov(r1, Operand(r1, ASR, 1), SetCC);
  __ adc(r1, r1, Operand(r1), LeaveCC, cs);
984
  __ str(r1, MemOperand(r0, offsetof(I, a)));
985

986
  __ ldr(r2, MemOperand(r0, offsetof(I, b)));
987 988
  __ mov(r2, Operand(r2, ASR, 1), SetCC);
  __ adc(r2, r2, Operand(r2), LeaveCC, cs);
989
  __ str(r2, MemOperand(r0, offsetof(I, b)));
990 991

  // Test corner cases.
992
  __ mov(r1, Operand(0xFFFFFFFF));
993 994 995
  __ mov(r2, Operand::Zero());
  __ mov(r3, Operand(r1, ASR, 1), SetCC);  // Set the carry.
  __ adc(r3, r1, Operand(r2));
996
  __ str(r3, MemOperand(r0, offsetof(I, c)));
997

998
  __ mov(r1, Operand(0xFFFFFFFF));
999 1000 1001
  __ mov(r2, Operand::Zero());
  __ mov(r3, Operand(r2, ASR, 1), SetCC);  // Unset the carry.
  __ adc(r3, r1, Operand(r2));
1002
  __ str(r3, MemOperand(r0, offsetof(I, d)));
1003 1004 1005 1006

  __ mov(pc, Operand(lr));

  CodeDesc desc;
1007
  assm.GetCode(isolate, &desc);
1008
  Object code = isolate->heap()->CreateCode(
1009
      desc,
1010
      CodeKind::FOR_TESTING,
1011 1012 1013
      Handle<Code>())->ToObjectChecked();
  CHECK(code->IsCode());
#ifdef DEBUG
1014
  Code::cast(code)->Print();
1015
#endif
1016 1017
  auto f = GeneratedCode<F_piiii>::FromCode(*code);
  f.Call(&i, 0, 0, 0, 0);
1018

1019 1020
  CHECK_EQ(0xABCD0001, i.a);
  CHECK_EQ(static_cast<int32_t>(0xABCD0000) >> 1, i.b);
1021
  CHECK_EQ(0x00000000, i.c);
1022
  CHECK_EQ(0xFFFFFFFF, i.d);
1023 1024 1025 1026 1027 1028
}


TEST(12) {
  // Test chaining of label usages within instructions (issue 1644).
  CcTest::InitializeVM();
1029
  Isolate* isolate = CcTest::i_isolate();
1030 1031
  HandleScope scope(isolate);

1032
  Assembler assm(AssemblerOptions{});
1033 1034 1035 1036 1037 1038 1039 1040
  Label target;
  __ b(eq, &target);
  __ b(ne, &target);
  __ bind(&target);
  __ nop();
}
#endif

1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085
TEST(WordSizedVectorInstructions) {
  CcTest::InitializeVM();
  Isolate* isolate = CcTest::i_isolate();
  HandleScope scope(isolate);

  Assembler assm(AssemblerOptions{});
  // Testing word sized vector operations.
  __ li(r0, Operand(5));  // v0 = {5, 5, 5, 5}
  __ mtvsrd(v0, r0);
  __ vspltw(v0, v0, Operand(1));

  // Integer
  __ vadduwm(v1, v0, v0);   // v1 = {10, 10, 10, 10}
  __ vmuluwm(v2, v0, v1);   // v2 = {50, 50, 50, 50}
  __ vsubuhm(v3, v2, v0);   // v3 = {45, 45, 45, 45}
  __ vslw(v4, v2, v0);      // v4 = {1600, 1600, 1600, 1600}
  __ vsrw(v5, v2, v0);      // v5 = {1, 1, 1, 1}
  __ vmaxsw(v4, v5, v4);    // v4 = unchanged
  __ vcmpgtuw(v5, v2, v3);  // v5 = all 1s
  __ vand(v4, v4, v5);      // v4 = unchanged
  // FP
  __ xvcvsxwsp(v1, v1);    // v1 = Converted to SP
  __ xvcvsxwsp(v4, v4);    // v4 = Converted to SP
  __ xvdivsp(v4, v4, v1);  // v4 = {160, 160, 160, 160}
  // Integer
  __ xvcvspuxws(v4, v4);  // v4 = Converted to Int
  __ vor(v0, v4, v3);     // v0 = {173, 173, 173, 173}

  __ vupkhsw(v0, v0);  // v0 = {173, 173}
  __ mfvsrd(r3, v0);
  __ blr();

  CodeDesc desc;
  assm.GetCode(isolate, &desc);
  Handle<Code> code =
      Factory::CodeBuilder(isolate, desc, CodeKind::FOR_TESTING).Build();
#ifdef DEBUG
  code->Print();
#endif
  auto f = GeneratedCode<F_iiiii>::FromCode(*code);
  intptr_t res = reinterpret_cast<intptr_t>(f.Call(0, 0, 0, 0, 0));
  ::printf("f() = %" V8PRIdPTR "\n", res);
  CHECK_EQ(173, static_cast<int>(res));
}

1086
#undef __
1087 1088 1089

}  // namespace internal
}  // namespace v8