diff options
author | Michaƫl Zasso <targos@protonmail.com> | 2017-09-12 11:34:59 +0200 |
---|---|---|
committer | Anna Henningsen <anna@addaleax.net> | 2017-09-13 16:15:18 +0200 |
commit | d82e1075dbc2cec2d6598ade10c1f43805f690fd (patch) | |
tree | ccd242b9b491dfc341d1099fe11b0ef528839877 /deps/v8/test/cctest/test-assembler-mips64.cc | |
parent | b4b7ac6ae811b2b5a3082468115dfb5a5246fe3f (diff) | |
download | android-node-v8-d82e1075dbc2cec2d6598ade10c1f43805f690fd.tar.gz android-node-v8-d82e1075dbc2cec2d6598ade10c1f43805f690fd.tar.bz2 android-node-v8-d82e1075dbc2cec2d6598ade10c1f43805f690fd.zip |
deps: update V8 to 6.1.534.36
PR-URL: https://github.com/nodejs/node/pull/14730
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Ali Ijaz Sheikh <ofrobots@google.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Diffstat (limited to 'deps/v8/test/cctest/test-assembler-mips64.cc')
-rw-r--r-- | deps/v8/test/cctest/test-assembler-mips64.cc | 1958 |
1 files changed, 1852 insertions, 106 deletions
diff --git a/deps/v8/test/cctest/test-assembler-mips64.cc b/deps/v8/test/cctest/test-assembler-mips64.cc index d796b4faad..b5a05f323b 100644 --- a/deps/v8/test/cctest/test-assembler-mips64.cc +++ b/deps/v8/test/cctest/test-assembler-mips64.cc @@ -46,7 +46,7 @@ typedef Object* (*F1)(int x, int p1, int p2, int p3, int p4); typedef Object* (*F2)(int x, int y, int p2, int p3, int p4); typedef Object* (*F3)(void* p, int p1, int p2, int p3, int p4); typedef Object* (*F4)(int64_t x, int64_t y, int64_t p2, int64_t p3, int64_t p4); - +typedef Object* (*F5)(void* p0, void* p1, int p2, int p3, int p4); #define __ assm. @@ -63,7 +63,7 @@ TEST(MIPS0) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F2 f = FUNCTION_CAST<F2>(code->entry()); @@ -99,7 +99,7 @@ TEST(MIPS1) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F1 f = FUNCTION_CAST<F1>(code->entry()); @@ -245,7 +245,7 @@ TEST(MIPS2) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F2 f = FUNCTION_CAST<F2>(code->entry()); @@ -316,7 +316,7 @@ TEST(MIPS3) { if (kArchVariant == kMips64r2) { __ Ldc1(f4, MemOperand(a0, offsetof(T, h))); __ Ldc1(f6, MemOperand(a0, offsetof(T, i))); - __ madd_d(f14, f6, f4, f6); + __ Madd_d(f14, f6, f4, f6, f8); __ Sdc1(f14, MemOperand(a0, offsetof(T, h))); } @@ -348,7 +348,7 @@ TEST(MIPS3) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -442,7 +442,7 @@ TEST(MIPS4) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -508,7 +508,7 @@ TEST(MIPS5) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -578,7 +578,7 @@ TEST(MIPS6) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -665,7 +665,7 @@ TEST(MIPS7) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -763,7 +763,7 @@ TEST(MIPS8) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -809,7 +809,7 @@ TEST(MIPS9) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); } @@ -885,7 +885,7 @@ TEST(MIPS10) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -1021,7 +1021,7 @@ TEST(MIPS11) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -1146,7 +1146,7 @@ TEST(MIPS12) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -1200,7 +1200,7 @@ TEST(MIPS13) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -1321,7 +1321,7 @@ TEST(MIPS14) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -1451,7 +1451,7 @@ TEST(MIPS16) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -1580,7 +1580,7 @@ TEST(seleqz_selnez) { __ jr(ra); __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -1696,7 +1696,7 @@ TEST(min_max) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -1805,7 +1805,7 @@ TEST(rint_d) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -1853,7 +1853,7 @@ TEST(sel) { __ jr(ra); __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -1986,7 +1986,7 @@ TEST(rint_s) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -2072,7 +2072,7 @@ TEST(mina_maxa) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -2154,7 +2154,7 @@ TEST(trunc_l) { __ nop(); Test test; CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -2235,7 +2235,7 @@ TEST(movz_movn) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -2336,7 +2336,7 @@ TEST(movt_movd) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -2422,7 +2422,7 @@ TEST(cvt_w_d) { __ nop(); Test test; CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -2489,7 +2489,7 @@ TEST(trunc_w) { __ nop(); Test test; CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -2558,7 +2558,7 @@ TEST(round_w) { __ nop(); Test test; CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -2629,7 +2629,7 @@ TEST(round_l) { __ nop(); Test test; CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -2701,7 +2701,7 @@ TEST(sub) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -2773,7 +2773,7 @@ TEST(sqrt_rsqrt_recip) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -2851,7 +2851,7 @@ TEST(neg) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -2909,7 +2909,7 @@ TEST(mul) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -2964,7 +2964,7 @@ TEST(mov) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -3031,7 +3031,7 @@ TEST(floor_w) { __ nop(); Test test; CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -3102,7 +3102,7 @@ TEST(floor_l) { __ nop(); Test test; CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -3173,7 +3173,7 @@ TEST(ceil_w) { __ nop(); Test test; CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -3244,7 +3244,7 @@ TEST(ceil_l) { __ nop(); Test test; CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -3315,7 +3315,7 @@ TEST(jump_tables1) { CHECK_EQ(0, assm.UnboundLabelsCount()); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); #ifdef OBJECT_PRINT @@ -3385,7 +3385,7 @@ TEST(jump_tables2) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); #ifdef OBJECT_PRINT @@ -3465,7 +3465,7 @@ TEST(jump_tables3) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); #ifdef OBJECT_PRINT @@ -3539,7 +3539,7 @@ TEST(BITSWAP) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -3682,7 +3682,7 @@ TEST(class_fmt) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -3776,7 +3776,7 @@ TEST(ABS) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -3869,7 +3869,7 @@ TEST(ADD_FMT) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -4024,7 +4024,7 @@ TEST(C_COND_FMT) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -4225,7 +4225,7 @@ TEST(CMP_COND_FMT) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -4403,7 +4403,7 @@ TEST(CVT) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -4574,7 +4574,7 @@ TEST(DIV_FMT) { __ jr(ra); __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -4665,7 +4665,7 @@ uint64_t run_align(uint64_t rs_value, uint64_t rt_value, uint8_t bp) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); @@ -4718,7 +4718,7 @@ uint64_t run_dalign(uint64_t rs_value, uint64_t rt_value, uint8_t bp) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); @@ -4776,7 +4776,7 @@ uint64_t run_aluipc(int16_t offset) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); @@ -4830,7 +4830,7 @@ uint64_t run_auipc(int16_t offset) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); @@ -4885,7 +4885,7 @@ uint64_t run_aui(uint64_t rs, uint16_t offset) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); @@ -4911,7 +4911,7 @@ uint64_t run_daui(uint64_t rs, uint16_t offset) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); @@ -4937,7 +4937,7 @@ uint64_t run_dahi(uint64_t rs, uint16_t offset) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); @@ -4963,7 +4963,7 @@ uint64_t run_dati(uint64_t rs, uint16_t offset) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); @@ -5053,22 +5053,27 @@ TEST(r6_aui_family) { } } - -uint64_t run_li_macro(uint64_t rs, LiFlags mode) { +uint64_t run_li_macro(uint64_t imm, LiFlags mode, int32_t num_instr = 0) { Isolate* isolate = CcTest::i_isolate(); HandleScope scope(isolate); MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes); - __ li(a0, rs, mode); - __ mov(v0, a0); + Label code_start; + __ bind(&code_start); + __ li(v0, imm, mode); + if (num_instr > 0) { + CHECK_EQ(assm.InstructionsGeneratedSince(&code_start), num_instr); + } __ jr(ra); __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); - +#ifdef OBJECT_PRINT + code->Print(std::cout); +#endif F2 f = FUNCTION_CAST<F2>(code->entry()); uint64_t res = reinterpret_cast<uint64_t>( @@ -5081,23 +5086,163 @@ uint64_t run_li_macro(uint64_t rs, LiFlags mode) { TEST(li_macro) { CcTest::InitializeVM(); - uint64_t inputs[] = { - 0x0000000000000000, 0x000000000000ffff, 0x00000000ffffffff, - 0x0000ffffffffffff, 0xffffffffffffffff, 0xffff000000000000, - 0xffffffff00000000, 0xffffffffffff0000, 0xffff0000ffff0000, - 0x0000ffffffff0000, 0x0000ffff0000ffff, 0x00007fffffffffff, - 0x7fffffffffffffff, 0x000000007fffffff, 0x00007fff7fffffff, + // Test li macro-instruction for border cases. + + struct TestCase_li { + uint64_t imm; + int32_t r2_num_instr; + int32_t r6_num_instr; + }; + + // We call li(v0, imm) to test cases listed below. + struct TestCase_li tc[] = { + // imm, r2_num_instr, r6_num_instr + {0xffffffffffff8000, 1, 1}, // min_int16 + // The test case above generates daddiu instruction. + // This is int16 value and we can load it using just daddiu. + {0x8000, 1, 1}, // max_int16 + 1 + // Generates ori + // max_int16 + 1 is not int16 but is uint16, just use ori. + {0xffffffffffff7fff, 2, 2}, // min_int16 - 1 + // Generates lui + ori + // We load int32 value using lui + ori. + {0x8001, 1, 1}, // max_int16 + 2 + // Generates ori + // Also an uint16 value, use ori. + {0x00010000, 1, 1}, // max_uint16 + 1 + // Generates lui + // Low 16 bits are 0, load value using lui. + {0x00010001, 2, 2}, // max_uint16 + 2 + // Generates lui + ori + // We have to generate two instructions in this case. + {0x00000000ffffffff, 2, 2}, // max_uint32 + // r2 - daddiu + dsrl32 + // r6 - daddiu + dahi + {0x00000000fffffffe, 3, 2}, // max_uint32 - 1 + // r2 - lui + ori + dsll + // r6 - daddiu + dahi + {0x00ffff000000fffe, 3, 3}, + // ori + dsll32 + ori + {0x00000001fffffffe, 4, 2}, // max_uint32 << 1 + // r2 - lui + ori + dsll + ori + // r6 - daddiu + dahi + {0x0000fffffffffffe, 4, 2}, // max_uint48 - 1 + // r2 - daddiu + dsll32 + ori + dsubu + // Loading imm directly would require ori + dsll + ori + dsll + ori. + // Optimized by loading -imm and using dsubu to get imm. + // r6 - daddiu + dati + {0xffffffff00000000, 2, 2}, // max_uint32 << 32 + // r2 - daddiu + dsll32 + // r6 - ori + dahi + // We need ori to clear register before loading value using dahi. + {0xffffffff80000000, 1, 1}, // min_int32 + // The test case above generates lui instruction. + {0x0000000080000000, 2, 2}, // max_int32 + 1 + // r2 - ori + dsll + // r6 - lui + dahi + {0x0000800000000000, 2, 2}, + // ori + dsll32 + {0xffff800000000000, 2, 2}, + // r2 - daddiu + dsll32 + // r6 - ori + dahi + {0xffff80000000ffff, 3, 2}, + // r2 - daddiu + dsll32 + ori + // r6 - ori + dahi + {0xffffff123000ffff, 3, 3}, + // daddiu + dsll + ori + {0xffff00000000ffff, 3, 2}, + // r2 - daddiu + dsll32 + ori + // r6 - ori + dati + {0xffff8000ffff0000, 3, 2}, + // r2 - lui + ori + dsll + // r6 - lui + dahi + {0x0000ffffffff0000, 4, 2}, + // r2 - ori + dsll + ori + dsll + // r6 - lui + dati + {0x1234ffff80000000, 3, 2}, + // r2 - lui + ori + dsll + // r6 - lui + dati + {0x1234ffff80010000, 5, 2}, + // r2 - lui + ori + dsll + ori + dsll + // r6 - lui + dati + {0xffff8000ffff8000, 2, 2}, + // r2 - daddiu + dinsu + // r6 - daddiu + dahi + {0xffff0000ffff8000, 4, 3}, + // r2 - ori + dsll32 + ori + dsubu + // Loading imm directly would require lui + dsll + ori + dsll + ori. + // Optimized by loading -imm and using dsubu to get imm. + // r6 - daddiu + dahi + dati + {0x8000000080000000, 2, 2}, + // lui + dinsu + {0xabcd0000abcd0000, 2, 2}, + // lui + dinsu + {0x8000800080008000, 3, 3}, + // lui + ori + dinsu + {0xabcd1234abcd1234, 3, 3}, + // The test case above generates lui + ori + dinsu instruction sequence. + {0xffff800080008000, 4, 3}, + // r2 - lui + ori + dsll + ori + // r6 - lui + ori + dahi + {0xffffabcd, 3, 2}, + // r2 - ori + dsll + ori + // r6 - daddiu + dahi + {0x1ffffabcd, 4, 2}, + // r2 - lui + ori + dsll + ori + // r6 - daddiu + dahi + {0xffffffffabcd, 4, 2}, + // r2 - daddiu + dsll32 + ori + dsubu + // Loading imm directly would require ori + dsll + ori + dsll + ori. + // Optimized by loading -imm and using dsubu to get imm. + // r6 - daddiu + dati + {0x1ffffffffabcd, 4, 2}, + // r2 - daddiu + dsll32 + ori + dsubu + // Loading imm directly would require lui + ori + dsll + ori + dsll + ori. + // Optimized by loading -imm and using dsubu to get imm. + // r6 - daddiu + dati + {0xffff7fff80010000, 5, 2}, + // r2 - lui + ori + dsll + ori + dsll + // r6 - lui + dahi + // Here lui sets high 32 bits to 1 so dahi can be used to get target + // value. + {0x00007fff7fff0000, 3, 2}, + // r2 - lui + ori + dsll + // r6 - lui + dahi + // High 32 bits are not set so dahi can be used to get target value. + {0xffff7fff7fff0000, 5, 3}, + // r2 - lui + ori + dsll + ori + dsll + // r6 - lui + dahi + dati + // High 32 bits are not set so just dahi can't be used to get target + // value. + {0x00007fff80010000, 3, 3}, + // r2 - lui + ori + dsll + // r6 - lui + ori + dsll + // High 32 bits are set so can't just use lui + dahi to get target value. + {0x1234abcd87654321, 6, 4}, + // The test case above generates: + // r2 - lui + ori + dsll + ori + dsll + ori instruction sequence, + // r6 - lui + ori + dahi + dati. + // Load using full instruction sequence. + {0xffff0000ffffffff, 3, 3}, + // r2 - ori + dsll32 + nor + // Loading imm directly would require lui + dsll + ori + dsll + ori. + // Optimized by loading ~imm and using nor to get imm. Loading -imm would + // require one instruction more. + // r6 - daddiu + dahi + dati }; - size_t nr_test_cases = sizeof(inputs) / sizeof(inputs[0]); + size_t nr_test_cases = sizeof(tc) / sizeof(TestCase_li); for (size_t i = 0; i < nr_test_cases; ++i) { - uint64_t res = run_li_macro(inputs[i], OPTIMIZE_SIZE); - CHECK_EQ(inputs[i], res); - res = run_li_macro(inputs[i], CONSTANT_SIZE); - CHECK_EQ(inputs[i], res); - if (is_int48(inputs[i])) { - res = run_li_macro(inputs[i], ADDRESS_LOAD); - CHECK_EQ(inputs[i], res); + if (kArchVariant == kMips64r2) { + CHECK_EQ(tc[i].imm, + run_li_macro(tc[i].imm, OPTIMIZE_SIZE, tc[i].r2_num_instr)); + } else { + CHECK_EQ(tc[i].imm, + run_li_macro(tc[i].imm, OPTIMIZE_SIZE, tc[i].r6_num_instr)); + } + CHECK_EQ(tc[i].imm, run_li_macro(tc[i].imm, CONSTANT_SIZE)); + if (is_int48(tc[i].imm)) { + CHECK_EQ(tc[i].imm, run_li_macro(tc[i].imm, ADDRESS_LOAD)); } } } @@ -5136,7 +5281,7 @@ uint64_t run_lwpc(int offset) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); @@ -5212,7 +5357,7 @@ uint64_t run_lwupc(int offset) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); @@ -5296,7 +5441,7 @@ uint64_t run_jic(int16_t offset) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); @@ -5368,7 +5513,7 @@ uint64_t run_beqzc(int32_t value, int32_t offset) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); @@ -5462,7 +5607,7 @@ uint64_t run_jialc(int16_t offset) { CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); @@ -5514,7 +5659,7 @@ uint64_t run_addiupc(int32_t imm19) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); @@ -5590,7 +5735,7 @@ uint64_t run_ldpc(int offset) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); @@ -5679,7 +5824,7 @@ int64_t run_bc(int32_t offset) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); @@ -5761,7 +5906,7 @@ int64_t run_balc(int32_t offset) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); @@ -5811,7 +5956,7 @@ uint64_t run_dsll(uint64_t rt_value, uint16_t sa_value) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); @@ -5867,7 +6012,7 @@ uint64_t run_bal(int16_t offset) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); @@ -5921,7 +6066,7 @@ TEST(Trampoline) { __ mov(v0, zero_reg); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F2 f = FUNCTION_CAST<F2>(code->entry()); @@ -5988,7 +6133,7 @@ void helper_madd_msub_maddf_msubf(F func) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F3 f = FUNCTION_CAST<F3>(code->entry()); @@ -6020,9 +6165,9 @@ void helper_madd_msub_maddf_msubf(F func) { TEST(madd_msub_s) { if (kArchVariant == kMips64r6) return; helper_madd_msub_maddf_msubf<float>([](MacroAssembler& assm) { - __ madd_s(f10, f4, f6, f8); + __ Madd_s(f10, f4, f6, f8, f12); __ Swc1(f10, MemOperand(a0, offsetof(TestCaseMaddMsub<float>, fd_add))); - __ msub_s(f16, f4, f6, f8); + __ Msub_s(f16, f4, f6, f8, f12); __ Swc1(f16, MemOperand(a0, offsetof(TestCaseMaddMsub<float>, fd_sub))); }); } @@ -6030,9 +6175,9 @@ TEST(madd_msub_s) { TEST(madd_msub_d) { if (kArchVariant == kMips64r6) return; helper_madd_msub_maddf_msubf<double>([](MacroAssembler& assm) { - __ madd_d(f10, f4, f6, f8); + __ Madd_d(f10, f4, f6, f8, f12); __ Sdc1(f10, MemOperand(a0, offsetof(TestCaseMaddMsub<double>, fd_add))); - __ msub_d(f16, f4, f6, f8); + __ Msub_d(f16, f4, f6, f8, f12); __ Sdc1(f16, MemOperand(a0, offsetof(TestCaseMaddMsub<double>, fd_sub))); }); } @@ -6057,6 +6202,185 @@ TEST(maddf_msubf_d) { }); } +uint64_t run_Subu(uint64_t imm, int32_t num_instr) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes); + + Label code_start; + __ bind(&code_start); + __ Subu(v0, zero_reg, Operand(imm)); + CHECK_EQ(assm.InstructionsGeneratedSince(&code_start), num_instr); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(isolate, &desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); +#ifdef OBJECT_PRINT + code->Print(std::cout); +#endif + F2 f = FUNCTION_CAST<F2>(code->entry()); + + uint64_t res = reinterpret_cast<uint64_t>( + CALL_GENERATED_CODE(isolate, f, 0, 0, 0, 0, 0)); + + return res; +} + +TEST(Subu) { + CcTest::InitializeVM(); + + // Test Subu macro-instruction for min_int16 and max_int16 border cases. + // For subtracting int16 immediate values we use addiu. + + struct TestCaseSubu { + uint64_t imm; + uint64_t expected_res; + int32_t num_instr; + }; + + // We call Subu(v0, zero_reg, imm) to test cases listed below. + // 0 - imm = expected_res + struct TestCaseSubu tc[] = { + // imm, expected_res, num_instr + {0xffffffffffff8000, 0x8000, 2}, // min_int16 + // The test case above generates ori + addu instruction sequence. + // We can't have just addiu because -min_int16 > max_int16 so use + // register. We can load min_int16 to at register with addiu and then + // subtract at with subu, but now we use ori + addu because -min_int16 can + // be loaded using ori. + {0x8000, 0xffffffffffff8000, 1}, // max_int16 + 1 + // Generates addiu + // max_int16 + 1 is not int16 but -(max_int16 + 1) is, just use addiu. + {0xffffffffffff7fff, 0x8001, 2}, // min_int16 - 1 + // Generates ori + addu + // To load this value to at we need two instructions and another one to + // subtract, lui + ori + subu. But we can load -value to at using just + // ori and then add at register with addu. + {0x8001, 0xffffffffffff7fff, 2}, // max_int16 + 2 + // Generates ori + subu + // Not int16 but is uint16, load value to at with ori and subtract with + // subu. + {0x00010000, 0xffffffffffff0000, 2}, + // Generates lui + subu + // Load value using lui to at and subtract with subu. + {0x00010001, 0xfffffffffffeffff, 3}, + // Generates lui + ori + subu + // We have to generate three instructions in this case. + {0x7fffffff, 0xffffffff80000001, 3}, // max_int32 + // Generates lui + ori + subu + {0xffffffff80000000, 0xffffffff80000000, 2}, // min_int32 + // The test case above generates lui + subu intruction sequence. + // The result of 0 - min_int32 eqauls max_int32 + 1, which wraps around to + // min_int32 again. + }; + + size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseSubu); + for (size_t i = 0; i < nr_test_cases; ++i) { + CHECK_EQ(tc[i].expected_res, run_Subu(tc[i].imm, tc[i].num_instr)); + } +} + +uint64_t run_Dsubu(uint64_t imm, int32_t num_instr) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes); + + Label code_start; + __ bind(&code_start); + __ Dsubu(v0, zero_reg, Operand(imm)); + CHECK_EQ(assm.InstructionsGeneratedSince(&code_start), num_instr); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(isolate, &desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); +#ifdef OBJECT_PRINT + code->Print(std::cout); +#endif + F2 f = FUNCTION_CAST<F2>(code->entry()); + + uint64_t res = reinterpret_cast<uint64_t>( + CALL_GENERATED_CODE(isolate, f, 0, 0, 0, 0, 0)); + + return res; +} + +TEST(Dsubu) { + CcTest::InitializeVM(); + + // Test Dsubu macro-instruction for min_int16 and max_int16 border cases. + // For subtracting int16 immediate values we use daddiu. + + struct TestCaseDsubu { + uint64_t imm; + uint64_t expected_res; + int32_t num_instr; + }; + + // We call Dsubu(v0, zero_reg, imm) to test cases listed below. + // 0 - imm = expected_res + struct TestCaseDsubu tc[] = { + // imm, expected_res, num_instr + {0xffffffffffff8000, 0x8000, 2}, // min_int16 + // The test case above generates ori + daddu instruction sequence. + // We can't have just daddiu because -min_int16 > max_int16 so use + // register. We can load min_int16 to at register with daddiu and then + // subtract at with dsubu, but now we use ori + daddu because -min_int16 + // can be loaded using ori. + {0x8000, 0xffffffffffff8000, 1}, // max_int16 + 1 + // Generates daddiu + // max_int16 + 1 is not int16 but -(max_int16 + 1) is, just use daddiu. + {0xffffffffffff7fff, 0x8001, 2}, // min_int16 - 1 + // Generates ori + daddu + // To load this value to at we need two instructions and another one to + // subtract, lui + ori + dsubu. But we can load -value to at using just + // ori and then dadd at register with daddu. + {0x8001, 0xffffffffffff7fff, 2}, // max_int16 + 2 + // Generates ori + dsubu + // Not int16 but is uint16, load value to at with ori and subtract with + // dsubu. + {0x00010000, 0xffffffffffff0000, 2}, + // Generates lui + dsubu + // Load value using lui to at and subtract with dsubu. + {0x00010001, 0xfffffffffffeffff, 3}, + // Generates lui + ori + dsubu + // We have to generate three instructions in this case. + {0x7fffffff, 0xffffffff80000001, 3}, // max_int32 + // Generates lui + ori + dsubu + {0xffffffff80000000, 0x0000000080000000, 2}, // min_int32 + // Generates lui + dsubu + // The result of 0 - min_int32 eqauls max_int32 + 1, which fits into a 64 + // bit register, Dsubu gives a different result here. + {0x7fffffffffffffff, 0x8000000000000001, 3}, // max_int64 + // r2 - Generates daddiu + dsrl + dsubu + // r6 - Generates daddiu + dati + dsubu + {0x8000000000000000, 0x8000000000000000, 3}, // min_int64 + // The test case above generates: + // r2 - daddiu + dsrl32 + dsubu instruction sequence, + // r6 - ori + dati + dsubu. + // The result of 0 - min_int64 eqauls max_int64 + 1, which wraps around to + // min_int64 again. + {0xffff0000ffffffff, 0x0000ffff00000001, 4}, + // The test case above generates: + // r2 - ori + dsrl32 + ori + daddu instruction sequence, + // r6 - daddiu + dahi + dati + dsubu. + // For r2 loading imm would take more instructions than loading -imm so we + // can load -imm and add with daddu. + }; + + size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseDsubu); + for (size_t i = 0; i < nr_test_cases; ++i) { + CHECK_EQ(tc[i].expected_res, run_Dsubu(tc[i].imm, tc[i].num_instr)); + } +} + uint64_t run_Dins(uint64_t imm, uint64_t source, uint16_t pos, uint16_t size) { Isolate* isolate = CcTest::i_isolate(); HandleScope scope(isolate); @@ -6070,7 +6394,7 @@ uint64_t run_Dins(uint64_t imm, uint64_t source, uint16_t pos, uint16_t size) { __ nop(); CodeDesc desc; - assm.GetCode(&desc); + assm.GetCode(isolate, &desc); Handle<Code> code = isolate->factory()->NewCode( desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); F2 f = FUNCTION_CAST<F2>(code->entry()); @@ -6098,15 +6422,15 @@ TEST(Dins) { // Dins(v0, t0, pos, size) to test cases listed below. struct TestCaseDins tc[] = { // imm, source, pos, size, expected_res - {0x5555555555555555, 0x1ABCDEF01, 31, 1, 0x55555555D5555555}, - {0x5555555555555555, 0x1ABCDEF02, 30, 2, 0x5555555595555555}, - {0x201234567, 0x1FABCDEFF, 0, 32, 0x2FABCDEFF}, - {0x201234567, 0x7FABCDEFF, 31, 2, 0x381234567}, - {0x800000000, 0x7FABCDEFF, 0, 33, 0x9FABCDEFF}, - {0x1234, 0xABCDABCDABCDABCD, 0, 64, 0xABCDABCDABCDABCD}, - {0xABCD, 0xABCEABCF, 32, 1, 0x10000ABCD}, - {0xABCD, 0xABCEABCF, 63, 1, 0x800000000000ABCD}, - {0xABCD, 0xABC1ABC2ABC3ABC4, 32, 32, 0xABC3ABC40000ABCD}, + {0x5555555555555555, 0x1abcdef01, 31, 1, 0x55555555d5555555}, + {0x5555555555555555, 0x1abcdef02, 30, 2, 0x5555555595555555}, + {0x201234567, 0x1fabcdeff, 0, 32, 0x2fabcdeff}, + {0x201234567, 0x7fabcdeff, 31, 2, 0x381234567}, + {0x800000000, 0x7fabcdeff, 0, 33, 0x9fabcdeff}, + {0x1234, 0xabcdabcdabcdabcd, 0, 64, 0xabcdabcdabcdabcd}, + {0xabcd, 0xabceabcf, 32, 1, 0x10000abcd}, + {0xabcd, 0xabceabcf, 63, 1, 0x800000000000abcd}, + {0x10000abcd, 0xabc1abc2abc3abc4, 32, 32, 0xabc3abc40000abcd}, }; size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseDins); @@ -6116,4 +6440,1426 @@ TEST(Dins) { } } +uint64_t run_Ins(uint64_t imm, uint64_t source, uint16_t pos, uint16_t size) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes); + + __ li(v0, imm); + __ li(t0, source); + __ Ins(v0, t0, pos, size); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(isolate, &desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F2 f = FUNCTION_CAST<F2>(code->entry()); + + uint64_t res = reinterpret_cast<uint64_t>( + CALL_GENERATED_CODE(isolate, f, 0, 0, 0, 0, 0)); + + return res; +} + +TEST(Ins) { + CcTest::InitializeVM(); + + // run_Ins(rt_value, rs_value, pos, size), + // expected_result + CHECK_EQ(run_Ins(0x0000000055555555, 0xffffffffabcdef01, 31, 1), + 0xffffffffd5555555); + CHECK_EQ(run_Ins(0x0000000055555555, 0xffffffffabcdef02, 30, 2), + 0xffffffff95555555); + CHECK_EQ(run_Ins(0x0000000001234567, 0xfffffffffabcdeff, 0, 32), + 0xfffffffffabcdeff); + + // Results with positive sign. + CHECK_EQ(run_Ins(0x0000000055555550, 0xffffffff80000001, 0, 1), + 0x0000000055555551); + CHECK_EQ(run_Ins(0x0000000055555555, 0x0000000040000001, 0, 32), + 0x0000000040000001); + CHECK_EQ(run_Ins(0x0000000055555555, 0x0000000020000001, 1, 31), + 0x0000000040000003); + CHECK_EQ(run_Ins(0x0000000055555555, 0xffffffff80700001, 8, 24), + 0x0000000070000155); + CHECK_EQ(run_Ins(0x0000000055555555, 0xffffffff80007001, 16, 16), + 0x0000000070015555); + CHECK_EQ(run_Ins(0x0000000055555555, 0xffffffff80000071, 24, 8), + 0x0000000071555555); + CHECK_EQ(run_Ins(0x0000000075555555, 0x0000000040000000, 31, 1), + 0x0000000075555555); + + // Results with negative sign. + CHECK_EQ(run_Ins(0xffffffff85555550, 0xffffffff80000001, 0, 1), + 0xffffffff85555551); + CHECK_EQ(run_Ins(0x0000000055555555, 0xffffffff80000001, 0, 32), + 0xffffffff80000001); + CHECK_EQ(run_Ins(0x0000000055555555, 0x0000000040000001, 1, 31), + 0xffffffff80000003); + CHECK_EQ(run_Ins(0x0000000055555555, 0xffffffff80800001, 8, 24), + 0xffffffff80000155); + CHECK_EQ(run_Ins(0x0000000055555555, 0xffffffff80008001, 16, 16), + 0xffffffff80015555); + CHECK_EQ(run_Ins(0x0000000055555555, 0xffffffff80000081, 24, 8), + 0xffffffff81555555); + CHECK_EQ(run_Ins(0x0000000075555555, 0x0000000000000001, 31, 1), + 0xfffffffff5555555); +} + +uint64_t run_Ext(uint64_t source, uint16_t pos, uint16_t size) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes); + + __ li(v0, 0xffffffffffffffff); + __ li(t0, source); + __ Ext(v0, t0, pos, size); + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(isolate, &desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); + F2 f = FUNCTION_CAST<F2>(code->entry()); + + uint64_t res = reinterpret_cast<uint64_t>( + CALL_GENERATED_CODE(isolate, f, 0, 0, 0, 0, 0)); + + return res; +} + +TEST(Ext) { + CcTest::InitializeVM(); + + // Source values with negative sign. + // run_Ext(rs_value, pos, size), expected_result + CHECK_EQ(run_Ext(0xffffffff80000001, 0, 1), 0x0000000000000001); + CHECK_EQ(run_Ext(0xffffffff80000001, 0, 32), 0xffffffff80000001); + CHECK_EQ(run_Ext(0xffffffff80000002, 1, 31), 0x0000000040000001); + CHECK_EQ(run_Ext(0xffffffff80000100, 8, 24), 0x0000000000800001); + CHECK_EQ(run_Ext(0xffffffff80010000, 16, 16), 0x0000000000008001); + CHECK_EQ(run_Ext(0xffffffff81000000, 24, 8), 0x0000000000000081); + CHECK_EQ(run_Ext(0xffffffff80000000, 31, 1), 0x0000000000000001); + + // Source values with positive sign. + CHECK_EQ(run_Ext(0x0000000000000001, 0, 1), 0x0000000000000001); + CHECK_EQ(run_Ext(0x0000000040000001, 0, 32), 0x0000000040000001); + CHECK_EQ(run_Ext(0x0000000040000002, 1, 31), 0x0000000020000001); + CHECK_EQ(run_Ext(0x0000000040000100, 8, 24), 0x0000000000400001); + CHECK_EQ(run_Ext(0x0000000040010000, 16, 16), 0x0000000000004001); + CHECK_EQ(run_Ext(0x0000000041000000, 24, 8), 0x0000000000000041); + CHECK_EQ(run_Ext(0x0000000040000000, 31, 1), 0x0000000000000000); +} + +TEST(MSA_fill_copy) { + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + typedef struct { + uint64_t u8; + uint64_t u16; + uint64_t u32; + uint64_t s8; + uint64_t s16; + uint64_t s32; + uint64_t s64; + } T; + T t; + + MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes); + if ((kArchVariant != kMips64r6) || !CpuFeatures::IsSupported(MIPS_SIMD)) + return; + + { + CpuFeatureScope fscope(&assm, MIPS_SIMD); + + __ li(t0, 0x9e7689aca512b683); + + __ fill_b(w0, t0); + __ fill_h(w2, t0); + __ fill_w(w4, t0); + __ fill_d(w6, t0); + __ copy_u_b(t1, w0, 11); + __ sd(t1, MemOperand(a0, offsetof(T, u8))); + __ copy_u_h(t1, w2, 6); + __ sd(t1, MemOperand(a0, offsetof(T, u16))); + __ copy_u_w(t1, w4, 3); + __ sd(t1, MemOperand(a0, offsetof(T, u32))); + + __ copy_s_b(t1, w0, 8); + __ sd(t1, MemOperand(a0, offsetof(T, s8))); + __ copy_s_h(t1, w2, 5); + __ sd(t1, MemOperand(a0, offsetof(T, s16))); + __ copy_s_w(t1, w4, 1); + __ sd(t1, MemOperand(a0, offsetof(T, s32))); + __ copy_s_d(t1, w6, 0); + __ sd(t1, MemOperand(a0, offsetof(T, s64))); + + __ jr(ra); + __ nop(); + } + + CodeDesc desc; + assm.GetCode(isolate, &desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); +#ifdef OBJECT_PRINT + code->Print(std::cout); +#endif + F3 f = FUNCTION_CAST<F3>(code->entry()); + + Object* dummy = CALL_GENERATED_CODE(isolate, f, &t, 0, 0, 0, 0); + USE(dummy); + + CHECK_EQ(0x83u, t.u8); + CHECK_EQ(0xb683u, t.u16); + CHECK_EQ(0xa512b683u, t.u32); + CHECK_EQ(0xffffffffffffff83u, t.s8); + CHECK_EQ(0xffffffffffffb683u, t.s16); + CHECK_EQ(0xffffffffa512b683u, t.s32); + CHECK_EQ(0x9e7689aca512b683u, t.s64); +} + +TEST(MSA_fill_copy_2) { + // Similar to MSA_fill_copy test, but also check overlaping between MSA and + // FPU registers with same numbers + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + typedef struct { + uint64_t d0; + uint64_t d1; + } T; + T t[2]; + + MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes); + if ((kArchVariant != kMips64r6) || !CpuFeatures::IsSupported(MIPS_SIMD)) + return; + + { + CpuFeatureScope fscope(&assm, MIPS_SIMD); + + __ li(t0, 0xaaaaaaaaaaaaaaaa); + __ li(t1, 0x5555555555555555); + + __ fill_d(w0, t0); + __ fill_d(w2, t0); + + __ Move(f0, t1); + __ Move(f2, t1); + +#define STORE_MSA_REG(w_reg, base, scratch) \ + __ copy_s_d(scratch, w_reg, 0); \ + __ sd(scratch, MemOperand(base, offsetof(T, d0))); \ + __ copy_s_d(scratch, w_reg, 1); \ + __ sd(scratch, MemOperand(base, offsetof(T, d1))); + + STORE_MSA_REG(w0, a0, t2) + STORE_MSA_REG(w2, a1, t2) +#undef STORE_MSA_REG + + __ jr(ra); + __ nop(); + } + + CodeDesc desc; + assm.GetCode(isolate, &desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); +#ifdef OBJECT_PRINT + code->Print(std::cout); +#endif + F5 f = FUNCTION_CAST<F5>(code->entry()); + + Object* dummy = CALL_GENERATED_CODE(isolate, f, &t[0], &t[1], 0, 0, 0); + USE(dummy); + + CHECK_EQ(0x5555555555555555, t[0].d0); + CHECK_EQ(0xaaaaaaaaaaaaaaaa, t[0].d1); + CHECK_EQ(0x5555555555555555, t[1].d0); + CHECK_EQ(0xaaaaaaaaaaaaaaaa, t[1].d1); +} + +TEST(MSA_fill_copy_3) { + // Similar to MSA_fill_copy test, but also check overlaping between MSA and + // FPU registers with same numbers + CcTest::InitializeVM(); + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + typedef struct { + uint64_t d0; + uint64_t d1; + } T; + T t[2]; + + MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes); + if ((kArchVariant != kMips64r6) || !CpuFeatures::IsSupported(MIPS_SIMD)) + return; + + { + CpuFeatureScope fscope(&assm, MIPS_SIMD); + + __ li(t0, 0xaaaaaaaaaaaaaaaa); + __ li(t1, 0x5555555555555555); + + __ Move(f0, t0); + __ Move(f2, t0); + + __ fill_d(w0, t1); + __ fill_d(w2, t1); + + __ Sdc1(f0, MemOperand(a0, offsetof(T, d0))); + __ Sdc1(f2, MemOperand(a1, offsetof(T, d0))); + + __ jr(ra); + __ nop(); + } + + CodeDesc desc; + assm.GetCode(isolate, &desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); +#ifdef OBJECT_PRINT + code->Print(std::cout); +#endif + F5 f = FUNCTION_CAST<F5>(code->entry()); + + Object* dummy = CALL_GENERATED_CODE(isolate, f, &t[0], &t[1], 0, 0, 0); + USE(dummy); + + CHECK_EQ(0x5555555555555555, t[0].d0); + CHECK_EQ(0x5555555555555555, t[1].d0); +} + +typedef union { + uint8_t b[16]; + uint16_t h[8]; + uint32_t w[4]; + uint64_t d[2]; +} msa_reg_t; + +template <typename T> +void run_msa_insert(int64_t rs_value, int n, msa_reg_t* w) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes); + CpuFeatureScope fscope(&assm, MIPS_SIMD); + + __ li(t0, -1); + __ li(t1, rs_value); + __ fill_w(w0, t0); + + if (std::is_same<T, int8_t>::value) { + DCHECK(n < 16); + __ insert_b(w0, n, t1); + } else if (std::is_same<T, int16_t>::value) { + DCHECK(n < 8); + __ insert_h(w0, n, t1); + } else if (std::is_same<T, int32_t>::value) { + DCHECK(n < 4); + __ insert_w(w0, n, t1); + } else if (std::is_same<T, int64_t>::value) { + DCHECK(n < 2); + __ insert_d(w0, n, t1); + } else { + UNREACHABLE(); + } + + __ copy_u_w(t2, w0, 0); + __ sw(t2, MemOperand(a0, 0)); + __ copy_u_w(t2, w0, 1); + __ sw(t2, MemOperand(a0, 4)); + __ copy_u_w(t2, w0, 2); + __ sw(t2, MemOperand(a0, 8)); + __ copy_u_w(t2, w0, 3); + __ sw(t2, MemOperand(a0, 12)); + + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(isolate, &desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); +#ifdef OBJECT_PRINT + code->Print(std::cout); +#endif + F3 f = FUNCTION_CAST<F3>(code->entry()); + + (CALL_GENERATED_CODE(isolate, f, w, 0, 0, 0, 0)); +} + +TEST(MSA_insert) { + if ((kArchVariant != kMips64r6) || !CpuFeatures::IsSupported(MIPS_SIMD)) + return; + + CcTest::InitializeVM(); + + struct TestCaseInsert { + uint64_t input; + int n; + uint64_t exp_res_lo; + uint64_t exp_res_hi; + }; + + struct TestCaseInsert tc_b[] = { + // input, n, exp_res_lo, exp_res_hi + {0xa2, 13, 0xffffffffffffffffu, 0xffffa2ffffffffffu}, + {0x73, 10, 0xffffffffffffffffu, 0xffffffffff73ffffu}, + {0x3494, 5, 0xffff94ffffffffffu, 0xffffffffffffffffu}, + {0xa6b8, 1, 0xffffffffffffb8ffu, 0xffffffffffffffffu}}; + + for (size_t i = 0; i < sizeof(tc_b) / sizeof(TestCaseInsert); ++i) { + msa_reg_t res; + run_msa_insert<int8_t>(tc_b[i].input, tc_b[i].n, &res); + CHECK_EQ(tc_b[i].exp_res_lo, res.d[0]); + CHECK_EQ(tc_b[i].exp_res_hi, res.d[1]); + } + + struct TestCaseInsert tc_h[] = { + // input, n, exp_res_lo, exp_res_hi + {0x85a2, 7, 0xffffffffffffffffu, 0x85a2ffffffffffffu}, + {0xe873, 5, 0xffffffffffffffffu, 0xffffffffe873ffffu}, + {0x3494, 3, 0x3494ffffffffffffu, 0xffffffffffffffffu}, + {0xa6b8, 1, 0xffffffffa6b8ffffu, 0xffffffffffffffffu}}; + + for (size_t i = 0; i < sizeof(tc_h) / sizeof(TestCaseInsert); ++i) { + msa_reg_t res; + run_msa_insert<int16_t>(tc_h[i].input, tc_h[i].n, &res); + CHECK_EQ(tc_h[i].exp_res_lo, res.d[0]); + CHECK_EQ(tc_h[i].exp_res_hi, res.d[1]); + } + + struct TestCaseInsert tc_w[] = { + // input, n, exp_res_lo, exp_res_hi + {0xd2f085a2u, 3, 0xffffffffffffffffu, 0xd2f085a2ffffffffu}, + {0x4567e873u, 2, 0xffffffffffffffffu, 0xffffffff4567e873u}, + {0xacdb3494u, 1, 0xacdb3494ffffffffu, 0xffffffffffffffffu}, + {0x89aba6b8u, 0, 0xffffffff89aba6b8u, 0xffffffffffffffffu}}; + + for (size_t i = 0; i < sizeof(tc_w) / sizeof(TestCaseInsert); ++i) { + msa_reg_t res; + run_msa_insert<int32_t>(tc_w[i].input, tc_w[i].n, &res); + CHECK_EQ(tc_w[i].exp_res_lo, res.d[0]); + CHECK_EQ(tc_w[i].exp_res_hi, res.d[1]); + } + + struct TestCaseInsert tc_d[] = { + // input, n, exp_res_lo, exp_res_hi + {0xf35862e13e38f8b0, 1, 0xffffffffffffffffu, 0xf35862e13e38f8b0}, + {0x4f41ffdef2bfe636, 0, 0x4f41ffdef2bfe636, 0xffffffffffffffffu}}; + + for (size_t i = 0; i < sizeof(tc_d) / sizeof(TestCaseInsert); ++i) { + msa_reg_t res; + run_msa_insert<int64_t>(tc_d[i].input, tc_d[i].n, &res); + CHECK_EQ(tc_d[i].exp_res_lo, res.d[0]); + CHECK_EQ(tc_d[i].exp_res_hi, res.d[1]); + } +} + +struct ExpResShf { + uint8_t i8; + uint64_t lo; + uint64_t hi; +}; + +void run_msa_i8(SecondaryField opcode, uint64_t ws_lo, uint64_t ws_hi, + uint8_t i8) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes); + CpuFeatureScope fscope(&assm, MIPS_SIMD); + msa_reg_t res; + uint64_t wd_lo = 0xf35862e13e38f8b0; + uint64_t wd_hi = 0x4f41ffdef2bfe636; + +#define LOAD_W_REG(lo, hi, w_reg) \ + __ li(t0, lo); \ + __ li(t1, hi); \ + __ insert_d(w_reg, 0, t0); \ + __ insert_d(w_reg, 1, t1); + + LOAD_W_REG(ws_lo, ws_hi, w0) + + switch (opcode) { + case ANDI_B: + __ andi_b(w2, w0, i8); + break; + case ORI_B: + __ ori_b(w2, w0, i8); + break; + case NORI_B: + __ nori_b(w2, w0, i8); + break; + case XORI_B: + __ xori_b(w2, w0, i8); + break; + case BMNZI_B: + LOAD_W_REG(wd_lo, wd_hi, w2); + __ bmnzi_b(w2, w0, i8); + break; + case BMZI_B: + LOAD_W_REG(wd_lo, wd_hi, w2); + __ bmzi_b(w2, w0, i8); + break; + case BSELI_B: + LOAD_W_REG(wd_lo, wd_hi, w2); + __ bseli_b(w2, w0, i8); + break; + case SHF_B: + __ shf_b(w2, w0, i8); + break; + case SHF_H: + __ shf_h(w2, w0, i8); + break; + case SHF_W: + __ shf_w(w2, w0, i8); + break; + default: + UNREACHABLE(); + } + + __ copy_u_w(t2, w2, 0); + __ sw(t2, MemOperand(a0, 0)); + __ copy_u_w(t2, w2, 1); + __ sw(t2, MemOperand(a0, 4)); + __ copy_u_w(t2, w2, 2); + __ sw(t2, MemOperand(a0, 8)); + __ copy_u_w(t2, w2, 3); + __ sw(t2, MemOperand(a0, 12)); + + __ jr(ra); + __ nop(); + +#undef LOAD_W_REG + + CodeDesc desc; + assm.GetCode(isolate, &desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); +#ifdef OBJECT_PRINT + code->Print(std::cout); +#endif + F3 f = FUNCTION_CAST<F3>(code->entry()); + + (CALL_GENERATED_CODE(isolate, f, &res, 0, 0, 0, 0)); + + uint64_t mask = i8 * 0x0101010101010101ull; + switch (opcode) { + case ANDI_B: + CHECK_EQ(ws_lo & mask, res.d[0]); + CHECK_EQ(ws_hi & mask, res.d[1]); + break; + case ORI_B: + CHECK_EQ(ws_lo | mask, res.d[0]); + CHECK_EQ(ws_hi | mask, res.d[1]); + break; + case NORI_B: + CHECK_EQ(~(ws_lo | mask), res.d[0]); + CHECK_EQ(~(ws_hi | mask), res.d[1]); + break; + case XORI_B: + CHECK_EQ(ws_lo ^ mask, res.d[0]); + CHECK_EQ(ws_hi ^ mask, res.d[1]); + break; + case BMNZI_B: + CHECK_EQ((ws_lo & mask) | (wd_lo & ~mask), res.d[0]); + CHECK_EQ((ws_hi & mask) | (wd_hi & ~mask), res.d[1]); + break; + case BMZI_B: + CHECK_EQ((ws_lo & ~mask) | (wd_lo & mask), res.d[0]); + CHECK_EQ((ws_hi & ~mask) | (wd_hi & mask), res.d[1]); + break; + case BSELI_B: + CHECK_EQ((ws_lo & ~wd_lo) | (mask & wd_lo), res.d[0]); + CHECK_EQ((ws_hi & ~wd_hi) | (mask & wd_hi), res.d[1]); + break; + case SHF_B: { + struct ExpResShf exp_b[] = { + // i8, exp_lo, exp_hi + {0xffu, 0x11111111b9b9b9b9, 0xf7f7f7f7c8c8c8c8}, + {0x0u, 0x62626262dfdfdfdf, 0xd6d6d6d6c8c8c8c8}, + {0xe4u, 0xf35862e13e38f8b0, 0x4f41ffdef2bfe636}, + {0x1bu, 0x1b756911c3d9a7b9, 0xae94a5f79c8aefc8}, + {0xb1u, 0x662b6253e8c4df12, 0x0d3ad6803f8bc88b}, + {0x4eu, 0x62e1f358f8b03e38, 0xffde4f41e636f2bf}, + {0x27u, 0x1b697511c3a7d9b9, 0xaea594f79cef8ac8}}; + for (size_t i = 0; i < sizeof(exp_b) / sizeof(ExpResShf); ++i) { + if (exp_b[i].i8 == i8) { + CHECK_EQ(exp_b[i].lo, res.d[0]); + CHECK_EQ(exp_b[i].hi, res.d[1]); + } + } + } break; + case SHF_H: { + struct ExpResShf exp_h[] = { + // i8, exp_lo, exp_hi + {0xffu, 0x1169116911691169, 0xf7a5f7a5f7a5f7a5}, + {0x0u, 0x12df12df12df12df, 0x8bc88bc88bc88bc8}, + {0xe4u, 0xf35862e13e38f8b0, 0x4f41ffdef2bfe636}, + {0x1bu, 0xd9c3b9a7751b1169, 0x8a9cc8ef94aef7a5}, + {0xb1u, 0x53622b6612dfc4e8, 0x80d63a0d8bc88b3f}, + {0x4eu, 0x3e38f8b0f35862e1, 0xf2bfe6364f41ffde}, + {0x27u, 0xd9c3751bb9a71169, 0x8a9c94aec8eff7a5}}; + for (size_t i = 0; i < sizeof(exp_h) / sizeof(ExpResShf); ++i) { + if (exp_h[i].i8 == i8) { + CHECK_EQ(exp_h[i].lo, res.d[0]); + CHECK_EQ(exp_h[i].hi, res.d[1]); + } + } + } break; + case SHF_W: { + struct ExpResShf exp_w[] = { + // i8, exp_lo, exp_hi + {0xffu, 0xf7a594aef7a594ae, 0xf7a594aef7a594ae}, + {0x0u, 0xc4e812dfc4e812df, 0xc4e812dfc4e812df}, + {0xe4u, 0xf35862e13e38f8b0, 0x4f41ffdef2bfe636}, + {0x1bu, 0xc8ef8a9cf7a594ae, 0xb9a7d9c31169751b}, + {0xb1u, 0xc4e812df2b665362, 0x8b3f8bc83a0d80d6}, + {0x4eu, 0x4f41ffdef2bfe636, 0xf35862e13e38f8b0}, + {0x27u, 0x1169751bf7a594ae, 0xb9a7d9c3c8ef8a9c}}; + for (size_t i = 0; i < sizeof(exp_w) / sizeof(ExpResShf); ++i) { + if (exp_w[i].i8 == i8) { + CHECK_EQ(exp_w[i].lo, res.d[0]); + CHECK_EQ(exp_w[i].hi, res.d[1]); + } + } + } break; + default: + UNREACHABLE(); + } +} + +struct TestCaseMsaI8 { + uint64_t input_lo; + uint64_t input_hi; + uint8_t i8; +}; + +TEST(MSA_andi_ori_nori_xori) { + if ((kArchVariant != kMips64r6) || !CpuFeatures::IsSupported(MIPS_SIMD)) + return; + + CcTest::InitializeVM(); + + struct TestCaseMsaI8 tc[] = {// input_lo, input_hi, i8 + {0x1169751bb9a7d9c3, 0xf7a594aec8ef8a9c, 0xffu}, + {0x2b665362c4e812df, 0x3a0d80d68b3f8bc8, 0x0u}, + {0x1169751bb9a7d9c3, 0xf7a594aec8ef8a9c, 0x3bu}, + {0x2b665362c4e812df, 0x3a0d80d68b3f8bc8, 0xd9u}}; + + for (size_t i = 0; i < sizeof(tc) / sizeof(TestCaseMsaI8); ++i) { + run_msa_i8(ANDI_B, tc[i].input_lo, tc[i].input_hi, tc[i].i8); + run_msa_i8(ORI_B, tc[i].input_lo, tc[i].input_hi, tc[i].i8); + run_msa_i8(NORI_B, tc[i].input_lo, tc[i].input_hi, tc[i].i8); + run_msa_i8(XORI_B, tc[i].input_lo, tc[i].input_hi, tc[i].i8); + } +} + +TEST(MSA_bmnzi_bmzi_bseli) { + if ((kArchVariant != kMips64r6) || !CpuFeatures::IsSupported(MIPS_SIMD)) + return; + + CcTest::InitializeVM(); + + struct TestCaseMsaI8 tc[] = {// input_lo, input_hi, i8 + {0x1169751bb9a7d9c3, 0xf7a594aec8ef8a9c, 0xffu}, + {0x2b665362c4e812df, 0x3a0d80d68b3f8bc8, 0x0u}, + {0x1169751bb9a7d9c3, 0xf7a594aec8ef8a9c, 0x3bu}, + {0x2b665362c4e812df, 0x3a0d80d68b3f8bc8, 0xd9u}}; + + for (size_t i = 0; i < sizeof(tc) / sizeof(TestCaseMsaI8); ++i) { + run_msa_i8(BMNZI_B, tc[i].input_lo, tc[i].input_hi, tc[i].i8); + run_msa_i8(BMZI_B, tc[i].input_lo, tc[i].input_hi, tc[i].i8); + run_msa_i8(BSELI_B, tc[i].input_lo, tc[i].input_hi, tc[i].i8); + } +} + +TEST(MSA_shf) { + if ((kArchVariant != kMips64r6) || !CpuFeatures::IsSupported(MIPS_SIMD)) + return; + + CcTest::InitializeVM(); + + struct TestCaseMsaI8 tc[] = { + // input_lo, input_hi, i8 + {0x1169751bb9a7d9c3, 0xf7a594aec8ef8a9c, 0xffu}, // 3333 + {0x2b665362c4e812df, 0x3a0d80d68b3f8bc8, 0x0u}, // 0000 + {0xf35862e13e38f8b0, 0x4f41ffdef2bfe636, 0xe4u}, // 3210 + {0x1169751bb9a7d9c3, 0xf7a594aec8ef8a9c, 0x1bu}, // 0123 + {0x2b665362c4e812df, 0x3a0d80d68b3f8bc8, 0xb1u}, // 2301 + {0xf35862e13e38f8b0, 0x4f41ffdef2bfe636, 0x4eu}, // 1032 + {0x1169751bb9a7d9c3, 0xf7a594aec8ef8a9c, 0x27u} // 0213 + }; + + for (size_t i = 0; i < sizeof(tc) / sizeof(TestCaseMsaI8); ++i) { + run_msa_i8(SHF_B, tc[i].input_lo, tc[i].input_hi, tc[i].i8); + run_msa_i8(SHF_H, tc[i].input_lo, tc[i].input_hi, tc[i].i8); + run_msa_i8(SHF_W, tc[i].input_lo, tc[i].input_hi, tc[i].i8); + } +} + +struct TestCaseMsaI5 { + uint64_t ws_lo; + uint64_t ws_hi; + uint32_t i5; +}; + +template <typename InstFunc, typename OperFunc> +void run_msa_i5(struct TestCaseMsaI5* input, bool i5_sign_ext, + InstFunc GenerateI5InstructionFunc, + OperFunc GenerateOperationFunc) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes); + CpuFeatureScope fscope(&assm, MIPS_SIMD); + msa_reg_t res; + int32_t i5 = + i5_sign_ext ? static_cast<int32_t>(input->i5 << 27) >> 27 : input->i5; + + __ li(t0, input->ws_lo); + __ li(t1, input->ws_hi); + __ insert_d(w0, 0, t0); + __ insert_d(w0, 1, t1); + + GenerateI5InstructionFunc(assm, i5); + + __ copy_u_w(t2, w2, 0); + __ sw(t2, MemOperand(a0, 0)); + __ copy_u_w(t2, w2, 1); + __ sw(t2, MemOperand(a0, 4)); + __ copy_u_w(t2, w2, 2); + __ sw(t2, MemOperand(a0, 8)); + __ copy_u_w(t2, w2, 3); + __ sw(t2, MemOperand(a0, 12)); + + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(isolate, &desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); +#ifdef OBJECT_PRINT + code->Print(std::cout); +#endif + F3 f = FUNCTION_CAST<F3>(code->entry()); + + (CALL_GENERATED_CODE(isolate, f, &res, 0, 0, 0, 0)); + + CHECK_EQ(GenerateOperationFunc(input->ws_lo, input->i5), res.d[0]); + CHECK_EQ(GenerateOperationFunc(input->ws_hi, input->i5), res.d[1]); +} + +TEST(MSA_addvi_subvi) { + if ((kArchVariant != kMips64r6) || !CpuFeatures::IsSupported(MIPS_SIMD)) + return; + + CcTest::InitializeVM(); + + struct TestCaseMsaI5 tc[] = { + // ws_lo, ws_hi, i5 + {0x1169751bb9a7d9c3, 0xf7a594aec8ef8a9c, 0x0000001f}, + {0x2b665362c4e812df, 0x3a0d80d68b3f8bc8, 0x0000000f}, + {0x1169751bb9a7d9c3, 0xf7a594aec8ef8a9c, 0x00000005}, + {0x2b665362c4e812df, 0x3a0d80d68b3f8bc8, 0x00000010}, + {0xffab807f807fffcd, 0x7f23ff80ff567f80, 0x0000000f}, + {0x80ffefff7f12807f, 0x807f80ff7fdeff78, 0x00000010}}; + +#define ADDVI_DF(lanes, mask) \ + uint64_t res = 0; \ + for (int i = 0; i < lanes / 2; ++i) { \ + int shift = (kMSARegSize / lanes) * i; \ + res |= ((((ws >> shift) & mask) + i5) & mask) << shift; \ + } \ + return res + +#define SUBVI_DF(lanes, mask) \ + uint64_t res = 0; \ + for (int i = 0; i < lanes / 2; ++i) { \ + int shift = (kMSARegSize / lanes) * i; \ + res |= ((((ws >> shift) & mask) - i5) & mask) << shift; \ + } \ + return res + + for (size_t i = 0; i < sizeof(tc) / sizeof(TestCaseMsaI5); ++i) { + run_msa_i5( + &tc[i], false, + [](MacroAssembler& assm, int32_t i5) { __ addvi_b(w2, w0, i5); }, + [](uint64_t ws, uint32_t i5) { ADDVI_DF(kMSALanesByte, UINT8_MAX); }); + + run_msa_i5( + &tc[i], false, + [](MacroAssembler& assm, int32_t i5) { __ addvi_h(w2, w0, i5); }, + [](uint64_t ws, uint32_t i5) { ADDVI_DF(kMSALanesHalf, UINT16_MAX); }); + + run_msa_i5( + &tc[i], false, + [](MacroAssembler& assm, int32_t i5) { __ addvi_w(w2, w0, i5); }, + [](uint64_t ws, uint32_t i5) { ADDVI_DF(kMSALanesWord, UINT32_MAX); }); + + run_msa_i5( + &tc[i], false, + [](MacroAssembler& assm, int32_t i5) { __ addvi_d(w2, w0, i5); }, + [](uint64_t ws, uint32_t i5) { ADDVI_DF(kMSALanesDword, UINT64_MAX); }); + + run_msa_i5( + &tc[i], false, + [](MacroAssembler& assm, int32_t i5) { __ subvi_b(w2, w0, i5); }, + [](uint64_t ws, uint32_t i5) { SUBVI_DF(kMSALanesByte, UINT8_MAX); }); + + run_msa_i5( + &tc[i], false, + [](MacroAssembler& assm, int32_t i5) { __ subvi_h(w2, w0, i5); }, + [](uint64_t ws, uint32_t i5) { SUBVI_DF(kMSALanesHalf, UINT16_MAX); }); + + run_msa_i5( + &tc[i], false, + [](MacroAssembler& assm, int32_t i5) { __ subvi_w(w2, w0, i5); }, + [](uint64_t ws, uint32_t i5) { SUBVI_DF(kMSALanesWord, UINT32_MAX); }); + + run_msa_i5( + &tc[i], false, + [](MacroAssembler& assm, int32_t i5) { __ subvi_d(w2, w0, i5); }, + [](uint64_t ws, uint32_t i5) { SUBVI_DF(kMSALanesDword, UINT64_MAX); }); + } +#undef ADDVI_DF +#undef SUBVI_DF +} + +TEST(MSA_maxi_mini) { + if ((kArchVariant != kMips64r6) || !CpuFeatures::IsSupported(MIPS_SIMD)) + return; + + CcTest::InitializeVM(); + + struct TestCaseMsaI5 tc[] = { + // ws_lo, ws_hi, i5 + {0x7f80ff3480ff7f00, 0x8d7fff80ff7f6780, 0x0000001f}, + {0x7f80ff3480ff7f00, 0x8d7fff80ff7f6780, 0x0000000f}, + {0x7f80ff3480ff7f00, 0x8d7fff80ff7f6780, 0x00000010}, + {0x80007fff91daffff, 0x7fff8000ffff5678, 0x0000001f}, + {0x80007fff91daffff, 0x7fff8000ffff5678, 0x0000000f}, + {0x80007fff91daffff, 0x7fff8000ffff5678, 0x00000010}, + {0x7fffffff80000000, 0x12345678ffffffff, 0x0000001f}, + {0x7fffffff80000000, 0x12345678ffffffff, 0x0000000f}, + {0x7fffffff80000000, 0x12345678ffffffff, 0x00000010}, + {0x1169751bb9a7d9c3, 0xf7a594aec8ef8a9c, 0x0000001f}, + {0x2b665362c4e812df, 0x3a0d80d68b3f8bc8, 0x0000000f}, + {0xf35862e13e38f8b0, 0x4f41ffdef2bfe636, 0x00000010}, + {0x1169751bb9a7d9c3, 0xf7a594aec8ef8a9c, 0x00000015}, + {0x2b665362c4e812df, 0x3a0d80d68b3f8bc8, 0x00000009}, + {0xf35862e13e38f8b0, 0x4f41ffdef2bfe636, 0x00000003}}; + +#define MAXI_MINI_S_DF(lanes, mask, func) \ + [](uint64_t ws, uint32_t ui5) { \ + uint64_t res = 0; \ + int64_t i5 = ArithmeticShiftRight(static_cast<int64_t>(ui5) << 59, 59); \ + int elem_size = kMSARegSize / lanes; \ + for (int i = 0; i < lanes / 2; ++i) { \ + int shift = elem_size * i; \ + int64_t elem = \ + static_cast<int64_t>(((ws >> shift) & mask) << (64 - elem_size)) >> \ + (64 - elem_size); \ + res |= static_cast<uint64_t>(func(elem, i5) & mask) << shift; \ + } \ + return res; \ + } + +#define MAXI_MINI_U_DF(lanes, mask, func) \ + [](uint64_t ws, uint32_t ui5) { \ + uint64_t res = 0; \ + int elem_size = kMSARegSize / lanes; \ + for (int i = 0; i < lanes / 2; ++i) { \ + int shift = elem_size * i; \ + uint64_t elem = (ws >> shift) & mask; \ + res |= (func(elem, static_cast<uint64_t>(ui5)) & mask) << shift; \ + } \ + return res; \ + } + + for (size_t i = 0; i < sizeof(tc) / sizeof(TestCaseMsaI5); ++i) { + run_msa_i5( + &tc[i], true, + [](MacroAssembler& assm, int32_t i5) { __ maxi_s_b(w2, w0, i5); }, + MAXI_MINI_S_DF(kMSALanesByte, UINT8_MAX, Max)); + + run_msa_i5( + &tc[i], true, + [](MacroAssembler& assm, int32_t i5) { __ maxi_s_h(w2, w0, i5); }, + MAXI_MINI_S_DF(kMSALanesHalf, UINT16_MAX, Max)); + + run_msa_i5( + &tc[i], true, + [](MacroAssembler& assm, int32_t i5) { __ maxi_s_w(w2, w0, i5); }, + MAXI_MINI_S_DF(kMSALanesWord, UINT32_MAX, Max)); + + run_msa_i5( + &tc[i], true, + [](MacroAssembler& assm, int32_t i5) { __ maxi_s_d(w2, w0, i5); }, + MAXI_MINI_S_DF(kMSALanesDword, UINT64_MAX, Max)); + + run_msa_i5( + &tc[i], true, + [](MacroAssembler& assm, int32_t i5) { __ mini_s_b(w2, w0, i5); }, + MAXI_MINI_S_DF(kMSALanesByte, UINT8_MAX, Min)); + + run_msa_i5( + &tc[i], true, + [](MacroAssembler& assm, int32_t i5) { __ mini_s_h(w2, w0, i5); }, + MAXI_MINI_S_DF(kMSALanesHalf, UINT16_MAX, Min)); + + run_msa_i5( + &tc[i], true, + [](MacroAssembler& assm, int32_t i5) { __ mini_s_w(w2, w0, i5); }, + MAXI_MINI_S_DF(kMSALanesWord, UINT32_MAX, Min)); + + run_msa_i5( + &tc[i], true, + [](MacroAssembler& assm, int32_t i5) { __ mini_s_d(w2, w0, i5); }, + MAXI_MINI_S_DF(kMSALanesDword, UINT64_MAX, Min)); + + run_msa_i5( + &tc[i], false, + [](MacroAssembler& assm, int32_t i5) { __ maxi_u_b(w2, w0, i5); }, + MAXI_MINI_U_DF(kMSALanesByte, UINT8_MAX, Max)); + + run_msa_i5( + &tc[i], false, + [](MacroAssembler& assm, int32_t i5) { __ maxi_u_h(w2, w0, i5); }, + MAXI_MINI_U_DF(kMSALanesHalf, UINT16_MAX, Max)); + + run_msa_i5( + &tc[i], false, + [](MacroAssembler& assm, int32_t i5) { __ maxi_u_w(w2, w0, i5); }, + MAXI_MINI_U_DF(kMSALanesWord, UINT32_MAX, Max)); + + run_msa_i5( + &tc[i], false, + [](MacroAssembler& assm, int32_t i5) { __ maxi_u_d(w2, w0, i5); }, + MAXI_MINI_U_DF(kMSALanesDword, UINT64_MAX, Max)); + + run_msa_i5( + &tc[i], false, + [](MacroAssembler& assm, int32_t i5) { __ mini_u_b(w2, w0, i5); }, + MAXI_MINI_U_DF(kMSALanesByte, UINT8_MAX, Min)); + + run_msa_i5( + &tc[i], false, + [](MacroAssembler& assm, int32_t i5) { __ mini_u_h(w2, w0, i5); }, + MAXI_MINI_U_DF(kMSALanesHalf, UINT16_MAX, Min)); + + run_msa_i5( + &tc[i], false, + [](MacroAssembler& assm, int32_t i5) { __ mini_u_w(w2, w0, i5); }, + MAXI_MINI_U_DF(kMSALanesWord, UINT32_MAX, Min)); + + run_msa_i5( + &tc[i], false, + [](MacroAssembler& assm, int32_t i5) { __ mini_u_d(w2, w0, i5); }, + MAXI_MINI_U_DF(kMSALanesDword, UINT64_MAX, Min)); + } +#undef MAXI_MINI_S_DF +#undef MAXI_MINI_U_DF +} + +TEST(MSA_ceqi_clti_clei) { + if ((kArchVariant != kMips64r6) || !CpuFeatures::IsSupported(MIPS_SIMD)) + return; + + CcTest::InitializeVM(); + + struct TestCaseMsaI5 tc[] = { + {0xff69751bb9a7d9c3, 0xf7a594aec8ff8a9c, 0x0000001f}, + {0xe669ffffb9a7d9c3, 0xf7a594aeffff8a9c, 0x0000001f}, + {0xffffffffb9a7d9c3, 0xf7a594aeffffffff, 0x0000001f}, + {0x2b0b5362c4e812df, 0x3a0d80d68b3f0bc8, 0x0000000b}, + {0x2b66000bc4e812df, 0x3a0d000b8b3f8bc8, 0x0000000b}, + {0x0000000bc4e812df, 0x3a0d80d60000000b, 0x0000000b}, + {0xf38062e13e38f8b0, 0x8041ffdef2bfe636, 0x00000010}, + {0xf35880003e38f8b0, 0x4f41ffdef2bf8000, 0x00000010}, + {0xf35862e180000000, 0x80000000f2bfe636, 0x00000010}, + {0x1169751bb9a7d9c3, 0xf7a594aec8ef8a9c, 0x00000015}, + {0x2b665362c4e812df, 0x3a0d80d68b3f8bc8, 0x00000009}, + {0xf30062e13e38f800, 0x4f00ffdef2bf0036, 0x00000000}}; + +#define CEQI_CLTI_CLEI_S_DF(lanes, mask, func) \ + [](uint64_t ws, uint32_t ui5) { \ + uint64_t res = 0; \ + int elem_size = kMSARegSize / lanes; \ + int64_t i5 = ArithmeticShiftRight(static_cast<int64_t>(ui5) << 59, 59); \ + for (int i = 0; i < lanes / 2; ++i) { \ + int shift = elem_size * i; \ + int64_t elem = \ + static_cast<int64_t>(((ws >> shift) & mask) << (64 - elem_size)) >> \ + (64 - elem_size); \ + res |= static_cast<uint64_t>((func)&mask) << shift; \ + } \ + return res; \ + } + +#define CEQI_CLTI_CLEI_U_DF(lanes, mask, func) \ + [](uint64_t ws, uint64_t ui5) { \ + uint64_t res = 0; \ + int elem_size = kMSARegSize / lanes; \ + for (int i = 0; i < lanes / 2; ++i) { \ + int shift = elem_size * i; \ + uint64_t elem = (ws >> shift) & mask; \ + res |= ((func)&mask) << shift; \ + } \ + return res; \ + } + + for (size_t i = 0; i < sizeof(tc) / sizeof(TestCaseMsaI5); ++i) { + run_msa_i5(&tc[i], true, + [](MacroAssembler& assm, int32_t i5) { __ ceqi_b(w2, w0, i5); }, + CEQI_CLTI_CLEI_S_DF(kMSALanesByte, UINT8_MAX, + !Compare(elem, i5) ? -1u : 0u)); + + run_msa_i5(&tc[i], true, + [](MacroAssembler& assm, int32_t i5) { __ ceqi_h(w2, w0, i5); }, + CEQI_CLTI_CLEI_S_DF(kMSALanesHalf, UINT16_MAX, + !Compare(elem, i5) ? -1u : 0u)); + + run_msa_i5(&tc[i], true, + [](MacroAssembler& assm, int32_t i5) { __ ceqi_w(w2, w0, i5); }, + CEQI_CLTI_CLEI_S_DF(kMSALanesWord, UINT32_MAX, + !Compare(elem, i5) ? -1u : 0u)); + + run_msa_i5(&tc[i], true, + [](MacroAssembler& assm, int32_t i5) { __ ceqi_d(w2, w0, i5); }, + CEQI_CLTI_CLEI_S_DF(kMSALanesDword, UINT64_MAX, + !Compare(elem, i5) ? -1u : 0u)); + + run_msa_i5( + &tc[i], true, + [](MacroAssembler& assm, int32_t i5) { __ clti_s_b(w2, w0, i5); }, + CEQI_CLTI_CLEI_S_DF(kMSALanesByte, UINT8_MAX, + (Compare(elem, i5) == -1) ? -1u : 0u)); + + run_msa_i5( + &tc[i], true, + [](MacroAssembler& assm, int32_t i5) { __ clti_s_h(w2, w0, i5); }, + CEQI_CLTI_CLEI_S_DF(kMSALanesHalf, UINT16_MAX, + (Compare(elem, i5) == -1) ? -1u : 0u)); + + run_msa_i5( + &tc[i], true, + [](MacroAssembler& assm, int32_t i5) { __ clti_s_w(w2, w0, i5); }, + CEQI_CLTI_CLEI_S_DF(kMSALanesWord, UINT32_MAX, + (Compare(elem, i5) == -1) ? -1u : 0u)); + + run_msa_i5( + &tc[i], true, + [](MacroAssembler& assm, int32_t i5) { __ clti_s_d(w2, w0, i5); }, + CEQI_CLTI_CLEI_S_DF(kMSALanesDword, UINT64_MAX, + (Compare(elem, i5) == -1) ? -1ull : 0ull)); + + run_msa_i5( + &tc[i], true, + [](MacroAssembler& assm, int32_t i5) { __ clei_s_b(w2, w0, i5); }, + CEQI_CLTI_CLEI_S_DF(kMSALanesByte, UINT8_MAX, + (Compare(elem, i5) != 1) ? -1u : 0u)); + + run_msa_i5( + &tc[i], true, + [](MacroAssembler& assm, int32_t i5) { __ clei_s_h(w2, w0, i5); }, + CEQI_CLTI_CLEI_S_DF(kMSALanesHalf, UINT16_MAX, + (Compare(elem, i5) != 1) ? -1u : 0u)); + + run_msa_i5( + &tc[i], true, + [](MacroAssembler& assm, int32_t i5) { __ clei_s_w(w2, w0, i5); }, + CEQI_CLTI_CLEI_S_DF(kMSALanesWord, UINT32_MAX, + (Compare(elem, i5) != 1) ? -1u : 0u)); + + run_msa_i5( + &tc[i], true, + [](MacroAssembler& assm, int32_t i5) { __ clei_s_d(w2, w0, i5); }, + CEQI_CLTI_CLEI_S_DF(kMSALanesDword, UINT64_MAX, + (Compare(elem, i5) != 1) ? -1ull : 0ull)); + + run_msa_i5( + &tc[i], false, + [](MacroAssembler& assm, int32_t i5) { __ clti_u_b(w2, w0, i5); }, + CEQI_CLTI_CLEI_U_DF(kMSALanesByte, UINT8_MAX, + (Compare(elem, ui5) == -1) ? -1ull : 0ull)); + + run_msa_i5( + &tc[i], false, + [](MacroAssembler& assm, int32_t i5) { __ clti_u_h(w2, w0, i5); }, + CEQI_CLTI_CLEI_U_DF(kMSALanesHalf, UINT16_MAX, + (Compare(elem, ui5) == -1) ? -1ull : 0ull)); + + run_msa_i5( + &tc[i], false, + [](MacroAssembler& assm, int32_t i5) { __ clti_u_w(w2, w0, i5); }, + CEQI_CLTI_CLEI_U_DF(kMSALanesWord, UINT32_MAX, + (Compare(elem, ui5) == -1) ? -1ull : 0ull)); + + run_msa_i5( + &tc[i], false, + [](MacroAssembler& assm, int32_t i5) { __ clti_u_d(w2, w0, i5); }, + CEQI_CLTI_CLEI_U_DF(kMSALanesDword, UINT64_MAX, + (Compare(elem, ui5) == -1) ? -1ull : 0ull)); + + run_msa_i5( + &tc[i], false, + [](MacroAssembler& assm, int32_t i5) { __ clei_u_b(w2, w0, i5); }, + CEQI_CLTI_CLEI_U_DF(kMSALanesByte, UINT8_MAX, + (Compare(elem, ui5) != 1) ? -1ull : 0ull)); + + run_msa_i5( + &tc[i], false, + [](MacroAssembler& assm, int32_t i5) { __ clei_u_h(w2, w0, i5); }, + CEQI_CLTI_CLEI_U_DF(kMSALanesHalf, UINT16_MAX, + (Compare(elem, ui5) != 1) ? -1ull : 0ull)); + + run_msa_i5( + &tc[i], false, + [](MacroAssembler& assm, int32_t i5) { __ clei_u_w(w2, w0, i5); }, + CEQI_CLTI_CLEI_U_DF(kMSALanesWord, UINT32_MAX, + (Compare(elem, ui5) != 1) ? -1ull : 0ull)); + + run_msa_i5( + &tc[i], false, + [](MacroAssembler& assm, int32_t i5) { __ clei_u_d(w2, w0, i5); }, + CEQI_CLTI_CLEI_U_DF(kMSALanesDword, UINT64_MAX, + (Compare(elem, ui5) != 1) ? -1ull : 0ull)); + } +#undef CEQI_CLTI_CLEI_S_DF +#undef CEQI_CLTI_CLEI_U_DF +} + +struct TestCaseMsa2R { + uint64_t ws_lo; + uint64_t ws_hi; + uint64_t exp_res_lo; + uint64_t exp_res_hi; +}; + +template <typename Func> +void run_msa_2r(struct TestCaseMsa2R* input, Func Generate2RInstructionFunc) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes); + CpuFeatureScope fscope(&assm, MIPS_SIMD); + msa_reg_t res; + + __ li(t0, input->ws_lo); + __ li(t1, input->ws_hi); + __ insert_d(w0, 0, t0); + __ insert_d(w0, 1, t1); + + Generate2RInstructionFunc(assm); + + __ copy_u_w(t2, w2, 0); + __ sw(t2, MemOperand(a0, 0)); + __ copy_u_w(t2, w2, 1); + __ sw(t2, MemOperand(a0, 4)); + __ copy_u_w(t2, w2, 2); + __ sw(t2, MemOperand(a0, 8)); + __ copy_u_w(t2, w2, 3); + __ sw(t2, MemOperand(a0, 12)); + + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(isolate, &desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); +#ifdef OBJECT_PRINT + code->Print(std::cout); +#endif + F3 f = FUNCTION_CAST<F3>(code->entry()); + + (CALL_GENERATED_CODE(isolate, f, &res, 0, 0, 0, 0)); + + CHECK_EQ(input->exp_res_lo, res.d[0]); + CHECK_EQ(input->exp_res_hi, res.d[1]); +} + +TEST(MSA_pcnt) { + if ((kArchVariant != kMips64r6) || !CpuFeatures::IsSupported(MIPS_SIMD)) + return; + + CcTest::InitializeVM(); + + struct TestCaseMsa2R tc_b[] = {// ws_lo, ws_hi, exp_res_lo, exp_res_hi + {0x0000000000000000, 0x0000000000000000, 0, 0}, + {0xffffffffffffffff, 0xffffffffffffffff, + 0x0808080808080808, 0x0808080808080808}, + {0x1169751bb9a7d9c3, 0xf7a594aec8ef8a9c, + 0x0204050405050504, 0x0704030503070304}, + {0x2b665362c4e812df, 0x3a0d80d68b3f8bc8, + 0x0404040303040207, 0x0403010504060403}, + {0xf35862e13e38f8b0, 0x4f41ffdef2bfe636, + 0x0603030405030503, 0x0502080605070504}}; + + struct TestCaseMsa2R tc_h[] = {// ws_lo, ws_hi, exp_res_lo, exp_res_hi + {0x0000000000000000, 0x0000000000000000, 0, 0}, + {0xffffffffffffffff, 0xffffffffffffffff, + 0x0010001000100010, 0x0010001000100010}, + {0x1169751bb9a7d9c3, 0xf7a594aec8ef8a9c, + 0x00060009000a0009, 0x000b0008000a0007}, + {0x2b665362c4e812df, 0x3a0d80d68b3f8bc8, + 0x0008000700070009, 0x00070006000a0007}, + {0xf35862e13e38f8b0, 0x4f41ffdef2bfe636, + 0x0009000700080008, 0x0007000e000c0009}}; + + struct TestCaseMsa2R tc_w[] = {// ws_lo, ws_hi, exp_res_lo, exp_res_hi + {0x0000000000000000, 0x0000000000000000, 0, 0}, + {0xffffffffffffffff, 0xffffffffffffffff, + 0x0000002000000020, 0x0000002000000020}, + {0x1169751bb9a7d9c3, 0xf7a594aec8ef8a9c, + 0x0000000f00000013, 0x0000001300000011}, + {0x2b665362c4e812df, 0x3a0d80d68b3f8bc8, + 0x0000000f00000010, 0x0000000d00000011}, + {0xf35862e13e38f8b0, 0x4f41ffdef2bfe636, + 0x0000001000000010, 0x0000001500000015}}; + + struct TestCaseMsa2R tc_d[] = { + // ws_lo, ws_hi, exp_res_lo, exp_res_hi + {0x0000000000000000, 0x0000000000000000, 0, 0}, + {0xffffffffffffffff, 0xffffffffffffffff, 0x40, 0x40}, + {0x1169751bb9a7d9c3, 0xf7a594aec8ef8a9c, 0x22, 0x24}, + {0x2b665362c4e812df, 0x3a0d80d68b3f8bc8, 0x1f, 0x1e}, + {0xf35862e13e38f8b0, 0x4f41ffdef2bfe636, 0x20, 0x2a}}; + + for (size_t i = 0; i < sizeof(tc_b) / sizeof(TestCaseMsa2R); ++i) { + run_msa_2r(&tc_b[i], [](MacroAssembler& assm) { __ pcnt_b(w2, w0); }); + run_msa_2r(&tc_h[i], [](MacroAssembler& assm) { __ pcnt_h(w2, w0); }); + run_msa_2r(&tc_w[i], [](MacroAssembler& assm) { __ pcnt_w(w2, w0); }); + run_msa_2r(&tc_d[i], [](MacroAssembler& assm) { __ pcnt_d(w2, w0); }); + } +} + +TEST(MSA_nlzc) { + if ((kArchVariant != kMips64r6) || !CpuFeatures::IsSupported(MIPS_SIMD)) + return; + + CcTest::InitializeVM(); + + struct TestCaseMsa2R tc_b[] = {// ws_lo, ws_hi, exp_res_lo, exp_res_hi + {0x0000000000000000, 0x0000000000000000, + 0x0808080808080808, 0x0808080808080808}, + {0xffffffffffffffff, 0xffffffffffffffff, 0, 0}, + {0x1169350b07030100, 0x7f011402381f0a6c, + 0x0301020405060708, 0x0107030602030401}, + {0x010806003478121f, 0x03013016073f7b08, + 0x0704050802010303, 0x0607020305020104}, + {0x0168321100083803, 0x07113f03013f1676, + 0x0701020308040206, 0x0503020607020301}}; + + struct TestCaseMsa2R tc_h[] = {// ws_lo, ws_hi, exp_res_lo, exp_res_hi + {0x0000000000000000, 0x0000000000000000, + 0x0010001000100010, 0x0010001000100010}, + {0xffffffffffffffff, 0xffffffffffffffff, 0, 0}, + {0x00010007000a003c, 0x37a5001e00010002, + 0x000f000d000c000a, 0x0002000b000f000e}, + {0x0026066200780edf, 0x003d0003000f00c8, + 0x000a000500090004, 0x000a000e000c0008}, + {0x335807e100480030, 0x01410fde12bf5636, + 0x000200050009000a, 0x0007000400030001}}; + + struct TestCaseMsa2R tc_w[] = {// ws_lo, ws_hi, exp_res_lo, exp_res_hi + {0x0000000000000000, 0x0000000000000000, + 0x0000002000000020, 0x0000002000000020}, + {0xffffffffffffffff, 0xffffffffffffffff, 0, 0}, + {0x00000005000007c3, 0x000014ae00006a9c, + 0x0000001d00000015, 0x0000001300000011}, + {0x00009362000112df, 0x000380d6003f8bc8, + 0x000000100000000f, 0x0000000e0000000a}, + {0x135862e17e38f8b0, 0x0061ffde03bfe636, + 0x0000000300000001, 0x0000000900000006}}; + + struct TestCaseMsa2R tc_d[] = { + // ws_lo, ws_hi, exp_res_lo, exp_res_hi + {0x0000000000000000, 0x0000000000000000, 0x40, 0x40}, + {0xffffffffffffffff, 0xffffffffffffffff, 0, 0}, + {0x000000000000014e, 0x00000000000176da, 0x37, 0x2f}, + {0x00000062c4e812df, 0x000065d68b3f8bc8, 0x19, 0x11}, + {0x00000000e338f8b0, 0x0754534acab32654, 0x20, 0x5}}; + + for (size_t i = 0; i < sizeof(tc_b) / sizeof(TestCaseMsa2R); ++i) { + run_msa_2r(&tc_b[i], [](MacroAssembler& assm) { __ nlzc_b(w2, w0); }); + run_msa_2r(&tc_h[i], [](MacroAssembler& assm) { __ nlzc_h(w2, w0); }); + run_msa_2r(&tc_w[i], [](MacroAssembler& assm) { __ nlzc_w(w2, w0); }); + run_msa_2r(&tc_d[i], [](MacroAssembler& assm) { __ nlzc_d(w2, w0); }); + } +} + +TEST(MSA_nloc) { + if ((kArchVariant != kMips64r6) || !CpuFeatures::IsSupported(MIPS_SIMD)) + return; + + CcTest::InitializeVM(); + + struct TestCaseMsa2R tc_b[] = {// ws_lo, ws_hi, exp_res_lo, exp_res_hi + {0xffffffffffffffff, 0xffffffffffffffff, + 0x0808080808080808, 0x0808080808080808}, + {0x0000000000000000, 0x0000000000000000, 0, 0}, + {0xEE96CAF4F8FCFEFF, 0x80FEEBFDC7E0F593, + 0x0301020405060708, 0x0107030602030401}, + {0xFEF7F9FFCB87EDE0, 0xFCFECFE9F8C084F7, + 0x0704050802010303, 0x0607020305020104}, + {0xFE97CDEEFFF7C7FC, 0xF8EEC0FCFEC0E989, + 0x0701020308040206, 0x0503020607020301}}; + + struct TestCaseMsa2R tc_h[] = {// ws_lo, ws_hi, exp_res_lo, exp_res_hi + {0xffffffffffffffff, 0xffffffffffffffff, + 0x0010001000100010, 0x0010001000100010}, + {0x0000000000000000, 0x0000000000000000, 0, 0}, + {0xFFFEFFF8FFF5FFC3, 0xC85AFFE1FFFEFFFD, + 0x000f000d000c000a, 0x0002000b000f000e}, + {0xFFD9F99DFF87F120, 0xFFC2FFFCFFF0FF37, + 0x000a000500090004, 0x000a000e000c0008}, + {0xCCA7F81EFFB7FFCF, 0xFEBEF021ED40A9C9, + 0x000200050009000a, 0x0007000400030001}}; + + struct TestCaseMsa2R tc_w[] = {// ws_lo, ws_hi, exp_res_lo, exp_res_hi + {0xffffffffffffffff, 0xffffffffffffffff, + 0x0000002000000020, 0x0000002000000020}, + {0x0000000000000000, 0x0000000000000000, 0, 0}, + {0xFFFFFFFAFFFFF83C, 0xFFFFEB51FFFF9563, + 0x0000001d00000015, 0x0000001300000011}, + {0xFFFF6C9DFFFEED20, 0xFFFC7F29FFC07437, + 0x000000100000000f, 0x0000000e0000000a}, + {0xECA79D1E81C7074F, 0xFF9E0021FC4019C9, + 0x0000000300000001, 0x0000000900000006}}; + + struct TestCaseMsa2R tc_d[] = { + // ws_lo, ws_hi, exp_res_lo, exp_res_hi + {0xffffffffffffffff, 0xffffffffffffffff, 0x40, 0x40}, + {0x0000000000000000, 0x0000000000000000, 0, 0}, + {0xFFFFFFFFFFFFFEB1, 0xFFFFFFFFFFFE8925, 0x37, 0x2f}, + {0xFFFFFF9D3B17ED20, 0xFFFF9A2974C07437, 0x19, 0x11}, + {0xFFFFFFFF1CC7074F, 0xF8ABACB5354CD9AB, 0x20, 0x5}}; + + for (size_t i = 0; i < sizeof(tc_b) / sizeof(TestCaseMsa2R); ++i) { + run_msa_2r(&tc_b[i], [](MacroAssembler& assm) { __ nloc_b(w2, w0); }); + run_msa_2r(&tc_h[i], [](MacroAssembler& assm) { __ nloc_h(w2, w0); }); + run_msa_2r(&tc_w[i], [](MacroAssembler& assm) { __ nloc_w(w2, w0); }); + run_msa_2r(&tc_d[i], [](MacroAssembler& assm) { __ nloc_d(w2, w0); }); + } +} + +struct TestCaseMsaVector { + uint64_t wd_lo; + uint64_t wd_hi; + uint64_t ws_lo; + uint64_t ws_hi; + uint64_t wt_lo; + uint64_t wt_hi; +}; + +template <typename InstFunc, typename OperFunc> +void run_msa_vector(struct TestCaseMsaVector* input, + InstFunc GenerateVectorInstructionFunc, + OperFunc GenerateOperationFunc) { + Isolate* isolate = CcTest::i_isolate(); + HandleScope scope(isolate); + + MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes); + CpuFeatureScope fscope(&assm, MIPS_SIMD); + msa_reg_t res; + +#define LOAD_W_REG(lo, hi, w_reg) \ + __ li(t0, lo); \ + __ li(t1, hi); \ + __ insert_d(w_reg, 0, t0); \ + __ insert_d(w_reg, 1, t1) + + LOAD_W_REG(input->ws_lo, input->ws_hi, w0); + LOAD_W_REG(input->wt_lo, input->wt_hi, w2); + LOAD_W_REG(input->wd_lo, input->wd_hi, w4); +#undef LOAD_W_REG + + GenerateVectorInstructionFunc(assm); + + __ copy_u_w(t2, w4, 0); + __ sw(t2, MemOperand(a0, 0)); + __ copy_u_w(t2, w4, 1); + __ sw(t2, MemOperand(a0, 4)); + __ copy_u_w(t2, w4, 2); + __ sw(t2, MemOperand(a0, 8)); + __ copy_u_w(t2, w4, 3); + __ sw(t2, MemOperand(a0, 12)); + + __ jr(ra); + __ nop(); + + CodeDesc desc; + assm.GetCode(isolate, &desc); + Handle<Code> code = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle<Code>()); +#ifdef OBJECT_PRINT + code->Print(std::cout); +#endif + F3 f = FUNCTION_CAST<F3>(code->entry()); + + (CALL_GENERATED_CODE(isolate, f, &res, 0, 0, 0, 0)); + + CHECK_EQ(GenerateOperationFunc(input->wd_lo, input->ws_lo, input->wt_lo), + res.d[0]); + CHECK_EQ(GenerateOperationFunc(input->wd_hi, input->ws_hi, input->wt_hi), + res.d[1]); +} + +TEST(MSA_vector) { + if ((kArchVariant != kMips64r6) || !CpuFeatures::IsSupported(MIPS_SIMD)) + return; + + CcTest::InitializeVM(); + + struct TestCaseMsaVector tc[] = { + // wd_lo, wd_hi, ws_lo, ws_hi, wt_lo, wt_hi + {0xf35862e13e38f8b0, 0x4f41ffdef2bfe636, 0xdcd39d91f9057627, + 0x64be4f6dbe9caa51, 0x6b23de1a687d9cb9, 0x49547aad691da4ca}, + {0xf35862e13e38f8b0, 0x4f41ffdef2bfe636, 0x401614523d830549, + 0xd7c46d613f50eddd, 0x52284cbc60a1562b, 0x1756ed510d8849cd}, + {0xf35862e13e38f8b0, 0x4f41ffdef2bfe636, 0xd6e2d2ebcb40d72f, + 0x13a619afce67b079, 0x36cce284343e40f9, 0xb4e8f44fd148bf7f}}; + + for (size_t i = 0; i < sizeof(tc) / sizeof(TestCaseMsaVector); ++i) { + run_msa_vector( + &tc[i], [](MacroAssembler& assm) { __ and_v(w4, w0, w2); }, + [](uint64_t wd, uint64_t ws, uint64_t wt) { return ws & wt; }); + run_msa_vector( + &tc[i], [](MacroAssembler& assm) { __ or_v(w4, w0, w2); }, + [](uint64_t wd, uint64_t ws, uint64_t wt) { return ws | wt; }); + run_msa_vector( + &tc[i], [](MacroAssembler& assm) { __ nor_v(w4, w0, w2); }, + [](uint64_t wd, uint64_t ws, uint64_t wt) { return ~(ws | wt); }); + run_msa_vector( + &tc[i], [](MacroAssembler& assm) { __ xor_v(w4, w0, w2); }, + [](uint64_t wd, uint64_t ws, uint64_t wt) { return ws ^ wt; }); + run_msa_vector(&tc[i], [](MacroAssembler& assm) { __ bmnz_v(w4, w0, w2); }, + [](uint64_t wd, uint64_t ws, uint64_t wt) { + return (ws & wt) | (wd & ~wt); + }); + run_msa_vector(&tc[i], [](MacroAssembler& assm) { __ bmz_v(w4, w0, w2); }, + [](uint64_t wd, uint64_t ws, uint64_t wt) { + return (ws & ~wt) | (wd & wt); + }); + run_msa_vector(&tc[i], [](MacroAssembler& assm) { __ bsel_v(w4, w0, w2); }, + [](uint64_t wd, uint64_t ws, uint64_t wt) { + return (ws & ~wd) | (wt & wd); + }); + } +} + #undef __ |