Commit a1fc8a1b authored by LiuYu's avatar LiuYu Committed by Commit Bot

[mips][wasm-simd] Prototype load lane and store lane

Port: 6dbc2b01

Bug: v8:10975

Change-Id: Id3e70dda9f71ecf333890e70d6a5e64ed5a91ccf
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2575731Reviewed-by: 's avatarZhao Jiazhong <zhaojiazhong-hf@loongson.cn>
Reviewed-by: 's avatarZhi An Ng <zhin@chromium.org>
Commit-Queue: Zhi An Ng <zhin@chromium.org>
Auto-Submit: Liu yu <liuyu@loongson.cn>
Cr-Commit-Position: refs/heads/master@{#71734}
parent ccf2e735
......@@ -240,6 +240,8 @@ class MSARegisters {
static const RegisterAlias aliases_[];
};
enum MSASize { MSA_B = 0x0, MSA_H = 0x1, MSA_W = 0x2, MSA_D = 0x3 };
// -----------------------------------------------------------------------------
// Instructions encoding constants.
......
......@@ -2621,6 +2621,64 @@ void TurboAssembler::Round_s_s(FPURegister dst, FPURegister src) {
});
}
void TurboAssembler::LoadLane(MSASize sz, MSARegister dst, uint8_t laneidx,
MemOperand src) {
switch (sz) {
case MSA_B:
Lbu(kScratchReg, src);
insert_b(dst, laneidx, kScratchReg);
break;
case MSA_H:
Lhu(kScratchReg, src);
insert_h(dst, laneidx, kScratchReg);
break;
case MSA_W:
Lwu(kScratchReg, src);
insert_w(dst, laneidx, kScratchReg);
break;
case MSA_D:
Ld(kScratchReg, src);
insert_d(dst, laneidx, kScratchReg);
break;
default:
UNREACHABLE();
}
}
void TurboAssembler::StoreLane(MSASize sz, MSARegister src, uint8_t laneidx,
MemOperand dst) {
switch (sz) {
case MSA_B:
copy_u_b(kScratchReg, src, laneidx);
Sb(kScratchReg, dst);
break;
case MSA_H:
copy_u_h(kScratchReg, src, laneidx);
Sh(kScratchReg, dst);
break;
case MSA_W:
if (laneidx == 0) {
FPURegister src_reg = FPURegister::from_code(src.code());
Swc1(src_reg, dst);
} else {
copy_u_w(kScratchReg, src, laneidx);
Sw(kScratchReg, dst);
}
break;
case MSA_D:
if (laneidx == 0) {
FPURegister src_reg = FPURegister::from_code(src.code());
Sdc1(src_reg, dst);
} else {
copy_s_d(kScratchReg, src, laneidx);
Sd(kScratchReg, dst);
}
break;
default:
UNREACHABLE();
}
}
void TurboAssembler::MSARoundW(MSARegister dst, MSARegister src,
FPURoundingMode mode) {
BlockTrampolinePoolScope block_trampoline_pool(this);
......
......@@ -791,6 +791,8 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
void Floor_s_s(FPURegister fd, FPURegister fs);
void Ceil_s_s(FPURegister fd, FPURegister fs);
void LoadLane(MSASize sz, MSARegister dst, uint8_t laneidx, MemOperand src);
void StoreLane(MSASize sz, MSARegister src, uint8_t laneidx, MemOperand dst);
void MSARoundW(MSARegister dst, MSARegister src, FPURoundingMode mode);
void MSARoundD(MSARegister dst, MSARegister src, FPURoundingMode mode);
......
......@@ -2829,12 +2829,12 @@ void InstructionSelector::VisitI16x8ExtAddPairwiseI8x16U(Node* node) {
#endif // !V8_TARGET_ARCH_ARM64 && !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_X64
#if !V8_TARGET_ARCH_X64 && !V8_TARGET_ARCH_IA32 && !V8_TARGET_ARCH_ARM64 && \
!V8_TARGET_ARCH_ARM
!V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_MIPS64
// TODO(v8:10975): Prototyping load lane and store lane.
void InstructionSelector::VisitLoadLane(Node* node) { UNIMPLEMENTED(); }
void InstructionSelector::VisitStoreLane(Node* node) { UNIMPLEMENTED(); }
#endif // !V8_TARGET_ARCH_X64 && !V8_TARGET_ARCH_IA32 && !V8_TARGET_ARCH_ARM64
// && !V8_TARGET_ARCH_ARM
// && !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_MIPS64
#if !V8_TARGET_ARCH_X64 && !V8_TARGET_ARCH_IA32 && !V8_TARGET_ARCH_ARM64 && \
!V8_TARGET_ARCH_ARM
......
......@@ -1967,6 +1967,21 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ insert_d(dst, 0, kScratchReg);
break;
}
case kMips64S128LoadLane: {
CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
Simd128Register dst = i.OutputSimd128Register();
DCHECK_EQ(dst, i.InputSimd128Register(0));
auto sz = static_cast<MSASize>(MiscField::decode(instr->opcode()));
__ LoadLane(sz, dst, i.InputUint8(1), i.MemoryOperand(2));
break;
}
case kMips64S128StoreLane: {
CpuFeatureScope msa_scope(tasm(), MIPS_SIMD);
Simd128Register src = i.InputSimd128Register(0);
auto sz = static_cast<MSASize>(MiscField::decode(instr->opcode()));
__ StoreLane(sz, src, i.InputUint8(1), i.MemoryOperand(2));
break;
}
case kWord32AtomicLoadInt8:
ASSEMBLE_ATOMIC_LOAD_INTEGER(Lb);
break;
......
......@@ -362,6 +362,8 @@ namespace compiler {
V(Mips64S128Load32x2U) \
V(Mips64S128Load32Zero) \
V(Mips64S128Load64Zero) \
V(Mips64S128LoadLane) \
V(Mips64S128StoreLane) \
V(Mips64MsaLd) \
V(Mips64MsaSt) \
V(Mips64I32x4SConvertI16x8Low) \
......
......@@ -363,6 +363,7 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kMips64S128Load32x2U:
case kMips64S128Load32Zero:
case kMips64S128Load64Zero:
case kMips64S128LoadLane:
case kMips64Word64AtomicLoadUint8:
case kMips64Word64AtomicLoadUint16:
case kMips64Word64AtomicLoadUint32:
......@@ -387,6 +388,7 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kMips64Usw:
case kMips64Uswc1:
case kMips64Sync:
case kMips64S128StoreLane:
case kMips64Word64AtomicStoreWord8:
case kMips64Word64AtomicStoreWord16:
case kMips64Word64AtomicStoreWord32:
......
......@@ -4,6 +4,7 @@
#include "src/base/bits.h"
#include "src/base/platform/wrappers.h"
#include "src/codegen/machine-type.h"
#include "src/compiler/backend/instruction-selector-impl.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/node-properties.h"
......@@ -374,7 +375,7 @@ void EmitLoad(InstructionSelector* selector, Node* node, InstructionCode opcode,
} else {
InstructionOperand addr_reg = g.TempRegister();
selector->Emit(kMips64Dadd | AddressingModeField::encode(kMode_None),
addr_reg, g.UseRegister(index), g.UseRegister(base));
addr_reg, g.UseRegister(base), g.UseRegister(index));
// Emit desired load opcode, using temp addr_reg.
selector->Emit(opcode | AddressingModeField::encode(kMode_MRI),
g.DefineAsRegister(output == nullptr ? node : output),
......@@ -382,6 +383,77 @@ void EmitLoad(InstructionSelector* selector, Node* node, InstructionCode opcode,
}
}
namespace {
InstructionOperand EmitAddBeforeS128LoadStore(InstructionSelector* selector,
Node* node,
InstructionCode* opcode) {
Mips64OperandGenerator g(selector);
Node* base = node->InputAt(0);
Node* index = node->InputAt(1);
InstructionOperand addr_reg = g.TempRegister();
selector->Emit(kMips64Dadd | AddressingModeField::encode(kMode_None),
addr_reg, g.UseRegister(base), g.UseRegister(index));
*opcode |= AddressingModeField::encode(kMode_MRI);
return addr_reg;
}
// Helper struct for load lane and store lane to indicate what memory size
// to be encoded in the opcode, and the new lane index.
struct LoadStoreLaneParams {
MSASize sz;
uint8_t laneidx;
LoadStoreLaneParams(uint8_t laneidx, MSASize sz, int lanes)
: sz(sz), laneidx(laneidx % lanes) {}
};
LoadStoreLaneParams GetLoadStoreLaneParams(MachineRepresentation rep,
uint8_t laneidx) {
switch (rep) {
case MachineRepresentation::kWord8:
return LoadStoreLaneParams(laneidx, MSA_B, 16);
case MachineRepresentation::kWord16:
return LoadStoreLaneParams(laneidx, MSA_H, 8);
case MachineRepresentation::kWord32:
return LoadStoreLaneParams(laneidx, MSA_W, 4);
case MachineRepresentation::kWord64:
return LoadStoreLaneParams(laneidx, MSA_D, 2);
default:
break;
}
UNREACHABLE();
}
} // namespace
void InstructionSelector::VisitStoreLane(Node* node) {
StoreLaneParameters params = StoreLaneParametersOf(node->op());
LoadStoreLaneParams f = GetLoadStoreLaneParams(params.rep, params.laneidx);
InstructionCode opcode = kMips64S128StoreLane;
opcode |= MiscField::encode(f.sz);
Mips64OperandGenerator g(this);
InstructionOperand addr = EmitAddBeforeS128LoadStore(this, node, &opcode);
InstructionOperand inputs[4] = {
g.UseRegister(node->InputAt(2)),
g.UseImmediate(f.laneidx),
addr,
g.TempImmediate(0),
};
Emit(opcode, 0, nullptr, 4, inputs);
}
void InstructionSelector::VisitLoadLane(Node* node) {
LoadLaneParameters params = LoadLaneParametersOf(node->op());
LoadStoreLaneParams f =
GetLoadStoreLaneParams(params.rep.representation(), params.laneidx);
InstructionCode opcode = kMips64S128LoadLane;
opcode |= MiscField::encode(f.sz);
Mips64OperandGenerator g(this);
InstructionOperand addr = EmitAddBeforeS128LoadStore(this, node, &opcode);
Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(2)),
g.UseImmediate(f.laneidx), addr, g.TempImmediate(0));
}
void InstructionSelector::VisitLoadTransform(Node* node) {
LoadTransformParameters params = LoadTransformParametersOf(node->op());
......
......@@ -3983,7 +3983,7 @@ WASM_SIMD_TEST(S128Load64Zero) {
}
#if V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_ARM64 || \
V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_S390X
V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_S390X || V8_TARGET_ARCH_MIPS64
// TODO(v8:10975): Prototyping load lane and store lane.
template <typename T>
void RunLoadLaneTest(TestExecutionTier execution_tier, LowerSimd lower_simd,
......@@ -4189,7 +4189,7 @@ WASM_SIMD_TEST_NO_LOWERING(S128Store64Lane) {
}
#endif // V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_ARM64 ||
// V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_S390X
// V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_S390X || V8_TARGET_ARCH_MIPS64
#define WASM_SIMD_ANYTRUE_TEST(format, lanes, max, param_type) \
WASM_SIMD_TEST(S##format##AnyTrue) { \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment