Commit c0a632b3 authored by Ivica Bogosavljevic's avatar Ivica Bogosavljevic Committed by Commit Bot

MIPS[64]: Add simulation support for MIPS SIMD MI10 instruction group

Add support for the simulation of MIPS SIMD MI10 instruction group,
which included Load Vector and Store Vector instructions. Add
corresponding test for these instructions.

Bug: 
Change-Id: I7cbc9d8dff2a779d9a716f539cd9a2bbb8ac694a
Reviewed-on: https://chromium-review.googlesource.com/595567Reviewed-by: 's avatarMiran Karić <Miran.Karic@imgtec.com>
Commit-Queue: Ivica Bogosavljevic <ivica.bogosavljevic@imgtec.com>
Cr-Commit-Position: refs/heads/master@{#47226}
parent 6cd7fcd2
......@@ -1898,6 +1898,74 @@ void Simulator::TraceMemWr(int32_t addr, int32_t value, TraceType t) {
}
}
template <typename T>
void Simulator::TraceMemRd(int32_t addr, T value) {
if (::v8::internal::FLAG_trace_sim) {
switch (sizeof(T)) {
case 1:
SNPrintF(trace_buf_,
"%08" PRIx8 " <-- [%08" PRIx32 "] (%" PRIu64
") int8:%" PRId8 " uint8:%" PRIu8,
static_cast<uint8_t>(value), addr, icount_,
static_cast<int8_t>(value), static_cast<uint8_t>(value));
break;
case 2:
SNPrintF(trace_buf_,
"%08" PRIx16 " <-- [%08" PRIx32 "] (%" PRIu64
") int16:%" PRId16 " uint16:%" PRIu16,
static_cast<uint16_t>(value), addr, icount_,
static_cast<int16_t>(value), static_cast<uint16_t>(value));
break;
case 4:
SNPrintF(trace_buf_,
"%08" PRIx32 " <-- [%08" PRIx32 "] (%" PRIu64
") int32:%" PRId32 " uint32:%" PRIu32,
static_cast<uint32_t>(value), addr, icount_,
static_cast<int32_t>(value), static_cast<uint32_t>(value));
break;
case 8:
SNPrintF(trace_buf_,
"%08" PRIx64 " <-- [%08" PRIx32 "] (%" PRIu64
") int64:%" PRId64 " uint64:%" PRIu64,
static_cast<uint64_t>(value), addr, icount_,
static_cast<int64_t>(value), static_cast<uint64_t>(value));
break;
default:
UNREACHABLE();
}
}
}
template <typename T>
void Simulator::TraceMemWr(int32_t addr, T value) {
if (::v8::internal::FLAG_trace_sim) {
switch (sizeof(T)) {
case 1:
SNPrintF(trace_buf_,
" %02" PRIx8 " --> [%08" PRIx32 "] (%" PRIu64 ")",
static_cast<uint8_t>(value), addr, icount_);
break;
case 2:
SNPrintF(trace_buf_,
" %04" PRIx16 " --> [%08" PRIx32 "] (%" PRIu64 ")",
static_cast<uint16_t>(value), addr, icount_);
break;
case 4:
SNPrintF(trace_buf_,
"%08" PRIx32 " --> [%08" PRIx32 "] (%" PRIu64 ")",
static_cast<uint32_t>(value), addr, icount_);
break;
case 8:
SNPrintF(trace_buf_,
"%16" PRIx64 " --> [%08" PRIx32 "] (%" PRIu64 ")",
static_cast<uint64_t>(value), addr, icount_);
break;
default:
UNREACHABLE();
}
}
}
void Simulator::TraceMemRd(int32_t addr, int64_t value, TraceType t) {
if (::v8::internal::FLAG_trace_sim) {
union {
......@@ -2104,6 +2172,34 @@ void Simulator::WriteB(int32_t addr, int8_t value) {
*ptr = value;
}
template <typename T>
T Simulator::ReadMem(int32_t addr, Instruction* instr) {
int alignment_mask = (1 << sizeof(T)) - 1;
if ((addr & alignment_mask) == 0 || IsMipsArchVariant(kMips32r6)) {
T* ptr = reinterpret_cast<T*>(addr);
TraceMemRd(addr, *ptr);
return *ptr;
}
PrintF("Unaligned read of type sizeof(%d) at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
sizeof(T), addr, reinterpret_cast<intptr_t>(instr));
base::OS::Abort();
return 0;
}
template <typename T>
void Simulator::WriteMem(int32_t addr, T value, Instruction* instr) {
int alignment_mask = (1 << sizeof(T)) - 1;
if ((addr & alignment_mask) == 0 || IsMipsArchVariant(kMips32r6)) {
T* ptr = reinterpret_cast<T*>(addr);
*ptr = value;
TraceMemWr(addr, value);
return;
}
PrintF("Unaligned write of type sizeof(%d) at 0x%08x, pc=0x%08" V8PRIxPTR
"\n",
sizeof(T), addr, reinterpret_cast<intptr_t>(instr));
base::OS::Abort();
}
// Returns the limit of the stack area to enable checking for stack overflows.
uintptr_t Simulator::StackLimit(uintptr_t c_limit) const {
......@@ -4740,13 +4836,65 @@ void Simulator::DecodeTypeMsaMI10() {
DCHECK(IsMipsArchVariant(kMips32r6));
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
uint32_t opcode = instr_.InstructionBits() & kMsaMI10Mask;
int32_t s10 = (static_cast<int32_t>(instr_.MsaImmMI10Value()) << 22) >> 22;
int32_t rs = get_register(instr_.WsValue());
int32_t addr;
msa_reg_t wd;
#define MSA_MI10_LOAD(elem, num_of_lanes, T) \
for (int i = 0; i < num_of_lanes; ++i) { \
addr = rs + (s10 + i) * sizeof(T); \
wd.elem[i] = ReadMem<T>(addr, instr_.instr()); \
} \
set_msa_register(instr_.WdValue(), wd.elem);
#define MSA_MI10_STORE(elem, num_of_lanes, T) \
get_msa_register(instr_.WdValue(), wd.elem); \
for (int i = 0; i < num_of_lanes; ++i) { \
addr = rs + (s10 + i) * sizeof(T); \
WriteMem<T>(addr, wd.elem[i], instr_.instr()); \
}
if (opcode == MSA_LD) {
UNIMPLEMENTED();
switch (DecodeMsaDataFormat()) {
case MSA_BYTE:
MSA_MI10_LOAD(b, kMSALanesByte, int8_t);
break;
case MSA_HALF:
MSA_MI10_LOAD(h, kMSALanesHalf, int16_t);
break;
case MSA_WORD:
MSA_MI10_LOAD(w, kMSALanesWord, int32_t);
break;
case MSA_DWORD:
MSA_MI10_LOAD(d, kMSALanesDword, int64_t);
break;
default:
UNREACHABLE();
}
} else if (opcode == MSA_ST) {
UNIMPLEMENTED();
switch (DecodeMsaDataFormat()) {
case MSA_BYTE:
MSA_MI10_STORE(b, kMSALanesByte, int8_t);
break;
case MSA_HALF:
MSA_MI10_STORE(h, kMSALanesHalf, int16_t);
break;
case MSA_WORD:
MSA_MI10_STORE(w, kMSALanesWord, int32_t);
break;
case MSA_DWORD:
MSA_MI10_STORE(d, kMSALanesDword, int64_t);
break;
default:
UNREACHABLE();
}
} else {
UNREACHABLE();
}
#undef MSA_MI10_LOAD
#undef MSA_MI10_STORE
}
void Simulator::DecodeTypeMsa3R() {
......
......@@ -365,6 +365,12 @@ class Simulator {
inline double ReadD(int32_t addr, Instruction* instr);
inline void WriteD(int32_t addr, double value, Instruction* instr);
template <typename T>
T ReadMem(int32_t addr, Instruction* instr);
template <typename T>
void WriteMem(int32_t addr, T value, Instruction* instr);
void TraceRegWr(int32_t value, TraceType t = WORD);
void TraceRegWr(int64_t value, TraceType t = DWORD);
template <typename T>
......@@ -375,6 +381,10 @@ class Simulator {
void TraceMemRd(int32_t addr, int32_t value, TraceType t = WORD);
void TraceMemWr(int32_t addr, int64_t value, TraceType t = DWORD);
void TraceMemRd(int32_t addr, int64_t value, TraceType t = DWORD);
template <typename T>
void TraceMemRd(int32_t addr, T value);
template <typename T>
void TraceMemWr(int32_t addr, T value);
EmbeddedVector<char, 128> trace_buf_;
// Operations depending on endianness.
......
......@@ -1847,6 +1847,73 @@ void Simulator::TraceMemWr(int64_t addr, int64_t value, TraceType t) {
}
}
template <typename T>
void Simulator::TraceMemRd(int64_t addr, T value) {
if (::v8::internal::FLAG_trace_sim) {
switch (sizeof(T)) {
case 1:
SNPrintF(trace_buf_,
"%08" PRIx8 " <-- [%08" PRIx64 "] (%" PRIu64
") int8:%" PRId8 " uint8:%" PRIu8,
static_cast<uint8_t>(value), addr, icount_,
static_cast<int8_t>(value), static_cast<uint8_t>(value));
break;
case 2:
SNPrintF(trace_buf_,
"%08" PRIx16 " <-- [%08" PRIx64 "] (%" PRIu64
") int16:%" PRId16 " uint16:%" PRIu16,
static_cast<uint16_t>(value), addr, icount_,
static_cast<int16_t>(value), static_cast<uint16_t>(value));
break;
case 4:
SNPrintF(trace_buf_,
"%08" PRIx32 " <-- [%08" PRIx64 "] (%" PRIu64
") int32:%" PRId32 " uint32:%" PRIu32,
static_cast<uint32_t>(value), addr, icount_,
static_cast<int32_t>(value), static_cast<uint32_t>(value));
break;
case 8:
SNPrintF(trace_buf_,
"%08" PRIx64 " <-- [%08" PRIx64 "] (%" PRIu64
") int64:%" PRId64 " uint64:%" PRIu64,
static_cast<uint64_t>(value), addr, icount_,
static_cast<int64_t>(value), static_cast<uint64_t>(value));
break;
default:
UNREACHABLE();
}
}
}
template <typename T>
void Simulator::TraceMemWr(int64_t addr, T value) {
if (::v8::internal::FLAG_trace_sim) {
switch (sizeof(T)) {
case 1:
SNPrintF(trace_buf_,
" %02" PRIx8 " --> [%08" PRIx64 "] (%" PRIu64 ")",
static_cast<uint8_t>(value), addr, icount_);
break;
case 2:
SNPrintF(trace_buf_,
" %04" PRIx16 " --> [%08" PRIx64 "] (%" PRIu64 ")",
static_cast<uint16_t>(value), addr, icount_);
break;
case 4:
SNPrintF(trace_buf_,
"%08" PRIx32 " --> [%08" PRIx64 "] (%" PRIu64 ")",
static_cast<uint32_t>(value), addr, icount_);
break;
case 8:
SNPrintF(trace_buf_,
"%16" PRIx64 " --> [%08" PRIx64 "] (%" PRIu64 ")",
static_cast<uint64_t>(value), addr, icount_);
break;
default:
UNREACHABLE();
}
}
}
// TODO(plind): sign-extend and zero-extend not implmented properly
// on all the ReadXX functions, I don't think re-interpret cast does it.
......@@ -2058,6 +2125,35 @@ void Simulator::WriteB(int64_t addr, int8_t value) {
*ptr = value;
}
template <typename T>
T Simulator::ReadMem(int64_t addr, Instruction* instr) {
int alignment_mask = (1 << sizeof(T)) - 1;
if ((addr & alignment_mask) == 0 || kArchVariant == kMips64r6) {
T* ptr = reinterpret_cast<T*>(addr);
TraceMemRd(addr, *ptr);
return *ptr;
}
PrintF("Unaligned read of type sizeof(%ld) at 0x%08lx, pc=0x%08" V8PRIxPTR
"\n",
sizeof(T), addr, reinterpret_cast<intptr_t>(instr));
base::OS::Abort();
return 0;
}
template <typename T>
void Simulator::WriteMem(int64_t addr, T value, Instruction* instr) {
int alignment_mask = (1 << sizeof(T)) - 1;
if ((addr & alignment_mask) == 0 || kArchVariant == kMips64r6) {
T* ptr = reinterpret_cast<T*>(addr);
*ptr = value;
TraceMemWr(addr, value);
return;
}
PrintF("Unaligned write of type sizeof(%ld) at 0x%08lx, pc=0x%08" V8PRIxPTR
"\n",
sizeof(T), addr, reinterpret_cast<intptr_t>(instr));
base::OS::Abort();
}
// Returns the limit of the stack area to enable checking for stack overflows.
uintptr_t Simulator::StackLimit(uintptr_t c_limit) const {
......@@ -4965,13 +5061,65 @@ void Simulator::DecodeTypeMsaMI10() {
DCHECK(kArchVariant == kMips64r6);
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
uint32_t opcode = instr_.InstructionBits() & kMsaMI10Mask;
int64_t s10 = (static_cast<int64_t>(instr_.MsaImmMI10Value()) << 54) >> 54;
int64_t rs = get_register(instr_.WsValue());
int64_t addr;
msa_reg_t wd;
#define MSA_MI10_LOAD(elem, num_of_lanes, T) \
for (int i = 0; i < num_of_lanes; ++i) { \
addr = rs + (s10 + i) * sizeof(T); \
wd.elem[i] = ReadMem<T>(addr, instr_.instr()); \
} \
set_msa_register(instr_.WdValue(), wd.elem);
#define MSA_MI10_STORE(elem, num_of_lanes, T) \
get_msa_register(instr_.WdValue(), wd.elem); \
for (int i = 0; i < num_of_lanes; ++i) { \
addr = rs + (s10 + i) * sizeof(T); \
WriteMem<T>(addr, wd.elem[i], instr_.instr()); \
}
if (opcode == MSA_LD) {
UNIMPLEMENTED();
switch (DecodeMsaDataFormat()) {
case MSA_BYTE:
MSA_MI10_LOAD(b, kMSALanesByte, int8_t);
break;
case MSA_HALF:
MSA_MI10_LOAD(h, kMSALanesHalf, int16_t);
break;
case MSA_WORD:
MSA_MI10_LOAD(w, kMSALanesWord, int32_t);
break;
case MSA_DWORD:
MSA_MI10_LOAD(d, kMSALanesDword, int64_t);
break;
default:
UNREACHABLE();
}
} else if (opcode == MSA_ST) {
UNIMPLEMENTED();
switch (DecodeMsaDataFormat()) {
case MSA_BYTE:
MSA_MI10_STORE(b, kMSALanesByte, int8_t);
break;
case MSA_HALF:
MSA_MI10_STORE(h, kMSALanesHalf, int16_t);
break;
case MSA_WORD:
MSA_MI10_STORE(w, kMSALanesWord, int32_t);
break;
case MSA_DWORD:
MSA_MI10_STORE(d, kMSALanesDword, int64_t);
break;
default:
UNREACHABLE();
}
} else {
UNREACHABLE();
}
#undef MSA_MI10_LOAD
#undef MSA_MI10_STORE
}
void Simulator::DecodeTypeMsa3R() {
......
......@@ -386,6 +386,11 @@ class Simulator {
inline double ReadD(int64_t addr, Instruction* instr);
inline void WriteD(int64_t addr, double value, Instruction* instr);
template <typename T>
T ReadMem(int64_t addr, Instruction* instr);
template <typename T>
void WriteMem(int64_t addr, T value, Instruction* instr);
// Helper for debugging memory access.
inline void DieOrDebug();
......@@ -396,6 +401,10 @@ class Simulator {
void TraceMSARegWr(T* value);
void TraceMemWr(int64_t addr, int64_t value, TraceType t);
void TraceMemRd(int64_t addr, int64_t value, TraceType t = DWORD);
template <typename T>
void TraceMemRd(int64_t addr, T value);
template <typename T>
void TraceMemWr(int64_t addr, T value);
// Operations depending on endianness.
// Get Double Higher / Lower word.
......
......@@ -7577,4 +7577,76 @@ TEST(MSA_ldi) {
#undef LDI_DF
}
template <typename T, typename InstFunc>
void run_msa_mi10(InstFunc GenerateVectorInstructionFunc) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes);
CpuFeatureScope fscope(&assm, MIPS_SIMD);
T in_test_vector[1024];
T out_test_vector[1024];
T* in_array_middle = in_test_vector + arraysize(in_test_vector) / 2;
T* out_array_middle = out_test_vector + arraysize(out_test_vector) / 2;
v8::base::RandomNumberGenerator rand_gen(FLAG_random_seed);
for (unsigned int i = 0; i < arraysize(in_test_vector); i++) {
in_test_vector[i] = static_cast<T>(rand_gen.NextInt());
out_test_vector[i] = 0;
}
GenerateVectorInstructionFunc(assm);
__ 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
F4 f = FUNCTION_CAST<F4>(code->entry());
(CALL_GENERATED_CODE(isolate, f, in_array_middle, out_array_middle, 0, 0, 0));
CHECK_EQ(memcmp(in_test_vector, out_test_vector, arraysize(in_test_vector)),
0);
}
TEST(MSA_load_store_vector) {
if (!IsMipsArchVariant(kMips32r6) || !CpuFeatures::IsSupported(MIPS_SIMD))
return;
CcTest::InitializeVM();
run_msa_mi10<uint8_t>([](MacroAssembler& assm) {
for (int i = -512; i < 512; i += 16) {
__ ld_b(w0, MemOperand(a0, i));
__ st_b(w0, MemOperand(a1, i));
}
});
run_msa_mi10<uint16_t>([](MacroAssembler& assm) {
for (int i = -512; i < 512; i += 8) {
__ ld_h(w0, MemOperand(a0, i));
__ st_h(w0, MemOperand(a1, i));
}
});
run_msa_mi10<uint32_t>([](MacroAssembler& assm) {
for (int i = -512; i < 512; i += 4) {
__ ld_w(w0, MemOperand(a0, i));
__ st_w(w0, MemOperand(a1, i));
}
});
run_msa_mi10<uint64_t>([](MacroAssembler& assm) {
for (int i = -512; i < 512; i += 2) {
__ ld_d(w0, MemOperand(a0, i));
__ st_d(w0, MemOperand(a1, i));
}
});
#undef LDI_DF
}
#undef __
......@@ -8437,4 +8437,76 @@ TEST(MSA_ldi) {
#undef LDI_DF
}
template <typename T, typename InstFunc>
void run_msa_mi10(InstFunc GenerateVectorInstructionFunc) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes);
CpuFeatureScope fscope(&assm, MIPS_SIMD);
T in_test_vector[1024];
T out_test_vector[1024];
T* in_array_middle = in_test_vector + arraysize(in_test_vector) / 2;
T* out_array_middle = out_test_vector + arraysize(out_test_vector) / 2;
v8::base::RandomNumberGenerator rand_gen(FLAG_random_seed);
for (unsigned int i = 0; i < arraysize(in_test_vector); i++) {
in_test_vector[i] = static_cast<T>(rand_gen.NextInt());
out_test_vector[i] = 0;
}
GenerateVectorInstructionFunc(assm);
__ 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
F4 f = FUNCTION_CAST<F4>(code->entry());
(CALL_GENERATED_CODE(isolate, f, in_array_middle, out_array_middle, 0, 0, 0));
CHECK_EQ(memcmp(in_test_vector, out_test_vector, arraysize(in_test_vector)),
0);
}
TEST(MSA_load_store_vector) {
if ((kArchVariant != kMips64r6) || !CpuFeatures::IsSupported(MIPS_SIMD))
return;
CcTest::InitializeVM();
run_msa_mi10<uint8_t>([](MacroAssembler& assm) {
for (int i = -512; i < 512; i += 16) {
__ ld_b(w0, MemOperand(a0, i));
__ st_b(w0, MemOperand(a1, i));
}
});
run_msa_mi10<uint16_t>([](MacroAssembler& assm) {
for (int i = -512; i < 512; i += 8) {
__ ld_h(w0, MemOperand(a0, i));
__ st_h(w0, MemOperand(a1, i));
}
});
run_msa_mi10<uint32_t>([](MacroAssembler& assm) {
for (int i = -512; i < 512; i += 4) {
__ ld_w(w0, MemOperand(a0, i));
__ st_w(w0, MemOperand(a1, i));
}
});
run_msa_mi10<uint64_t>([](MacroAssembler& assm) {
for (int i = -512; i < 512; i += 2) {
__ ld_d(w0, MemOperand(a0, i));
__ st_d(w0, MemOperand(a1, i));
}
});
#undef LDI_DF
}
#undef __
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