diff --git a/src/compiler/instruction-selector.cc b/src/compiler/instruction-selector.cc index 82d76ef827..9e3163beba 100644 --- a/src/compiler/instruction-selector.cc +++ b/src/compiler/instruction-selector.cc @@ -2451,7 +2451,7 @@ void InstructionSelector::VisitS8x16Select(Node* node) { UNIMPLEMENTED(); } #endif // !V8_TARGET_ARCH_X64 && !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_MIPS && // !V8_TARGET_ARCH_MIPS64 -#if !V8_TARGET_ARCH_ARM +#if !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_MIPS && !V8_TARGET_ARCH_MIPS64 void InstructionSelector::VisitS1x4And(Node* node) { UNIMPLEMENTED(); } void InstructionSelector::VisitS1x4Or(Node* node) { UNIMPLEMENTED(); } @@ -2487,7 +2487,7 @@ void InstructionSelector::VisitS1x16Not(Node* node) { UNIMPLEMENTED(); } void InstructionSelector::VisitS1x16AnyTrue(Node* node) { UNIMPLEMENTED(); } void InstructionSelector::VisitS1x16AllTrue(Node* node) { UNIMPLEMENTED(); } -#endif // !V8_TARGET_ARCH_ARM +#endif // !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_MIPS && !V8_TARGET_ARCH_MIPS64 void InstructionSelector::VisitFinishRegion(Node* node) { EmitIdentity(node); } diff --git a/src/compiler/mips/code-generator-mips.cc b/src/compiler/mips/code-generator-mips.cc index d79e6a6f63..b663bcab0b 100644 --- a/src/compiler/mips/code-generator-mips.cc +++ b/src/compiler/mips/code-generator-mips.cc @@ -2226,6 +2226,63 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( i.InputSimd128Register(0)); break; } + case kMipsS1x4AnyTrue: + case kMipsS1x8AnyTrue: + case kMipsS1x16AnyTrue: { + CpuFeatureScope msa_scope(masm(), MIPS_SIMD); + Register dst = i.OutputRegister(); + Label all_false; + + __ BranchMSA(&all_false, MSA_BRANCH_V, all_zero, + i.InputSimd128Register(0), USE_DELAY_SLOT); + __ li(dst, 0); // branch delay slot + __ li(dst, -1); + __ bind(&all_false); + break; + } + case kMipsS1x4AllTrue: { + CpuFeatureScope msa_scope(masm(), MIPS_SIMD); + Register dst = i.OutputRegister(); + Label all_true; + __ BranchMSA(&all_true, MSA_BRANCH_W, all_not_zero, + i.InputSimd128Register(0), USE_DELAY_SLOT); + __ li(dst, -1); // branch delay slot + __ li(dst, 0); + __ bind(&all_true); + break; + } + case kMipsS1x8AllTrue: { + CpuFeatureScope msa_scope(masm(), MIPS_SIMD); + Register dst = i.OutputRegister(); + Label all_true; + __ BranchMSA(&all_true, MSA_BRANCH_H, all_not_zero, + i.InputSimd128Register(0), USE_DELAY_SLOT); + __ li(dst, -1); // branch delay slot + __ li(dst, 0); + __ bind(&all_true); + break; + } + case kMipsS1x16AllTrue: { + CpuFeatureScope msa_scope(masm(), MIPS_SIMD); + Register dst = i.OutputRegister(); + Label all_true; + __ BranchMSA(&all_true, MSA_BRANCH_B, all_not_zero, + i.InputSimd128Register(0), USE_DELAY_SLOT); + __ li(dst, -1); // branch delay slot + __ li(dst, 0); + __ bind(&all_true); + break; + } + case kMipsMsaLd: { + CpuFeatureScope msa_scope(masm(), MIPS_SIMD); + __ ld_b(i.OutputSimd128Register(), i.MemoryOperand()); + break; + } + case kMipsMsaSt: { + CpuFeatureScope msa_scope(masm(), MIPS_SIMD); + __ st_b(i.InputSimd128Register(2), i.MemoryOperand()); + break; + } } return kSuccess; } // NOLINT(readability/fn_size) diff --git a/src/compiler/mips/instruction-codes-mips.h b/src/compiler/mips/instruction-codes-mips.h index 401d8b7fd7..8fa3618a26 100644 --- a/src/compiler/mips/instruction-codes-mips.h +++ b/src/compiler/mips/instruction-codes-mips.h @@ -228,7 +228,15 @@ namespace compiler { V(MipsS128And) \ V(MipsS128Or) \ V(MipsS128Xor) \ - V(MipsS128Not) + V(MipsS128Not) \ + V(MipsS1x4AnyTrue) \ + V(MipsS1x4AllTrue) \ + V(MipsS1x8AnyTrue) \ + V(MipsS1x8AllTrue) \ + V(MipsS1x16AnyTrue) \ + V(MipsS1x16AllTrue) \ + V(MipsMsaLd) \ + V(MipsMsaSt) // Addressing modes represent the "shape" of inputs to an instruction. // Many instructions support multiple addressing modes. Addressing modes diff --git a/src/compiler/mips/instruction-selector-mips.cc b/src/compiler/mips/instruction-selector-mips.cc index 875265301c..0ec2819b37 100644 --- a/src/compiler/mips/instruction-selector-mips.cc +++ b/src/compiler/mips/instruction-selector-mips.cc @@ -294,8 +294,10 @@ void InstructionSelector::VisitLoad(Node* node) { case MachineRepresentation::kWord32: opcode = kMipsLw; break; + case MachineRepresentation::kSimd128: + opcode = kMipsMsaLd; + break; case MachineRepresentation::kWord64: // Fall through. - case MachineRepresentation::kSimd128: // Fall through. case MachineRepresentation::kSimd1x4: // Fall through. case MachineRepresentation::kSimd1x8: // Fall through. case MachineRepresentation::kSimd1x16: // Fall through. @@ -382,8 +384,10 @@ void InstructionSelector::VisitStore(Node* node) { case MachineRepresentation::kWord32: opcode = kMipsSw; break; + case MachineRepresentation::kSimd128: + opcode = kMipsMsaSt; + break; case MachineRepresentation::kWord64: // Fall through. - case MachineRepresentation::kSimd128: // Fall through. case MachineRepresentation::kSimd1x4: // Fall through. case MachineRepresentation::kSimd1x8: // Fall through. case MachineRepresentation::kSimd1x16: // Fall through. @@ -1234,8 +1238,10 @@ void InstructionSelector::VisitUnalignedLoad(Node* node) { case MachineRepresentation::kFloat64: opcode = kMipsUldc1; break; + case MachineRepresentation::kSimd128: + opcode = kMipsMsaLd; + break; case MachineRepresentation::kWord64: // Fall through. - case MachineRepresentation::kSimd128: // Fall through. case MachineRepresentation::kSimd1x4: // Fall through. case MachineRepresentation::kSimd1x8: // Fall through. case MachineRepresentation::kSimd1x16: // Fall through. @@ -1287,8 +1293,10 @@ void InstructionSelector::VisitUnalignedStore(Node* node) { case MachineRepresentation::kWord32: opcode = kMipsUsw; break; + case MachineRepresentation::kSimd128: + opcode = kMipsMsaSt; + break; case MachineRepresentation::kWord64: // Fall through. - case MachineRepresentation::kSimd128: // Fall through. case MachineRepresentation::kSimd1x4: // Fall through. case MachineRepresentation::kSimd1x8: // Fall through. case MachineRepresentation::kSimd1x16: // Fall through. @@ -2341,6 +2349,78 @@ void InstructionSelector::VisitS128Not(Node* node) { VisitRR(this, kMipsS128Not, node); } +void InstructionSelector::VisitS1x4And(Node* node) { + VisitRRR(this, kMipsS128And, node); +} + +void InstructionSelector::VisitS1x4Or(Node* node) { + VisitRRR(this, kMipsS128Or, node); +} + +void InstructionSelector::VisitS1x4Xor(Node* node) { + VisitRRR(this, kMipsS128Xor, node); +} + +void InstructionSelector::VisitS1x4Not(Node* node) { + VisitRR(this, kMipsS128Not, node); +} + +void InstructionSelector::VisitS1x4AnyTrue(Node* node) { + VisitRR(this, kMipsS1x4AnyTrue, node); +} + +void InstructionSelector::VisitS1x4AllTrue(Node* node) { + VisitRR(this, kMipsS1x4AllTrue, node); +} + +void InstructionSelector::VisitS1x8And(Node* node) { + VisitRRR(this, kMipsS128And, node); +} + +void InstructionSelector::VisitS1x8Or(Node* node) { + VisitRRR(this, kMipsS128Or, node); +} + +void InstructionSelector::VisitS1x8Xor(Node* node) { + VisitRRR(this, kMipsS128Xor, node); +} + +void InstructionSelector::VisitS1x8Not(Node* node) { + VisitRR(this, kMipsS128Not, node); +} + +void InstructionSelector::VisitS1x8AnyTrue(Node* node) { + VisitRR(this, kMipsS1x8AnyTrue, node); +} + +void InstructionSelector::VisitS1x8AllTrue(Node* node) { + VisitRR(this, kMipsS1x8AllTrue, node); +} + +void InstructionSelector::VisitS1x16And(Node* node) { + VisitRRR(this, kMipsS128And, node); +} + +void InstructionSelector::VisitS1x16Or(Node* node) { + VisitRRR(this, kMipsS128Or, node); +} + +void InstructionSelector::VisitS1x16Xor(Node* node) { + VisitRRR(this, kMipsS128Xor, node); +} + +void InstructionSelector::VisitS1x16Not(Node* node) { + VisitRR(this, kMipsS128Not, node); +} + +void InstructionSelector::VisitS1x16AnyTrue(Node* node) { + VisitRR(this, kMipsS1x16AnyTrue, node); +} + +void InstructionSelector::VisitS1x16AllTrue(Node* node) { + VisitRR(this, kMipsS1x16AllTrue, node); +} + // static MachineOperatorBuilder::Flags InstructionSelector::SupportedMachineOperatorFlags() { diff --git a/src/compiler/mips64/code-generator-mips64.cc b/src/compiler/mips64/code-generator-mips64.cc index 767da7062c..e904eaacaa 100644 --- a/src/compiler/mips64/code-generator-mips64.cc +++ b/src/compiler/mips64/code-generator-mips64.cc @@ -2546,6 +2546,62 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( i.InputSimd128Register(0)); break; } + case kMips64S1x4AnyTrue: + case kMips64S1x8AnyTrue: + case kMips64S1x16AnyTrue: { + CpuFeatureScope msa_scope(masm(), MIPS_SIMD); + Register dst = i.OutputRegister(); + Label all_false; + __ BranchMSA(&all_false, MSA_BRANCH_V, all_zero, + i.InputSimd128Register(0), USE_DELAY_SLOT); + __ li(dst, 0); // branch delay slot + __ li(dst, -1); + __ bind(&all_false); + break; + } + case kMips64S1x4AllTrue: { + CpuFeatureScope msa_scope(masm(), MIPS_SIMD); + Register dst = i.OutputRegister(); + Label all_true; + __ BranchMSA(&all_true, MSA_BRANCH_W, all_not_zero, + i.InputSimd128Register(0), USE_DELAY_SLOT); + __ li(dst, -1); // branch delay slot + __ li(dst, 0); + __ bind(&all_true); + break; + } + case kMips64S1x8AllTrue: { + CpuFeatureScope msa_scope(masm(), MIPS_SIMD); + Register dst = i.OutputRegister(); + Label all_true; + __ BranchMSA(&all_true, MSA_BRANCH_H, all_not_zero, + i.InputSimd128Register(0), USE_DELAY_SLOT); + __ li(dst, -1); // branch delay slot + __ li(dst, 0); + __ bind(&all_true); + break; + } + case kMips64S1x16AllTrue: { + CpuFeatureScope msa_scope(masm(), MIPS_SIMD); + Register dst = i.OutputRegister(); + Label all_true; + __ BranchMSA(&all_true, MSA_BRANCH_B, all_not_zero, + i.InputSimd128Register(0), USE_DELAY_SLOT); + __ li(dst, -1); // branch delay slot + __ li(dst, 0); + __ bind(&all_true); + break; + } + case kMips64MsaLd: { + CpuFeatureScope msa_scope(masm(), MIPS_SIMD); + __ ld_b(i.OutputSimd128Register(), i.MemoryOperand()); + break; + } + case kMips64MsaSt: { + CpuFeatureScope msa_scope(masm(), MIPS_SIMD); + __ st_b(i.InputSimd128Register(2), i.MemoryOperand()); + break; + } } return kSuccess; } // NOLINT(readability/fn_size) diff --git a/src/compiler/mips64/instruction-codes-mips64.h b/src/compiler/mips64/instruction-codes-mips64.h index 51c9e33f66..b3ab6f9c9f 100644 --- a/src/compiler/mips64/instruction-codes-mips64.h +++ b/src/compiler/mips64/instruction-codes-mips64.h @@ -262,7 +262,15 @@ namespace compiler { V(Mips64S128And) \ V(Mips64S128Or) \ V(Mips64S128Xor) \ - V(Mips64S128Not) + V(Mips64S128Not) \ + V(Mips64S1x4AnyTrue) \ + V(Mips64S1x4AllTrue) \ + V(Mips64S1x8AnyTrue) \ + V(Mips64S1x8AllTrue) \ + V(Mips64S1x16AnyTrue) \ + V(Mips64S1x16AllTrue) \ + V(Mips64MsaLd) \ + V(Mips64MsaSt) // Addressing modes represent the "shape" of inputs to an instruction. // Many instructions support multiple addressing modes. Addressing modes diff --git a/src/compiler/mips64/instruction-selector-mips64.cc b/src/compiler/mips64/instruction-selector-mips64.cc index 8126621bae..c67f6cc99b 100644 --- a/src/compiler/mips64/instruction-selector-mips64.cc +++ b/src/compiler/mips64/instruction-selector-mips64.cc @@ -411,7 +411,9 @@ void InstructionSelector::VisitLoad(Node* node) { case MachineRepresentation::kWord64: opcode = kMips64Ld; break; - case MachineRepresentation::kSimd128: // Fall through. + case MachineRepresentation::kSimd128: + opcode = kMips64MsaLd; + break; case MachineRepresentation::kSimd1x4: // Fall through. case MachineRepresentation::kSimd1x8: // Fall through. case MachineRepresentation::kSimd1x16: // Fall through. @@ -491,7 +493,9 @@ void InstructionSelector::VisitStore(Node* node) { case MachineRepresentation::kWord64: opcode = kMips64Sd; break; - case MachineRepresentation::kSimd128: // Fall through. + case MachineRepresentation::kSimd128: + opcode = kMips64MsaSt; + break; case MachineRepresentation::kSimd1x4: // Fall through. case MachineRepresentation::kSimd1x8: // Fall through. case MachineRepresentation::kSimd1x16: // Fall through. @@ -1785,7 +1789,9 @@ void InstructionSelector::VisitUnalignedLoad(Node* node) { case MachineRepresentation::kWord64: opcode = kMips64Uld; break; - case MachineRepresentation::kSimd128: // Fall through. + case MachineRepresentation::kSimd128: + opcode = kMips64MsaLd; + break; case MachineRepresentation::kSimd1x4: // Fall through. case MachineRepresentation::kSimd1x8: // Fall through. case MachineRepresentation::kSimd1x16: // Fall through. @@ -1838,7 +1844,9 @@ void InstructionSelector::VisitUnalignedStore(Node* node) { case MachineRepresentation::kWord64: opcode = kMips64Usd; break; - case MachineRepresentation::kSimd128: // Fall through. + case MachineRepresentation::kSimd128: + opcode = kMips64MsaSt; + break; case MachineRepresentation::kSimd1x4: // Fall through. case MachineRepresentation::kSimd1x8: // Fall through. case MachineRepresentation::kSimd1x16: // Fall through. @@ -3093,6 +3101,78 @@ void InstructionSelector::VisitS128Not(Node* node) { VisitRR(this, kMips64S128Not, node); } +void InstructionSelector::VisitS1x4And(Node* node) { + VisitRRR(this, kMips64S128And, node); +} + +void InstructionSelector::VisitS1x4Or(Node* node) { + VisitRRR(this, kMips64S128Or, node); +} + +void InstructionSelector::VisitS1x4Xor(Node* node) { + VisitRRR(this, kMips64S128Xor, node); +} + +void InstructionSelector::VisitS1x4Not(Node* node) { + VisitRR(this, kMips64S128Not, node); +} + +void InstructionSelector::VisitS1x4AnyTrue(Node* node) { + VisitRR(this, kMips64S1x4AnyTrue, node); +} + +void InstructionSelector::VisitS1x4AllTrue(Node* node) { + VisitRR(this, kMips64S1x4AllTrue, node); +} + +void InstructionSelector::VisitS1x8And(Node* node) { + VisitRRR(this, kMips64S128And, node); +} + +void InstructionSelector::VisitS1x8Or(Node* node) { + VisitRRR(this, kMips64S128Or, node); +} + +void InstructionSelector::VisitS1x8Xor(Node* node) { + VisitRRR(this, kMips64S128Xor, node); +} + +void InstructionSelector::VisitS1x8Not(Node* node) { + VisitRR(this, kMips64S128Not, node); +} + +void InstructionSelector::VisitS1x8AnyTrue(Node* node) { + VisitRR(this, kMips64S1x8AnyTrue, node); +} + +void InstructionSelector::VisitS1x8AllTrue(Node* node) { + VisitRR(this, kMips64S1x8AllTrue, node); +} + +void InstructionSelector::VisitS1x16And(Node* node) { + VisitRRR(this, kMips64S128And, node); +} + +void InstructionSelector::VisitS1x16Or(Node* node) { + VisitRRR(this, kMips64S128Or, node); +} + +void InstructionSelector::VisitS1x16Xor(Node* node) { + VisitRRR(this, kMips64S128Xor, node); +} + +void InstructionSelector::VisitS1x16Not(Node* node) { + VisitRR(this, kMips64S128Not, node); +} + +void InstructionSelector::VisitS1x16AnyTrue(Node* node) { + VisitRR(this, kMips64S1x16AnyTrue, node); +} + +void InstructionSelector::VisitS1x16AllTrue(Node* node) { + VisitRR(this, kMips64S1x16AllTrue, node); +} + // static MachineOperatorBuilder::Flags InstructionSelector::SupportedMachineOperatorFlags() { diff --git a/src/mips/assembler-mips.cc b/src/mips/assembler-mips.cc index 96750225f4..c507432a58 100644 --- a/src/mips/assembler-mips.cc +++ b/src/mips/assembler-mips.cc @@ -479,6 +479,29 @@ const int kEndOfChain = -4; // Determines the end of the Jump chain (a subset of the label link chain). const int kEndOfJumpChain = 0; +bool Assembler::IsMsaBranch(Instr instr) { + uint32_t opcode = GetOpcodeField(instr); + uint32_t rs_field = GetRsField(instr); + if (opcode == COP1) { + switch (rs_field) { + case BZ_V: + case BZ_B: + case BZ_H: + case BZ_W: + case BZ_D: + case BNZ_V: + case BNZ_B: + case BNZ_H: + case BNZ_W: + case BNZ_D: + return true; + default: + return false; + } + } else { + return false; + } +} bool Assembler::IsBranch(Instr instr) { uint32_t opcode = GetOpcodeField(instr); @@ -492,7 +515,7 @@ bool Assembler::IsBranch(Instr instr) { rt_field == BLTZAL || rt_field == BGEZAL)) || (opcode == COP1 && rs_field == BC1) || // Coprocessor branch. (opcode == COP1 && rs_field == BC1EQZ) || - (opcode == COP1 && rs_field == BC1NEZ); + (opcode == COP1 && rs_field == BC1NEZ) || IsMsaBranch(instr); if (!isBranch && IsMipsArchVariant(kMips32r6)) { // All the 3 variants of POP10 (BOVC, BEQC, BEQZALC) and // POP30 (BNVC, BNEC, BNEZALC) are branch ops. diff --git a/src/mips/assembler-mips.h b/src/mips/assembler-mips.h index 383d3bf460..e30e54273e 100644 --- a/src/mips/assembler-mips.h +++ b/src/mips/assembler-mips.h @@ -1104,15 +1104,45 @@ class Assembler : public AssemblerBase { // MSA instructions void bz_v(MSARegister wt, int16_t offset); + inline void bz_v(MSARegister wt, Label* L) { + bz_v(wt, shifted_branch_offset(L)); + } void bz_b(MSARegister wt, int16_t offset); + inline void bz_b(MSARegister wt, Label* L) { + bz_b(wt, shifted_branch_offset(L)); + } void bz_h(MSARegister wt, int16_t offset); + inline void bz_h(MSARegister wt, Label* L) { + bz_h(wt, shifted_branch_offset(L)); + } void bz_w(MSARegister wt, int16_t offset); + inline void bz_w(MSARegister wt, Label* L) { + bz_w(wt, shifted_branch_offset(L)); + } void bz_d(MSARegister wt, int16_t offset); + inline void bz_d(MSARegister wt, Label* L) { + bz_d(wt, shifted_branch_offset(L)); + } void bnz_v(MSARegister wt, int16_t offset); + inline void bnz_v(MSARegister wt, Label* L) { + bnz_v(wt, shifted_branch_offset(L)); + } void bnz_b(MSARegister wt, int16_t offset); + inline void bnz_b(MSARegister wt, Label* L) { + bnz_b(wt, shifted_branch_offset(L)); + } void bnz_h(MSARegister wt, int16_t offset); + inline void bnz_h(MSARegister wt, Label* L) { + bnz_h(wt, shifted_branch_offset(L)); + } void bnz_w(MSARegister wt, int16_t offset); + inline void bnz_w(MSARegister wt, Label* L) { + bnz_w(wt, shifted_branch_offset(L)); + } void bnz_d(MSARegister wt, int16_t offset); + inline void bnz_d(MSARegister wt, Label* L) { + bnz_d(wt, shifted_branch_offset(L)); + } void ld_b(MSARegister wd, const MemOperand& rs); void ld_h(MSARegister wd, const MemOperand& rs); @@ -1767,6 +1797,7 @@ class Assembler : public AssemblerBase { // Check if an instruction is a branch of some kind. static bool IsBranch(Instr instr); + static bool IsMsaBranch(Instr instr); static bool IsBc(Instr instr); static bool IsBzc(Instr instr); static bool IsBeq(Instr instr); diff --git a/src/mips/constants-mips.h b/src/mips/constants-mips.h index 6a62787ef4..3fd2da47d7 100644 --- a/src/mips/constants-mips.h +++ b/src/mips/constants-mips.h @@ -1061,6 +1061,36 @@ inline Condition NegateFpuCondition(Condition cc) { } } +enum MSABranchCondition { + all_not_zero = 0, // Branch If All Elements Are Not Zero + one_elem_not_zero, // Branch If At Least One Element of Any Format Is Not + // Zero + one_elem_zero, // Branch If At Least One Element Is Zero + all_zero // Branch If All Elements of Any Format Are Zero +}; + +inline MSABranchCondition NegateMSABranchCondition(MSABranchCondition cond) { + switch (cond) { + case all_not_zero: + return one_elem_zero; + case one_elem_not_zero: + return all_zero; + case one_elem_zero: + return all_not_zero; + case all_zero: + return one_elem_not_zero; + default: + return cond; + } +} + +enum MSABranchDF { + MSA_BRANCH_B = 0, + MSA_BRANCH_H, + MSA_BRANCH_W, + MSA_BRANCH_D, + MSA_BRANCH_V +}; // Commute a condition such that {a cond b == b cond' a}. inline Condition CommuteCondition(Condition cc) { @@ -1840,6 +1870,16 @@ bool InstructionGetters::IsForbiddenAfterBranchInstr(Instr instr) { case BC1: case BC1EQZ: case BC1NEZ: + case BZ_V: + case BZ_B: + case BZ_H: + case BZ_W: + case BZ_D: + case BNZ_V: + case BNZ_B: + case BNZ_H: + case BNZ_W: + case BNZ_D: return true; break; default: diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc index 90361e7305..b38cb9b8c2 100644 --- a/src/mips/macro-assembler-mips.cc +++ b/src/mips/macro-assembler-mips.cc @@ -2316,6 +2316,82 @@ void MacroAssembler::BranchShortF(SecondaryField sizeField, Label* target, } } +void MacroAssembler::BranchMSA(Label* target, MSABranchDF df, + MSABranchCondition cond, MSARegister wt, + BranchDelaySlot bd) { + { + BlockTrampolinePoolScope block_trampoline_pool(this); + + if (target) { + bool long_branch = + target->is_bound() ? !is_near(target) : is_trampoline_emitted(); + if (long_branch) { + Label skip; + MSABranchCondition neg_cond = NegateMSABranchCondition(cond); + BranchShortMSA(df, &skip, neg_cond, wt, bd); + BranchLong(target, bd); + bind(&skip); + } else { + BranchShortMSA(df, target, cond, wt, bd); + } + } + } +} + +void MacroAssembler::BranchShortMSA(MSABranchDF df, Label* target, + MSABranchCondition cond, MSARegister wt, + BranchDelaySlot bd) { + if (IsMipsArchVariant(kMips32r6)) { + BlockTrampolinePoolScope block_trampoline_pool(this); + if (target) { + switch (cond) { + case all_not_zero: + switch (df) { + case MSA_BRANCH_D: + bnz_d(wt, target); + break; + case MSA_BRANCH_W: + bnz_w(wt, target); + break; + case MSA_BRANCH_H: + bnz_h(wt, target); + break; + case MSA_BRANCH_B: + default: + bnz_b(wt, target); + } + break; + case one_elem_not_zero: + bnz_v(wt, target); + break; + case one_elem_zero: + switch (df) { + case MSA_BRANCH_D: + bz_d(wt, target); + break; + case MSA_BRANCH_W: + bz_w(wt, target); + break; + case MSA_BRANCH_H: + bz_h(wt, target); + break; + case MSA_BRANCH_B: + default: + bz_b(wt, target); + } + break; + case all_zero: + bz_v(wt, target); + break; + default: + UNREACHABLE(); + } + } + } + if (bd == PROTECT) { + nop(); + } +} void MacroAssembler::FmoveLow(FPURegister dst, Register src_low) { if (IsFp32Mode()) { diff --git a/src/mips/macro-assembler-mips.h b/src/mips/macro-assembler-mips.h index 3b2539e408..d7378317cc 100644 --- a/src/mips/macro-assembler-mips.h +++ b/src/mips/macro-assembler-mips.h @@ -913,6 +913,12 @@ class MacroAssembler: public Assembler { BranchF64(bd, target, nan, cc, cmp1, cmp2); } + void BranchMSA(Label* target, MSABranchDF df, MSABranchCondition cond, + MSARegister wt, BranchDelaySlot bd = PROTECT); + + void BranchShortMSA(MSABranchDF df, Label* target, MSABranchCondition cond, + MSARegister wt, BranchDelaySlot bd = PROTECT); + // Truncates a double using a specific rounding mode, and writes the value // to the result register. // The except_flag will contain any exceptions caused by the instruction. diff --git a/src/mips64/assembler-mips64.cc b/src/mips64/assembler-mips64.cc index 981fde07c7..838c2882af 100644 --- a/src/mips64/assembler-mips64.cc +++ b/src/mips64/assembler-mips64.cc @@ -460,6 +460,29 @@ const int kEndOfChain = -4; // Determines the end of the Jump chain (a subset of the label link chain). const int kEndOfJumpChain = 0; +bool Assembler::IsMsaBranch(Instr instr) { + uint32_t opcode = GetOpcodeField(instr); + uint32_t rs_field = GetRsField(instr); + if (opcode == COP1) { + switch (rs_field) { + case BZ_V: + case BZ_B: + case BZ_H: + case BZ_W: + case BZ_D: + case BNZ_V: + case BNZ_B: + case BNZ_H: + case BNZ_W: + case BNZ_D: + return true; + default: + return false; + } + } else { + return false; + } +} bool Assembler::IsBranch(Instr instr) { uint32_t opcode = GetOpcodeField(instr); @@ -473,7 +496,7 @@ bool Assembler::IsBranch(Instr instr) { rt_field == BLTZAL || rt_field == BGEZAL)) || (opcode == COP1 && rs_field == BC1) || // Coprocessor branch. (opcode == COP1 && rs_field == BC1EQZ) || - (opcode == COP1 && rs_field == BC1NEZ); + (opcode == COP1 && rs_field == BC1NEZ) || IsMsaBranch(instr); if (!isBranch && kArchVariant == kMips64r6) { // All the 3 variants of POP10 (BOVC, BEQC, BEQZALC) and // POP30 (BNVC, BNEC, BNEZALC) are branch ops. diff --git a/src/mips64/assembler-mips64.h b/src/mips64/assembler-mips64.h index 98e712455e..2312bfbbe2 100644 --- a/src/mips64/assembler-mips64.h +++ b/src/mips64/assembler-mips64.h @@ -1159,15 +1159,45 @@ class Assembler : public AssemblerBase { // MSA instructions void bz_v(MSARegister wt, int16_t offset); + inline void bz_v(MSARegister wt, Label* L) { + bz_v(wt, shifted_branch_offset(L)); + } void bz_b(MSARegister wt, int16_t offset); + inline void bz_b(MSARegister wt, Label* L) { + bz_b(wt, shifted_branch_offset(L)); + } void bz_h(MSARegister wt, int16_t offset); + inline void bz_h(MSARegister wt, Label* L) { + bz_h(wt, shifted_branch_offset(L)); + } void bz_w(MSARegister wt, int16_t offset); + inline void bz_w(MSARegister wt, Label* L) { + bz_w(wt, shifted_branch_offset(L)); + } void bz_d(MSARegister wt, int16_t offset); + inline void bz_d(MSARegister wt, Label* L) { + bz_d(wt, shifted_branch_offset(L)); + } void bnz_v(MSARegister wt, int16_t offset); + inline void bnz_v(MSARegister wt, Label* L) { + bnz_v(wt, shifted_branch_offset(L)); + } void bnz_b(MSARegister wt, int16_t offset); + inline void bnz_b(MSARegister wt, Label* L) { + bnz_b(wt, shifted_branch_offset(L)); + } void bnz_h(MSARegister wt, int16_t offset); + inline void bnz_h(MSARegister wt, Label* L) { + bnz_h(wt, shifted_branch_offset(L)); + } void bnz_w(MSARegister wt, int16_t offset); + inline void bnz_w(MSARegister wt, Label* L) { + bnz_w(wt, shifted_branch_offset(L)); + } void bnz_d(MSARegister wt, int16_t offset); + inline void bnz_d(MSARegister wt, Label* L) { + bnz_d(wt, shifted_branch_offset(L)); + } void ld_b(MSARegister wd, const MemOperand& rs); void ld_h(MSARegister wd, const MemOperand& rs); @@ -1827,6 +1857,7 @@ class Assembler : public AssemblerBase { // Check if an instruction is a branch of some kind. static bool IsBranch(Instr instr); + static bool IsMsaBranch(Instr instr); static bool IsBc(Instr instr); static bool IsBzc(Instr instr); diff --git a/src/mips64/constants-mips64.h b/src/mips64/constants-mips64.h index 27477a2046..7215da54fb 100644 --- a/src/mips64/constants-mips64.h +++ b/src/mips64/constants-mips64.h @@ -1092,6 +1092,36 @@ inline Condition NegateFpuCondition(Condition cc) { } } +enum MSABranchCondition { + all_not_zero = 0, // Branch If All Elements Are Not Zero + one_elem_not_zero, // Branch If At Least One Element of Any Format Is Not + // Zero + one_elem_zero, // Branch If At Least One Element Is Zero + all_zero // Branch If All Elements of Any Format Are Zero +}; + +inline MSABranchCondition NegateMSABranchCondition(MSABranchCondition cond) { + switch (cond) { + case all_not_zero: + return one_elem_zero; + case one_elem_not_zero: + return all_zero; + case one_elem_zero: + return all_not_zero; + case all_zero: + return one_elem_not_zero; + default: + return cond; + } +} + +enum MSABranchDF { + MSA_BRANCH_B = 0, + MSA_BRANCH_H, + MSA_BRANCH_W, + MSA_BRANCH_D, + MSA_BRANCH_V +}; // Commute a condition such that {a cond b == b cond' a}. inline Condition CommuteCondition(Condition cc) { @@ -1918,6 +1948,16 @@ bool InstructionGetters::IsForbiddenAfterBranchInstr(Instr instr) { case BC1: case BC1EQZ: case BC1NEZ: + case BZ_V: + case BZ_B: + case BZ_H: + case BZ_W: + case BZ_D: + case BNZ_V: + case BNZ_B: + case BNZ_H: + case BNZ_W: + case BNZ_D: return true; break; default: diff --git a/src/mips64/macro-assembler-mips64.cc b/src/mips64/macro-assembler-mips64.cc index 769cd7fd78..df9dbdb74f 100644 --- a/src/mips64/macro-assembler-mips64.cc +++ b/src/mips64/macro-assembler-mips64.cc @@ -2735,6 +2735,82 @@ void MacroAssembler::BranchShortF(SecondaryField sizeField, Label* target, } } +void MacroAssembler::BranchMSA(Label* target, MSABranchDF df, + MSABranchCondition cond, MSARegister wt, + BranchDelaySlot bd) { + { + BlockTrampolinePoolScope block_trampoline_pool(this); + + if (target) { + bool long_branch = + target->is_bound() ? !is_near(target) : is_trampoline_emitted(); + if (long_branch) { + Label skip; + MSABranchCondition neg_cond = NegateMSABranchCondition(cond); + BranchShortMSA(df, &skip, neg_cond, wt, bd); + BranchLong(target, bd); + bind(&skip); + } else { + BranchShortMSA(df, target, cond, wt, bd); + } + } + } +} + +void MacroAssembler::BranchShortMSA(MSABranchDF df, Label* target, + MSABranchCondition cond, MSARegister wt, + BranchDelaySlot bd) { + if (kArchVariant == kMips64r6) { + BlockTrampolinePoolScope block_trampoline_pool(this); + if (target) { + switch (cond) { + case all_not_zero: + switch (df) { + case MSA_BRANCH_D: + bnz_d(wt, target); + break; + case MSA_BRANCH_W: + bnz_w(wt, target); + break; + case MSA_BRANCH_H: + bnz_h(wt, target); + break; + case MSA_BRANCH_B: + default: + bnz_b(wt, target); + } + break; + case one_elem_not_zero: + bnz_v(wt, target); + break; + case one_elem_zero: + switch (df) { + case MSA_BRANCH_D: + bz_d(wt, target); + break; + case MSA_BRANCH_W: + bz_w(wt, target); + break; + case MSA_BRANCH_H: + bz_h(wt, target); + break; + case MSA_BRANCH_B: + default: + bz_b(wt, target); + } + break; + case all_zero: + bz_v(wt, target); + break; + default: + UNREACHABLE(); + } + } + } + if (bd == PROTECT) { + nop(); + } +} void MacroAssembler::FmoveLow(FPURegister dst, Register src_low) { DCHECK(!src_low.is(at)); diff --git a/src/mips64/macro-assembler-mips64.h b/src/mips64/macro-assembler-mips64.h index 695e1975d1..509d9fde97 100644 --- a/src/mips64/macro-assembler-mips64.h +++ b/src/mips64/macro-assembler-mips64.h @@ -977,6 +977,12 @@ class MacroAssembler: public Assembler { BranchF64(bd, target, nan, cc, cmp1, cmp2); } + void BranchMSA(Label* target, MSABranchDF df, MSABranchCondition cond, + MSARegister wt, BranchDelaySlot bd = PROTECT); + + void BranchShortMSA(MSABranchDF df, Label* target, MSABranchCondition cond, + MSARegister wt, BranchDelaySlot bd = PROTECT); + // Truncates a double using a specific rounding mode, and writes the value // to the result register. // The except_flag will contain any exceptions caused by the instruction. diff --git a/test/cctest/test-disasm-mips.cc b/test/cctest/test-disasm-mips.cc index a8e13937b7..7e99fda537 100644 --- a/test/cctest/test-disasm-mips.cc +++ b/test/cctest/test-disasm-mips.cc @@ -1131,14 +1131,16 @@ TEST(MSA_BRANCH) { 32767); COMPARE_MSA_BRANCH(bnz_d(w3, -32768), "47e38000 bnz.d w3, -32768", -32768); - COMPARE_MSA_BRANCH(bnz_v(w0, 0), "45e00000 bnz.v w0, 0", 0); + COMPARE_MSA_BRANCH(bnz_v(w0, static_cast(0)), + "45e00000 bnz.v w0, 0", 0); COMPARE_MSA_BRANCH(bz_b(w0, 1), "47000001 bz.b w0, 1", 1); COMPARE_MSA_BRANCH(bz_h(w1, -1), "4721ffff bz.h w1, -1", -1); COMPARE_MSA_BRANCH(bz_w(w2, 32767), "47427fff bz.w w2, 32767", 32767); COMPARE_MSA_BRANCH(bz_d(w3, -32768), "47638000 bz.d w3, -32768", -32768); - COMPARE_MSA_BRANCH(bz_v(w0, 0), "45600000 bz.v w0, 0", 0); + COMPARE_MSA_BRANCH(bz_v(w0, static_cast(0)), + "45600000 bz.v w0, 0", 0); } VERIFY_RUN(); } diff --git a/test/cctest/test-disasm-mips64.cc b/test/cctest/test-disasm-mips64.cc index 5046527d4e..fe5eec5bfa 100644 --- a/test/cctest/test-disasm-mips64.cc +++ b/test/cctest/test-disasm-mips64.cc @@ -1332,14 +1332,16 @@ TEST(MSA_BRANCH) { 32767); COMPARE_MSA_BRANCH(bnz_d(w3, -32768), "47e38000 bnz.d w3, -32768", -32768); - COMPARE_MSA_BRANCH(bnz_v(w0, 0), "45e00000 bnz.v w0, 0", 0); + COMPARE_MSA_BRANCH(bnz_v(w0, static_cast(0)), + "45e00000 bnz.v w0, 0", 0); COMPARE_MSA_BRANCH(bz_b(w0, 1), "47000001 bz.b w0, 1", 1); COMPARE_MSA_BRANCH(bz_h(w1, -1), "4721ffff bz.h w1, -1", -1); COMPARE_MSA_BRANCH(bz_w(w2, 32767), "47427fff bz.w w2, 32767", 32767); COMPARE_MSA_BRANCH(bz_d(w3, -32768), "47638000 bz.d w3, -32768", -32768); - COMPARE_MSA_BRANCH(bz_v(w0, 0), "45600000 bz.v w0, 0", 0); + COMPARE_MSA_BRANCH(bz_v(w0, static_cast(0)), + "45600000 bz.v w0, 0", 0); } VERIFY_RUN(); } diff --git a/test/cctest/wasm/test-run-wasm-simd.cc b/test/cctest/wasm/test-run-wasm-simd.cc index bfc5eb1e4e..3734268166 100644 --- a/test/cctest/wasm/test-run-wasm-simd.cc +++ b/test/cctest/wasm/test-run-wasm-simd.cc @@ -1800,7 +1800,9 @@ WASM_SIMD_TEST(S32x4Concat) { RunConcatOpTest(kExprS32x4Shuffle); } WASM_SIMD_TEST(S16x8Concat) { RunConcatOpTest(kExprS16x8Shuffle); } WASM_SIMD_TEST(S8x16Concat) { RunConcatOpTest(kExprS8x16Shuffle); } +#endif // V8_TARGET_ARCH_ARM +#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 // Boolean unary operations are 'AllTrue' and 'AnyTrue', which return an integer // result. Use relational ops on numeric vectors to create the boolean vector // test inputs. Test inputs with all true, all false, one true, and one false. @@ -1970,9 +1972,10 @@ WASM_SIMD_TEST(S1x16And) { RunS1x16BinOpTest(kExprS1x16And, And); } WASM_SIMD_TEST(S1x16Or) { RunS1x16BinOpTest(kExprS1x16Or, Or); } WASM_SIMD_TEST(S1x16Xor) { RunS1x16BinOpTest(kExprS1x16Xor, Xor); } -#endif // !V8_TARGET_ARCH_ARM +#endif // !V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 -#if V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET +#if V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET || V8_TARGET_ARCH_MIPS || \ + V8_TARGET_ARCH_MIPS64 WASM_SIMD_TEST(SimdI32x4ExtractWithF32x4) { WasmRunner r(kExecuteCompiled); BUILD(r, WASM_IF_ELSE_I( @@ -2026,9 +2029,11 @@ WASM_SIMD_TEST(SimdI32x4AddWithF32x4) { WASM_I32V(1), WASM_I32V(0))); CHECK_EQ(1, r.Call()); } -#endif // V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET +#endif // V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET || V8_TARGET_ARCH_MIPS || + // V8_TARGET_ARCH_MIPS64 -#if V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET || V8_TARGET_ARCH_X64 +#if V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET || V8_TARGET_ARCH_X64 || \ + V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 WASM_SIMD_TEST(SimdI32x4Local) { WasmRunner r(kExecuteCompiled); r.AllocateLocal(kWasmS128); @@ -2082,9 +2087,11 @@ WASM_SIMD_TEST(SimdI32x4For) { WASM_GET_LOCAL(0)); CHECK_EQ(1, r.Call()); } -#endif // V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET || V8_TARGET_ARCH_X64 +#endif // V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET || V8_TARGET_ARCH_X64 || + // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 -#if V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET +#if V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET || V8_TARGET_ARCH_MIPS || \ + V8_TARGET_ARCH_MIPS64 WASM_SIMD_TEST(SimdF32x4For) { WasmRunner r(kExecuteCompiled); r.AllocateLocal(kWasmI32); @@ -2108,9 +2115,11 @@ WASM_SIMD_TEST(SimdF32x4For) { WASM_GET_LOCAL(0)); CHECK_EQ(1, r.Call()); } -#endif // V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET +#endif // V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET || V8_TARGET_ARCH_MIPS || + // V8_TARGET_ARCH_MIPS64 -#if V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET || V8_TARGET_ARCH_X64 +#if V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET || V8_TARGET_ARCH_X64 || \ + V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 template void SetVectorByLanes(T* v, const std::array& arr) { @@ -2177,9 +2186,11 @@ WASM_SIMD_TEST(SimdI32x4SetGlobal) { CHECK_EQ(GetScalar(global, 2), 45); CHECK_EQ(GetScalar(global, 3), 56); } -#endif // V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET || V8_TARGET_ARCH_X64 +#endif // V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET || V8_TARGET_ARCH_X64 || + // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 -#if V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET +#if V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET || V8_TARGET_ARCH_MIPS || \ + V8_TARGET_ARCH_MIPS64 WASM_SIMD_TEST(SimdF32x4GetGlobal) { WasmRunner r(kExecuteCompiled); float* global = r.module().AddGlobal(kWasmS128); @@ -2220,9 +2231,11 @@ WASM_SIMD_TEST(SimdF32x4SetGlobal) { CHECK_EQ(GetScalar(global, 2), 32.25f); CHECK_EQ(GetScalar(global, 3), 65.0f); } -#endif // V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET +#endif // V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET || V8_TARGET_ARCH_MIPS || + // V8_TARGET_ARCH_MIPS64 -#if V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET || V8_TARGET_ARCH_X64 +#if V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET || V8_TARGET_ARCH_X64 || \ + V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 WASM_SIMD_TEST(SimdLoadStoreLoad) { WasmRunner r(kExecuteCompiled); int32_t* memory = r.module().AddMemoryElems(4); @@ -2239,4 +2252,5 @@ WASM_SIMD_TEST(SimdLoadStoreLoad) { CHECK_EQ(expected, r.Call()); } } -#endif // V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET || V8_TARGET_ARCH_X64 +#endif // V8_TARGET_ARCH_ARM || SIMD_LOWERING_TARGET || V8_TARGET_ARCH_X64 || + // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64