MIPS[64]: Support for some SIMD operations (8)

Add support for S1x4And, S1x4Or, S1x4Xor, S1x4Not, S1x4AnyTrue,
S1x4AllTrue, S1x8And, S1x8Or, S1x8Xor, S1x8Not, S1x8AnyTrue,
S1x8AllTrue, S1x16And, S1x16Or, S1x16Xor, S1x16Not, S1x16AnyTrue,
S1x16AllTrue, SimdLoad, SimdStore operations for mips32 and mips64
architectures.

BUG=

Review-Url: https://codereview.chromium.org/2801683003
Cr-Commit-Position: refs/heads/master@{#45662}
This commit is contained in:
dusan.simicic 2017-06-01 06:25:50 -07:00 committed by Commit Bot
parent 6a99238b90
commit 3e3dbdf3e5
20 changed files with 690 additions and 31 deletions

View File

@ -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); }

View File

@ -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)

View File

@ -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

View File

@ -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() {

View File

@ -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)

View File

@ -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

View File

@ -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() {

View File

@ -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.

View File

@ -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);

View File

@ -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<T>::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:

View File

@ -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()) {

View File

@ -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.

View File

@ -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.

View File

@ -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);

View File

@ -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<T>::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:

View File

@ -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));

View File

@ -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.

View File

@ -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<int16_t>(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<int16_t>(0)),
"45600000 bz.v w0, 0", 0);
}
VERIFY_RUN();
}

View File

@ -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<int16_t>(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<int16_t>(0)),
"45600000 bz.v w0, 0", 0);
}
VERIFY_RUN();
}

View File

@ -1800,7 +1800,9 @@ WASM_SIMD_TEST(S32x4Concat) { RunConcatOpTest<int32_t>(kExprS32x4Shuffle); }
WASM_SIMD_TEST(S16x8Concat) { RunConcatOpTest<int16_t>(kExprS16x8Shuffle); }
WASM_SIMD_TEST(S8x16Concat) { RunConcatOpTest<int8_t>(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<int32_t> 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<int32_t> 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<int32_t> 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 <typename T, int numLanes = 4>
void SetVectorByLanes(T* v, const std::array<T, numLanes>& 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<int32_t, int32_t> r(kExecuteCompiled);
float* global = r.module().AddGlobal<float>(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<int32_t> r(kExecuteCompiled);
int32_t* memory = r.module().AddMemoryElems<int32_t>(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