From c16a39f23e13a2135f43f749f0dea37b9f045097 Mon Sep 17 00:00:00 2001 From: Dusan Simicic Date: Fri, 7 Jul 2017 13:35:06 +0200 Subject: [PATCH] MIPS[64]: Implement vector MSA instructions in simulator Add support for and.v, or.v, nor.v, xor.v, bmnz.v, bmz.v, bsel.v MSA instructions in mips32 and mips64 simulator. Bug: Change-Id: Idf092a1c211959a096694485268fff379b612b77 Reviewed-on: https://chromium-review.googlesource.com/533075 Commit-Queue: Ivica Bogosavljevic Reviewed-by: Ivica Bogosavljevic Cr-Commit-Position: refs/heads/master@{#46474} --- src/mips/simulator-mips.cc | 48 +++++++++--- src/mips64/simulator-mips64.cc | 48 +++++++++--- test/cctest/test-assembler-mips.cc | 109 +++++++++++++++++++++++++++ test/cctest/test-assembler-mips64.cc | 105 ++++++++++++++++++++++++++ 4 files changed, 286 insertions(+), 24 deletions(-) diff --git a/src/mips/simulator-mips.cc b/src/mips/simulator-mips.cc index 9c96ddb876..c2e20a5f77 100644 --- a/src/mips/simulator-mips.cc +++ b/src/mips/simulator-mips.cc @@ -4753,19 +4753,43 @@ void Simulator::DecodeTypeMsaVec() { DCHECK(IsMipsArchVariant(kMips32r6)); DCHECK(CpuFeatures::IsSupported(MIPS_SIMD)); uint32_t opcode = instr_.InstructionBits() & kMsaVECMask; - switch (opcode) { - case AND_V: - case OR_V: - case NOR_V: - case XOR_V: - case BMNZ_V: - case BMZ_V: - case BSEL_V: - UNIMPLEMENTED(); - break; - default: - UNREACHABLE(); + msa_reg_t wd, ws, wt; + + get_msa_register(instr_.WsValue(), ws.w); + get_msa_register(instr_.WtValue(), wt.w); + if (opcode == BMNZ_V || opcode == BMZ_V || opcode == BSEL_V) { + get_msa_register(instr_.WdValue(), wd.w); } + + for (int i = 0; i < kMSALanesWord; i++) { + switch (opcode) { + case AND_V: + wd.w[i] = ws.w[i] & wt.w[i]; + break; + case OR_V: + wd.w[i] = ws.w[i] | wt.w[i]; + break; + case NOR_V: + wd.w[i] = ~(ws.w[i] | wt.w[i]); + break; + case XOR_V: + wd.w[i] = ws.w[i] ^ wt.w[i]; + break; + case BMNZ_V: + wd.w[i] = (wt.w[i] & ws.w[i]) | (~wt.w[i] & wd.w[i]); + break; + case BMZ_V: + wd.w[i] = (~wt.w[i] & ws.w[i]) | (wt.w[i] & wd.w[i]); + break; + case BSEL_V: + wd.w[i] = (~wd.w[i] & ws.w[i]) | (wd.w[i] & wt.w[i]); + break; + default: + UNREACHABLE(); + } + } + set_msa_register(instr_.WdValue(), wd.w); + TraceMSARegWr(wd.d); } void Simulator::DecodeTypeMsa2R() { diff --git a/src/mips64/simulator-mips64.cc b/src/mips64/simulator-mips64.cc index e2b5fe267e..9d10ca6a69 100644 --- a/src/mips64/simulator-mips64.cc +++ b/src/mips64/simulator-mips64.cc @@ -4978,19 +4978,43 @@ void Simulator::DecodeTypeMsaVec() { DCHECK(kArchVariant == kMips64r6); DCHECK(CpuFeatures::IsSupported(MIPS_SIMD)); uint32_t opcode = instr_.InstructionBits() & kMsaVECMask; - switch (opcode) { - case AND_V: - case OR_V: - case NOR_V: - case XOR_V: - case BMNZ_V: - case BMZ_V: - case BSEL_V: - UNIMPLEMENTED(); - break; - default: - UNREACHABLE(); + msa_reg_t wd, ws, wt; + + get_msa_register(instr_.WsValue(), ws.d); + get_msa_register(instr_.WtValue(), wt.d); + if (opcode == BMNZ_V || opcode == BMZ_V || opcode == BSEL_V) { + get_msa_register(instr_.WdValue(), wd.d); } + + for (int i = 0; i < kMSALanesDword; i++) { + switch (opcode) { + case AND_V: + wd.d[i] = ws.d[i] & wt.d[i]; + break; + case OR_V: + wd.d[i] = ws.d[i] | wt.d[i]; + break; + case NOR_V: + wd.d[i] = ~(ws.d[i] | wt.d[i]); + break; + case XOR_V: + wd.d[i] = ws.d[i] ^ wt.d[i]; + break; + case BMNZ_V: + wd.d[i] = (wt.d[i] & ws.d[i]) | (~wt.d[i] & wd.d[i]); + break; + case BMZ_V: + wd.d[i] = (~wt.d[i] & ws.d[i]) | (wt.d[i] & wd.d[i]); + break; + case BSEL_V: + wd.d[i] = (~wd.d[i] & ws.d[i]) | (wd.d[i] & wt.d[i]); + break; + default: + UNREACHABLE(); + } + } + set_msa_register(instr_.WdValue(), wd.d); + TraceMSARegWr(wd.d); } void Simulator::DecodeTypeMsa2R() { diff --git a/test/cctest/test-assembler-mips.cc b/test/cctest/test-assembler-mips.cc index 9c67a3b35f..96d939e0a8 100644 --- a/test/cctest/test-assembler-mips.cc +++ b/test/cctest/test-assembler-mips.cc @@ -6888,4 +6888,113 @@ TEST(MSA_nloc) { } } +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 +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, static_cast(lo & 0xffffffff)); \ + __ li(t1, static_cast((lo >> 32) & 0xffffffff)); \ + __ insert_w(w_reg, 0, t0); \ + __ insert_w(w_reg, 1, t1); \ + __ li(t0, static_cast(hi & 0xffffffff)); \ + __ li(t1, static_cast((hi >> 32) & 0xffffffff)); \ + __ insert_w(w_reg, 2, t0); \ + __ insert_w(w_reg, 3, 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 = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle()); +#ifdef OBJECT_PRINT + code->Print(std::cout); +#endif + F3 f = FUNCTION_CAST(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 (!IsMipsArchVariant(kMips32r6) || !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 __ diff --git a/test/cctest/test-assembler-mips64.cc b/test/cctest/test-assembler-mips64.cc index 072f91c05d..b5a05f323b 100644 --- a/test/cctest/test-assembler-mips64.cc +++ b/test/cctest/test-assembler-mips64.cc @@ -7757,4 +7757,109 @@ TEST(MSA_nloc) { } } +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 +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 = isolate->factory()->NewCode( + desc, Code::ComputeFlags(Code::STUB), Handle()); +#ifdef OBJECT_PRINT + code->Print(std::cout); +#endif + F3 f = FUNCTION_CAST(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 __