MIPS[64]: Implement insert.df and I8 instructions in simulator

Add support for insert.df, andi.b, ori.b, nori.b, xori.b,
bmnzi.b, bmzi.b, bseli.b, shf.df MSA instructions in mips32
and mips64 simulator.

BUG=

Review-Url: https://codereview.chromium.org/2908753002
Cr-Commit-Position: refs/heads/master@{#45620}
This commit is contained in:
dusan.simicic 2017-05-31 02:34:46 -07:00 committed by Commit Bot
parent 69aa868bb7
commit f87271ccd0
8 changed files with 1122 additions and 76 deletions

View File

@ -161,6 +161,11 @@ const int kInvalidMSARegister = -1;
const int kInvalidMSAControlRegister = -1;
const int kMSAIRRegister = 0;
const int kMSACSRRegister = 1;
const int kMSARegSize = 128;
const int kMSALanesByte = kMSARegSize / 8;
const int kMSALanesHalf = kMSARegSize / 16;
const int kMSALanesWord = kMSARegSize / 32;
const int kMSALanesDword = kMSARegSize / 64;
// FPU (coprocessor 1) control registers. Currently only FCSR is implemented.
const int kFCSRRegister = 31;

View File

@ -1810,6 +1810,43 @@ void Simulator::TraceMSARegWr(T* value, TraceType t) {
}
}
template <typename T>
void Simulator::TraceMSARegWr(T* value) {
if (::v8::internal::FLAG_trace_sim) {
union {
uint8_t b[kMSALanesByte];
uint16_t h[kMSALanesHalf];
uint32_t w[kMSALanesWord];
uint64_t d[kMSALanesDword];
float f[kMSALanesWord];
double df[kMSALanesDword];
} v;
memcpy(v.b, value, kMSALanesByte);
if (std::is_same<T, int32_t>::value) {
SNPrintF(trace_buf_,
"LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64
") int32[0..3]:%" PRId32 " %" PRId32 " %" PRId32
" %" PRId32,
v.d[0], v.d[1], icount_, v.w[0], v.w[1], v.w[2], v.w[3]);
} else if (std::is_same<T, float>::value) {
SNPrintF(trace_buf_,
"LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64
") flt[0..3]:%e %e %e %e",
v.d[0], v.d[1], icount_, v.f[0], v.f[1], v.f[2], v.f[3]);
} else if (std::is_same<T, double>::value) {
SNPrintF(trace_buf_,
"LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64
") dbl[0..1]:%e %e",
v.d[0], v.d[1], icount_, v.df[0], v.df[1]);
} else {
SNPrintF(trace_buf_,
"LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64 ")",
v.d[0], v.d[1], icount_);
}
}
}
// TODO(plind): consider making icount_ printing a flag option.
void Simulator::TraceMemRd(int32_t addr, int32_t value, TraceType t) {
if (::v8::internal::FLAG_trace_sim) {
@ -4263,19 +4300,97 @@ void Simulator::DecodeTypeMsaI8() {
DCHECK(IsMipsArchVariant(kMips32r6));
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
uint32_t opcode = instr_.InstructionBits() & kMsaI8Mask;
int8_t i8 = instr_.MsaImm8Value();
msa_reg_t ws, wd;
switch (opcode) {
case ANDI_B:
get_msa_register(instr_.WsValue(), ws.b);
for (int i = 0; i < kMSALanesByte; i++) {
wd.b[i] = ws.b[i] & i8;
}
set_msa_register(instr_.WdValue(), wd.b);
TraceMSARegWr(wd.b);
break;
case ORI_B:
get_msa_register(instr_.WsValue(), ws.b);
for (int i = 0; i < kMSALanesByte; i++) {
wd.b[i] = ws.b[i] | i8;
}
set_msa_register(instr_.WdValue(), wd.b);
TraceMSARegWr(wd.b);
break;
case NORI_B:
get_msa_register(instr_.WsValue(), ws.b);
for (int i = 0; i < kMSALanesByte; i++) {
wd.b[i] = ~(ws.b[i] | i8);
}
set_msa_register(instr_.WdValue(), wd.b);
TraceMSARegWr(wd.b);
break;
case XORI_B:
get_msa_register(instr_.WsValue(), ws.b);
for (int i = 0; i < kMSALanesByte; i++) {
wd.b[i] = ws.b[i] ^ i8;
}
set_msa_register(instr_.WdValue(), wd.b);
TraceMSARegWr(wd.b);
break;
case BMNZI_B:
get_msa_register(instr_.WsValue(), ws.b);
get_msa_register(instr_.WdValue(), wd.b);
for (int i = 0; i < kMSALanesByte; i++) {
wd.b[i] = (ws.b[i] & i8) | (wd.b[i] & ~i8);
}
set_msa_register(instr_.WdValue(), wd.b);
TraceMSARegWr(wd.b);
break;
case BMZI_B:
get_msa_register(instr_.WsValue(), ws.b);
get_msa_register(instr_.WdValue(), wd.b);
for (int i = 0; i < kMSALanesByte; i++) {
wd.b[i] = (ws.b[i] & ~i8) | (wd.b[i] & i8);
}
set_msa_register(instr_.WdValue(), wd.b);
TraceMSARegWr(wd.b);
break;
case BSELI_B:
get_msa_register(instr_.WsValue(), ws.b);
get_msa_register(instr_.WdValue(), wd.b);
for (int i = 0; i < kMSALanesByte; i++) {
wd.b[i] = (ws.b[i] & ~wd.b[i]) | (wd.b[i] & i8);
}
set_msa_register(instr_.WdValue(), wd.b);
TraceMSARegWr(wd.b);
break;
case SHF_B:
get_msa_register(instr_.WsValue(), ws.b);
for (int i = 0; i < kMSALanesByte; i++) {
int j = i % 4;
int k = (i8 >> (2 * j)) & 0x3;
wd.b[i] = ws.b[i - j + k];
}
set_msa_register(instr_.WdValue(), wd.b);
TraceMSARegWr(wd.b);
break;
case SHF_H:
get_msa_register(instr_.WsValue(), ws.h);
for (int i = 0; i < kMSALanesHalf; i++) {
int j = i % 4;
int k = (i8 >> (2 * j)) & 0x3;
wd.h[i] = ws.h[i - j + k];
}
set_msa_register(instr_.WdValue(), wd.h);
TraceMSARegWr(wd.h);
break;
case SHF_W:
UNIMPLEMENTED();
get_msa_register(instr_.WsValue(), ws.w);
for (int i = 0; i < kMSALanesWord; i++) {
int j = (i8 >> (2 * i)) & 0x3;
wd.w[i] = ws.w[j];
}
set_msa_register(instr_.WdValue(), wd.w);
TraceMSARegWr(wd.w);
break;
default:
UNREACHABLE();
@ -4325,39 +4440,70 @@ void Simulator::DecodeTypeMsaELM() {
int32_t alu_out;
switch (opcode) {
case COPY_S:
case COPY_U:
case COPY_U: {
msa_reg_t ws;
switch (DecodeMsaDataFormat()) {
case MSA_BYTE: {
DCHECK(n < 16);
int8_t ws[16];
get_msa_register(instr_.WsValue(), ws);
alu_out = static_cast<int32_t>(ws[n]);
DCHECK(n < kMSALanesByte);
get_msa_register(instr_.WsValue(), ws.b);
alu_out = static_cast<int32_t>(ws.b[n]);
SetResult(wd_reg(), (opcode == COPY_U) ? alu_out & 0xFFu : alu_out);
break;
}
case MSA_HALF: {
DCHECK(n < 8);
int16_t ws[8];
get_msa_register(instr_.WsValue(), ws);
alu_out = static_cast<int32_t>(ws[n]);
DCHECK(n < kMSALanesHalf);
get_msa_register(instr_.WsValue(), ws.h);
alu_out = static_cast<int32_t>(ws.h[n]);
SetResult(wd_reg(), (opcode == COPY_U) ? alu_out & 0xFFFFu : alu_out);
break;
}
case MSA_WORD: {
DCHECK(n < 4);
int32_t ws[4];
get_msa_register(instr_.WsValue(), ws);
alu_out = static_cast<int32_t>(ws[n]);
DCHECK(n < kMSALanesWord);
get_msa_register(instr_.WsValue(), ws.w);
alu_out = static_cast<int32_t>(ws.w[n]);
SetResult(wd_reg(), alu_out);
break;
}
default:
UNREACHABLE();
}
break;
} break;
case INSERT: {
msa_reg_t wd;
switch (DecodeMsaDataFormat()) {
case MSA_BYTE: {
DCHECK(n < kMSALanesByte);
int32_t rs = get_register(instr_.WsValue());
get_msa_register(instr_.WdValue(), wd.b);
wd.b[n] = rs & 0xFFu;
set_msa_register(instr_.WdValue(), wd.b);
TraceMSARegWr(wd.b);
break;
}
case MSA_HALF: {
DCHECK(n < kMSALanesHalf);
int32_t rs = get_register(instr_.WsValue());
get_msa_register(instr_.WdValue(), wd.h);
wd.h[n] = rs & 0xFFFFu;
set_msa_register(instr_.WdValue(), wd.h);
TraceMSARegWr(wd.h);
break;
}
case MSA_WORD: {
DCHECK(n < kMSALanesWord);
int32_t rs = get_register(instr_.WsValue());
get_msa_register(instr_.WdValue(), wd.w);
wd.w[n] = rs;
set_msa_register(instr_.WdValue(), wd.w);
TraceMSARegWr(wd.w);
break;
}
default:
UNREACHABLE();
}
} break;
case SLDI:
case SPLATI:
case INSERT:
case INSVE:
UNIMPLEMENTED();
break;
@ -4555,37 +4701,35 @@ void Simulator::DecodeTypeMsa2R() {
DCHECK(IsMipsArchVariant(kMips32r6));
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
uint32_t opcode = instr_.InstructionBits() & kMsa2RMask;
msa_reg_t wd;
switch (opcode) {
case FILL:
switch (DecodeMsaDataFormat()) {
case MSA_BYTE: {
int8_t wd[16];
int32_t rs = get_register(instr_.WsValue());
for (int i = 0; i < 16; i++) {
wd[i] = rs & 0xFFu;
for (int i = 0; i < kMSALanesByte; i++) {
wd.b[i] = rs & 0xFFu;
}
set_msa_register(instr_.WdValue(), wd);
TraceMSARegWr(wd, BYTE);
set_msa_register(instr_.WdValue(), wd.b);
TraceMSARegWr(wd.b);
break;
}
case MSA_HALF: {
int16_t wd[8];
int32_t rs = get_register(instr_.WsValue());
for (int i = 0; i < 8; i++) {
wd[i] = rs & 0xFFFFu;
for (int i = 0; i < kMSALanesHalf; i++) {
wd.h[i] = rs & 0xFFFFu;
}
set_msa_register(instr_.WdValue(), wd);
TraceMSARegWr(wd, HALF);
set_msa_register(instr_.WdValue(), wd.h);
TraceMSARegWr(wd.h);
break;
}
case MSA_WORD: {
int32_t wd[4];
int32_t rs = get_register(instr_.WsValue());
for (int i = 0; i < 4; i++) {
wd[i] = rs;
for (int i = 0; i < kMSALanesWord; i++) {
wd.w[i] = rs;
}
set_msa_register(instr_.WdValue(), wd);
TraceMSARegWr(wd, WORD);
set_msa_register(instr_.WdValue(), wd.w);
TraceMSARegWr(wd.w);
break;
}
default:

View File

@ -336,6 +336,12 @@ class Simulator {
// MSA Data Format
enum MSADataFormat { MSA_VECT = 0, MSA_BYTE, MSA_HALF, MSA_WORD, MSA_DWORD };
typedef union {
int8_t b[kMSALanesByte];
int16_t h[kMSALanesHalf];
int32_t w[kMSALanesWord];
int64_t d[kMSALanesDword];
} msa_reg_t;
// Read and write memory.
inline uint32_t ReadBU(int32_t addr);
@ -359,6 +365,8 @@ class Simulator {
void TraceRegWr(int64_t value, TraceType t = DWORD);
template <typename T>
void TraceMSARegWr(T* value, TraceType t);
template <typename T>
void TraceMSARegWr(T* value);
void TraceMemWr(int32_t addr, int32_t value, TraceType t = WORD);
void TraceMemRd(int32_t addr, int32_t value, TraceType t = WORD);
void TraceMemWr(int32_t addr, int64_t value, TraceType t = DWORD);

View File

@ -122,6 +122,11 @@ const int kInvalidMSARegister = -1;
const int kInvalidMSAControlRegister = -1;
const int kMSAIRRegister = 0;
const int kMSACSRRegister = 1;
const int kMSARegSize = 128;
const int kMSALanesByte = kMSARegSize / 8;
const int kMSALanesHalf = kMSARegSize / 16;
const int kMSALanesWord = kMSARegSize / 32;
const int kMSALanesDword = kMSARegSize / 64;
// FPU (coprocessor 1) control registers. Currently only FCSR is implemented.
const int kFCSRRegister = 31;

View File

@ -1737,6 +1737,43 @@ void Simulator::TraceMSARegWr(T* value, TraceType t) {
}
}
template <typename T>
void Simulator::TraceMSARegWr(T* value) {
if (::v8::internal::FLAG_trace_sim) {
union {
uint8_t b[kMSALanesByte];
uint16_t h[kMSALanesHalf];
uint32_t w[kMSALanesWord];
uint64_t d[kMSALanesDword];
float f[kMSALanesWord];
double df[kMSALanesDword];
} v;
memcpy(v.b, value, kMSALanesByte);
if (std::is_same<T, int32_t>::value) {
SNPrintF(trace_buf_,
"LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64
") int32[0..3]:%" PRId32 " %" PRId32 " %" PRId32
" %" PRId32,
v.d[0], v.d[1], icount_, v.w[0], v.w[1], v.w[2], v.w[3]);
} else if (std::is_same<T, float>::value) {
SNPrintF(trace_buf_,
"LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64
") flt[0..3]:%e %e %e %e",
v.d[0], v.d[1], icount_, v.f[0], v.f[1], v.f[2], v.f[3]);
} else if (std::is_same<T, double>::value) {
SNPrintF(trace_buf_,
"LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64
") dbl[0..1]:%e %e",
v.d[0], v.d[1], icount_, v.df[0], v.df[1]);
} else {
SNPrintF(trace_buf_,
"LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64 ")",
v.d[0], v.d[1], icount_);
}
}
}
// TODO(plind): consider making icount_ printing a flag option.
void Simulator::TraceMemRd(int64_t addr, int64_t value, TraceType t) {
if (::v8::internal::FLAG_trace_sim) {
@ -4485,19 +4522,97 @@ void Simulator::DecodeTypeMsaI8() {
DCHECK(kArchVariant == kMips64r6);
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
uint32_t opcode = instr_.InstructionBits() & kMsaI8Mask;
int8_t i8 = instr_.MsaImm8Value();
msa_reg_t ws, wd;
switch (opcode) {
case ANDI_B:
get_msa_register(instr_.WsValue(), ws.b);
for (int i = 0; i < kMSALanesByte; i++) {
wd.b[i] = ws.b[i] & i8;
}
set_msa_register(instr_.WdValue(), wd.b);
TraceMSARegWr(wd.b);
break;
case ORI_B:
get_msa_register(instr_.WsValue(), ws.b);
for (int i = 0; i < kMSALanesByte; i++) {
wd.b[i] = ws.b[i] | i8;
}
set_msa_register(instr_.WdValue(), wd.b);
TraceMSARegWr(wd.b);
break;
case NORI_B:
get_msa_register(instr_.WsValue(), ws.b);
for (int i = 0; i < kMSALanesByte; i++) {
wd.b[i] = ~(ws.b[i] | i8);
}
set_msa_register(instr_.WdValue(), wd.b);
TraceMSARegWr(wd.b);
break;
case XORI_B:
get_msa_register(instr_.WsValue(), ws.b);
for (int i = 0; i < kMSALanesByte; i++) {
wd.b[i] = ws.b[i] ^ i8;
}
set_msa_register(instr_.WdValue(), wd.b);
TraceMSARegWr(wd.b);
break;
case BMNZI_B:
get_msa_register(instr_.WsValue(), ws.b);
get_msa_register(instr_.WdValue(), wd.b);
for (int i = 0; i < kMSALanesByte; i++) {
wd.b[i] = (ws.b[i] & i8) | (wd.b[i] & ~i8);
}
set_msa_register(instr_.WdValue(), wd.b);
TraceMSARegWr(wd.b);
break;
case BMZI_B:
get_msa_register(instr_.WsValue(), ws.b);
get_msa_register(instr_.WdValue(), wd.b);
for (int i = 0; i < kMSALanesByte; i++) {
wd.b[i] = (ws.b[i] & ~i8) | (wd.b[i] & i8);
}
set_msa_register(instr_.WdValue(), wd.b);
TraceMSARegWr(wd.b);
break;
case BSELI_B:
get_msa_register(instr_.WsValue(), ws.b);
get_msa_register(instr_.WdValue(), wd.b);
for (int i = 0; i < kMSALanesByte; i++) {
wd.b[i] = (ws.b[i] & ~wd.b[i]) | (wd.b[i] & i8);
}
set_msa_register(instr_.WdValue(), wd.b);
TraceMSARegWr(wd.b);
break;
case SHF_B:
get_msa_register(instr_.WsValue(), ws.b);
for (int i = 0; i < kMSALanesByte; i++) {
int j = i % 4;
int k = (i8 >> (2 * j)) & 0x3;
wd.b[i] = ws.b[i - j + k];
}
set_msa_register(instr_.WdValue(), wd.b);
TraceMSARegWr(wd.b);
break;
case SHF_H:
get_msa_register(instr_.WsValue(), ws.h);
for (int i = 0; i < kMSALanesHalf; i++) {
int j = i % 4;
int k = (i8 >> (2 * j)) & 0x3;
wd.h[i] = ws.h[i - j + k];
}
set_msa_register(instr_.WdValue(), wd.h);
TraceMSARegWr(wd.h);
break;
case SHF_W:
UNIMPLEMENTED();
get_msa_register(instr_.WsValue(), ws.w);
for (int i = 0; i < kMSALanesWord; i++) {
int j = (i8 >> (2 * i)) & 0x3;
wd.w[i] = ws.w[j];
}
set_msa_register(instr_.WdValue(), wd.w);
TraceMSARegWr(wd.w);
break;
default:
UNREACHABLE();
@ -4547,48 +4662,83 @@ void Simulator::DecodeTypeMsaELM() {
int64_t alu_out;
switch (opcode) {
case COPY_S:
case COPY_U:
case COPY_U: {
msa_reg_t ws;
switch (DecodeMsaDataFormat()) {
case MSA_BYTE: {
DCHECK(n < 16);
int8_t ws[16];
get_msa_register(instr_.WsValue(), ws);
alu_out = static_cast<int32_t>(ws[n]);
case MSA_BYTE:
DCHECK(n < kMSALanesByte);
get_msa_register(instr_.WsValue(), ws.b);
alu_out = static_cast<int32_t>(ws.b[n]);
SetResult(wd_reg(), (opcode == COPY_U) ? alu_out & 0xFFu : alu_out);
break;
}
case MSA_HALF: {
DCHECK(n < 8);
int16_t ws[8];
get_msa_register(instr_.WsValue(), ws);
alu_out = static_cast<int32_t>(ws[n]);
case MSA_HALF:
DCHECK(n < kMSALanesHalf);
get_msa_register(instr_.WsValue(), ws.h);
alu_out = static_cast<int32_t>(ws.h[n]);
SetResult(wd_reg(), (opcode == COPY_U) ? alu_out & 0xFFFFu : alu_out);
break;
}
case MSA_WORD: {
DCHECK(n < 4);
int32_t ws[4];
get_msa_register(instr_.WsValue(), ws);
alu_out = static_cast<int32_t>(ws[n]);
case MSA_WORD:
DCHECK(n < kMSALanesWord);
get_msa_register(instr_.WsValue(), ws.w);
alu_out = static_cast<int32_t>(ws.w[n]);
SetResult(wd_reg(),
(opcode == COPY_U) ? alu_out & 0xFFFFFFFFu : alu_out);
break;
case MSA_DWORD:
DCHECK(n < kMSALanesDword);
get_msa_register(instr_.WsValue(), ws.d);
alu_out = static_cast<int64_t>(ws.d[n]);
SetResult(wd_reg(), alu_out);
break;
default:
UNREACHABLE();
}
} break;
case INSERT: {
msa_reg_t wd;
switch (DecodeMsaDataFormat()) {
case MSA_BYTE: {
DCHECK(n < kMSALanesByte);
int64_t rs = get_register(instr_.WsValue());
get_msa_register(instr_.WdValue(), wd.b);
wd.b[n] = rs & 0xFFu;
set_msa_register(instr_.WdValue(), wd.b);
TraceMSARegWr(wd.b);
break;
}
case MSA_HALF: {
DCHECK(n < kMSALanesHalf);
int64_t rs = get_register(instr_.WsValue());
get_msa_register(instr_.WdValue(), wd.h);
wd.h[n] = rs & 0xFFFFu;
set_msa_register(instr_.WdValue(), wd.h);
TraceMSARegWr(wd.h);
break;
}
case MSA_WORD: {
DCHECK(n < kMSALanesWord);
int64_t rs = get_register(instr_.WsValue());
get_msa_register(instr_.WdValue(), wd.w);
wd.w[n] = rs & 0xFFFFFFFFu;
set_msa_register(instr_.WdValue(), wd.w);
TraceMSARegWr(wd.w);
break;
}
case MSA_DWORD: {
DCHECK(n < 2);
int64_t ws[2];
get_msa_register(instr_.WsValue(), ws);
alu_out = static_cast<int64_t>(ws[n]);
SetResult(wd_reg(), alu_out);
DCHECK(n < kMSALanesDword);
int64_t rs = get_register(instr_.WsValue());
get_msa_register(instr_.WdValue(), wd.d);
wd.d[n] = rs;
set_msa_register(instr_.WdValue(), wd.d);
TraceMSARegWr(wd.d);
break;
}
default:
UNREACHABLE();
}
break;
} break;
case SLDI:
case SPLATI:
case INSERT:
case INSVE:
UNIMPLEMENTED();
break;
@ -4786,45 +4936,42 @@ void Simulator::DecodeTypeMsa2R() {
DCHECK(kArchVariant == kMips64r6);
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
uint32_t opcode = instr_.InstructionBits() & kMsa2RMask;
msa_reg_t wd;
switch (opcode) {
case FILL:
switch (DecodeMsaDataFormat()) {
case MSA_BYTE: {
int8_t wd[16];
int64_t rs = get_register(instr_.WsValue());
for (int i = 0; i < 16; i++) {
wd[i] = rs & 0xFFu;
for (int i = 0; i < kMSALanesByte; i++) {
wd.b[i] = rs & 0xFFu;
}
set_msa_register(instr_.WdValue(), wd);
TraceMSARegWr(wd, BYTE);
set_msa_register(instr_.WdValue(), wd.b);
TraceMSARegWr(wd.b);
break;
}
case MSA_HALF: {
int16_t wd[8];
int64_t rs = get_register(instr_.WsValue());
for (int i = 0; i < 8; i++) {
wd[i] = rs & 0xFFFFu;
for (int i = 0; i < kMSALanesHalf; i++) {
wd.h[i] = rs & 0xFFFFu;
}
set_msa_register(instr_.WdValue(), wd);
TraceMSARegWr(wd, HALF);
set_msa_register(instr_.WdValue(), wd.h);
TraceMSARegWr(wd.h);
break;
}
case MSA_WORD: {
int32_t wd[4];
int64_t rs = get_register(instr_.WsValue());
for (int i = 0; i < 4; i++) {
wd[i] = rs & 0xFFFFFFFFu;
for (int i = 0; i < kMSALanesWord; i++) {
wd.w[i] = rs & 0xFFFFFFFFu;
}
set_msa_register(instr_.WdValue(), wd);
TraceMSARegWr(wd, WORD);
set_msa_register(instr_.WdValue(), wd.w);
TraceMSARegWr(wd.w);
break;
}
case MSA_DWORD: {
int64_t wd[2];
int64_t rs = get_register(instr_.WsValue());
wd[0] = wd[1] = rs;
set_msa_register(instr_.WdValue(), wd);
TraceMSARegWr(wd, DWORD);
wd.d[0] = wd.d[1] = rs;
set_msa_register(instr_.WdValue(), wd.d);
TraceMSARegWr(wd.d);
break;
}
default:

View File

@ -354,6 +354,12 @@ class Simulator {
// MSA Data Format
enum MSADataFormat { MSA_VECT = 0, MSA_BYTE, MSA_HALF, MSA_WORD, MSA_DWORD };
typedef union {
int8_t b[kMSALanesByte];
int16_t h[kMSALanesHalf];
int32_t w[kMSALanesWord];
int64_t d[kMSALanesDword];
} msa_reg_t;
// Read and write memory.
inline uint32_t ReadBU(int64_t addr);
@ -382,6 +388,8 @@ class Simulator {
void TraceRegWr(int64_t value, TraceType t = DWORD);
template <typename T>
void TraceMSARegWr(T* value, TraceType t);
template <typename T>
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);

View File

@ -5775,4 +5775,363 @@ TEST(MSA_fill_copy_3) {
CHECK_EQ(0x5555555555555555, t[1].d0);
}
typedef union {
uint8_t b[16];
uint16_t h[8];
uint32_t w[4];
uint64_t d[2];
} msa_reg_t;
template <typename T>
void run_msa_insert(int32_t rs_value, int n, msa_reg_t* w) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes);
CpuFeatureScope fscope(&assm, MIPS_SIMD);
__ li(t0, -1);
__ li(t1, rs_value);
__ fill_w(w0, t0);
if (std::is_same<T, int8_t>::value) {
DCHECK(n < 16);
__ insert_b(w0, n, t1);
} else if (std::is_same<T, int16_t>::value) {
DCHECK(n < 8);
__ insert_h(w0, n, t1);
} else if (std::is_same<T, int32_t>::value) {
DCHECK(n < 4);
__ insert_w(w0, n, t1);
} else {
UNREACHABLE();
}
__ copy_u_w(t2, w0, 0);
__ sw(t2, MemOperand(a0, 0));
__ copy_u_w(t2, w0, 1);
__ sw(t2, MemOperand(a0, 4));
__ copy_u_w(t2, w0, 2);
__ sw(t2, MemOperand(a0, 8));
__ copy_u_w(t2, w0, 3);
__ sw(t2, MemOperand(a0, 12));
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
#ifdef OBJECT_PRINT
code->Print(std::cout);
#endif
F3 f = FUNCTION_CAST<F3>(code->entry());
(CALL_GENERATED_CODE(isolate, f, w, 0, 0, 0, 0));
}
TEST(MSA_insert) {
if (!IsMipsArchVariant(kMips32r6) || !CpuFeatures::IsSupported(MIPS_SIMD))
return;
CcTest::InitializeVM();
struct TestCaseInsert {
uint32_t input;
int n;
uint64_t exp_res_lo;
uint64_t exp_res_hi;
};
struct TestCaseInsert tc_b[] = {
// input, n, exp_res_lo, exp_res_hi
{0xa2, 13, 0xffffffffffffffffu, 0xffffa2ffffffffffu},
{0x73, 10, 0xffffffffffffffffu, 0xffffffffff73ffffu},
{0x3494, 5, 0xffff94ffffffffffu, 0xffffffffffffffffu},
{0xa6b8, 1, 0xffffffffffffb8ffu, 0xffffffffffffffffu}};
for (size_t i = 0; i < sizeof(tc_b) / sizeof(TestCaseInsert); ++i) {
msa_reg_t res;
run_msa_insert<int8_t>(tc_b[i].input, tc_b[i].n, &res);
CHECK_EQ(tc_b[i].exp_res_lo, res.d[0]);
CHECK_EQ(tc_b[i].exp_res_hi, res.d[1]);
}
struct TestCaseInsert tc_h[] = {
// input, n, exp_res_lo, exp_res_hi
{0x85a2, 7, 0xffffffffffffffffu, 0x85a2ffffffffffffu},
{0xe873, 5, 0xffffffffffffffffu, 0xffffffffe873ffffu},
{0x3494, 3, 0x3494ffffffffffffu, 0xffffffffffffffffu},
{0xa6b8, 1, 0xffffffffa6b8ffffu, 0xffffffffffffffffu}};
for (size_t i = 0; i < sizeof(tc_h) / sizeof(TestCaseInsert); ++i) {
msa_reg_t res;
run_msa_insert<int16_t>(tc_h[i].input, tc_h[i].n, &res);
CHECK_EQ(tc_h[i].exp_res_lo, res.d[0]);
CHECK_EQ(tc_h[i].exp_res_hi, res.d[1]);
}
struct TestCaseInsert tc_w[] = {
// input, n, exp_res_lo, exp_res_hi
{0xd2f085a2u, 3, 0xffffffffffffffffu, 0xd2f085a2ffffffffu},
{0x4567e873u, 2, 0xffffffffffffffffu, 0xffffffff4567e873u},
{0xacdb3494u, 1, 0xacdb3494ffffffffu, 0xffffffffffffffffu},
{0x89aba6b8u, 0, 0xffffffff89aba6b8u, 0xffffffffffffffffu}};
for (size_t i = 0; i < sizeof(tc_w) / sizeof(TestCaseInsert); ++i) {
msa_reg_t res;
run_msa_insert<int32_t>(tc_w[i].input, tc_w[i].n, &res);
CHECK_EQ(tc_w[i].exp_res_lo, res.d[0]);
CHECK_EQ(tc_w[i].exp_res_hi, res.d[1]);
}
}
struct ExpResShf {
uint8_t i8;
uint64_t lo;
uint64_t hi;
};
void run_msa_i8(SecondaryField opcode, uint64_t ws_lo, uint64_t ws_hi,
uint8_t i8) {
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;
uint64_t wd_lo = 0xf35862e13e38f8b0;
uint64_t wd_hi = 0x4f41ffdef2bfe636;
#define LOAD_W_REG(lo, hi, w_reg) \
__ li(t0, static_cast<uint32_t>(lo & 0xffffffff)); \
__ li(t1, static_cast<uint32_t>((lo >> 32) & 0xffffffff)); \
__ insert_w(w_reg, 0, t0); \
__ insert_w(w_reg, 1, t1); \
__ li(t0, static_cast<uint32_t>(hi & 0xffffffff)); \
__ li(t1, static_cast<uint32_t>((hi >> 32) & 0xffffffff)); \
__ insert_w(w_reg, 2, t0); \
__ insert_w(w_reg, 3, t1);
LOAD_W_REG(ws_lo, ws_hi, w0)
switch (opcode) {
case ANDI_B:
__ andi_b(w2, w0, i8);
break;
case ORI_B:
__ ori_b(w2, w0, i8);
break;
case NORI_B:
__ nori_b(w2, w0, i8);
break;
case XORI_B:
__ xori_b(w2, w0, i8);
break;
case BMNZI_B:
LOAD_W_REG(wd_lo, wd_hi, w2);
__ bmnzi_b(w2, w0, i8);
break;
case BMZI_B:
LOAD_W_REG(wd_lo, wd_hi, w2);
__ bmzi_b(w2, w0, i8);
break;
case BSELI_B:
LOAD_W_REG(wd_lo, wd_hi, w2);
__ bseli_b(w2, w0, i8);
break;
case SHF_B:
__ shf_b(w2, w0, i8);
break;
case SHF_H:
__ shf_h(w2, w0, i8);
break;
case SHF_W:
__ shf_w(w2, w0, i8);
break;
default:
UNREACHABLE();
}
__ copy_u_w(t2, w2, 0);
__ sw(t2, MemOperand(a0, 0));
__ copy_u_w(t2, w2, 1);
__ sw(t2, MemOperand(a0, 4));
__ copy_u_w(t2, w2, 2);
__ sw(t2, MemOperand(a0, 8));
__ copy_u_w(t2, w2, 3);
__ sw(t2, MemOperand(a0, 12));
__ jr(ra);
__ nop();
#undef LOAD_W_REG
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
#ifdef OBJECT_PRINT
code->Print(std::cout);
#endif
F3 f = FUNCTION_CAST<F3>(code->entry());
(CALL_GENERATED_CODE(isolate, f, &res, 0, 0, 0, 0));
uint64_t mask = i8 * 0x0101010101010101ull;
switch (opcode) {
case ANDI_B:
CHECK_EQ(ws_lo & mask, res.d[0]);
CHECK_EQ(ws_hi & mask, res.d[1]);
break;
case ORI_B:
CHECK_EQ(ws_lo | mask, res.d[0]);
CHECK_EQ(ws_hi | mask, res.d[1]);
break;
case NORI_B:
CHECK_EQ(~(ws_lo | mask), res.d[0]);
CHECK_EQ(~(ws_hi | mask), res.d[1]);
break;
case XORI_B:
CHECK_EQ(ws_lo ^ mask, res.d[0]);
CHECK_EQ(ws_hi ^ mask, res.d[1]);
break;
case BMNZI_B:
CHECK_EQ((ws_lo & mask) | (wd_lo & ~mask), res.d[0]);
CHECK_EQ((ws_hi & mask) | (wd_hi & ~mask), res.d[1]);
break;
case BMZI_B:
CHECK_EQ((ws_lo & ~mask) | (wd_lo & mask), res.d[0]);
CHECK_EQ((ws_hi & ~mask) | (wd_hi & mask), res.d[1]);
break;
case BSELI_B:
CHECK_EQ((ws_lo & ~wd_lo) | (mask & wd_lo), res.d[0]);
CHECK_EQ((ws_hi & ~wd_hi) | (mask & wd_hi), res.d[1]);
break;
case SHF_B: {
struct ExpResShf exp_b[] = {
// i8, exp_lo, exp_hi
{0xffu, 0x11111111b9b9b9b9, 0xf7f7f7f7c8c8c8c8},
{0x0u, 0x62626262dfdfdfdf, 0xd6d6d6d6c8c8c8c8},
{0xe4u, 0xf35862e13e38f8b0, 0x4f41ffdef2bfe636},
{0x1bu, 0x1b756911c3d9a7b9, 0xae94a5f79c8aefc8},
{0xb1u, 0x662b6253e8c4df12, 0x0d3ad6803f8bc88b},
{0x4eu, 0x62e1f358f8b03e38, 0xffde4f41e636f2bf},
{0x27u, 0x1b697511c3a7d9b9, 0xaea594f79cef8ac8}};
for (size_t i = 0; i < sizeof(exp_b) / sizeof(ExpResShf); ++i) {
if (exp_b[i].i8 == i8) {
CHECK_EQ(exp_b[i].lo, res.d[0]);
CHECK_EQ(exp_b[i].hi, res.d[1]);
}
}
} break;
case SHF_H: {
struct ExpResShf exp_h[] = {
// i8, exp_lo, exp_hi
{0xffu, 0x1169116911691169, 0xf7a5f7a5f7a5f7a5},
{0x0u, 0x12df12df12df12df, 0x8bc88bc88bc88bc8},
{0xe4u, 0xf35862e13e38f8b0, 0x4f41ffdef2bfe636},
{0x1bu, 0xd9c3b9a7751b1169, 0x8a9cc8ef94aef7a5},
{0xb1u, 0x53622b6612dfc4e8, 0x80d63a0d8bc88b3f},
{0x4eu, 0x3e38f8b0f35862e1, 0xf2bfe6364f41ffde},
{0x27u, 0xd9c3751bb9a71169, 0x8a9c94aec8eff7a5}};
for (size_t i = 0; i < sizeof(exp_h) / sizeof(ExpResShf); ++i) {
if (exp_h[i].i8 == i8) {
CHECK_EQ(exp_h[i].lo, res.d[0]);
CHECK_EQ(exp_h[i].hi, res.d[1]);
}
}
} break;
case SHF_W: {
struct ExpResShf exp_w[] = {
// i8, exp_lo, exp_hi
{0xffu, 0xf7a594aef7a594ae, 0xf7a594aef7a594ae},
{0x0u, 0xc4e812dfc4e812df, 0xc4e812dfc4e812df},
{0xe4u, 0xf35862e13e38f8b0, 0x4f41ffdef2bfe636},
{0x1bu, 0xc8ef8a9cf7a594ae, 0xb9a7d9c31169751b},
{0xb1u, 0xc4e812df2b665362, 0x8b3f8bc83a0d80d6},
{0x4eu, 0x4f41ffdef2bfe636, 0xf35862e13e38f8b0},
{0x27u, 0x1169751bf7a594ae, 0xb9a7d9c3c8ef8a9c}};
for (size_t i = 0; i < sizeof(exp_w) / sizeof(ExpResShf); ++i) {
if (exp_w[i].i8 == i8) {
CHECK_EQ(exp_w[i].lo, res.d[0]);
CHECK_EQ(exp_w[i].hi, res.d[1]);
}
}
} break;
default:
UNREACHABLE();
}
}
struct TestCaseMsaI8 {
uint64_t input_lo;
uint64_t input_hi;
uint8_t i8;
};
TEST(MSA_andi_ori_nori_xori) {
if (!IsMipsArchVariant(kMips32r6) || !CpuFeatures::IsSupported(MIPS_SIMD))
return;
CcTest::InitializeVM();
struct TestCaseMsaI8 tc[] = {// input_lo, input_hi, i8
{0x1169751bb9a7d9c3, 0xf7a594aec8ef8a9c, 0xffu},
{0x2b665362c4e812df, 0x3a0d80d68b3f8bc8, 0x0u},
{0x1169751bb9a7d9c3, 0xf7a594aec8ef8a9c, 0x3bu},
{0x2b665362c4e812df, 0x3a0d80d68b3f8bc8, 0xd9u}};
for (size_t i = 0; i < sizeof(tc) / sizeof(TestCaseMsaI8); ++i) {
run_msa_i8(ANDI_B, tc[i].input_lo, tc[i].input_hi, tc[i].i8);
run_msa_i8(ORI_B, tc[i].input_lo, tc[i].input_hi, tc[i].i8);
run_msa_i8(NORI_B, tc[i].input_lo, tc[i].input_hi, tc[i].i8);
run_msa_i8(XORI_B, tc[i].input_lo, tc[i].input_hi, tc[i].i8);
}
}
TEST(MSA_bmnzi_bmzi_bseli) {
if (!IsMipsArchVariant(kMips32r6) || !CpuFeatures::IsSupported(MIPS_SIMD))
return;
CcTest::InitializeVM();
struct TestCaseMsaI8 tc[] = {// input_lo, input_hi, i8
{0x1169751bb9a7d9c3, 0xf7a594aec8ef8a9c, 0xffu},
{0x2b665362c4e812df, 0x3a0d80d68b3f8bc8, 0x0u},
{0x1169751bb9a7d9c3, 0xf7a594aec8ef8a9c, 0x3bu},
{0x2b665362c4e812df, 0x3a0d80d68b3f8bc8, 0xd9u}};
for (size_t i = 0; i < sizeof(tc) / sizeof(TestCaseMsaI8); ++i) {
run_msa_i8(BMNZI_B, tc[i].input_lo, tc[i].input_hi, tc[i].i8);
run_msa_i8(BMZI_B, tc[i].input_lo, tc[i].input_hi, tc[i].i8);
run_msa_i8(BSELI_B, tc[i].input_lo, tc[i].input_hi, tc[i].i8);
}
}
TEST(MSA_shf) {
if (!IsMipsArchVariant(kMips32r6) || !CpuFeatures::IsSupported(MIPS_SIMD))
return;
CcTest::InitializeVM();
struct TestCaseMsaI8 tc[] = {
// input_lo, input_hi, i8
{0x1169751bb9a7d9c3, 0xf7a594aec8ef8a9c, 0xffu}, // 3333
{0x2b665362c4e812df, 0x3a0d80d68b3f8bc8, 0x0u}, // 0000
{0xf35862e13e38f8b0, 0x4f41ffdef2bfe636, 0xe4u}, // 3210
{0x1169751bb9a7d9c3, 0xf7a594aec8ef8a9c, 0x1bu}, // 0123
{0x2b665362c4e812df, 0x3a0d80d68b3f8bc8, 0xb1u}, // 2301
{0xf35862e13e38f8b0, 0x4f41ffdef2bfe636, 0x4eu}, // 1032
{0x1169751bb9a7d9c3, 0xf7a594aec8ef8a9c, 0x27u} // 0213
};
for (size_t i = 0; i < sizeof(tc) / sizeof(TestCaseMsaI8); ++i) {
run_msa_i8(SHF_B, tc[i].input_lo, tc[i].input_hi, tc[i].i8);
run_msa_i8(SHF_H, tc[i].input_lo, tc[i].input_hi, tc[i].i8);
run_msa_i8(SHF_W, tc[i].input_lo, tc[i].input_hi, tc[i].i8);
}
}
#undef __

View File

@ -6591,4 +6591,374 @@ TEST(MSA_fill_copy_3) {
CHECK_EQ(0x5555555555555555, t[1].d0);
}
typedef union {
uint8_t b[16];
uint16_t h[8];
uint32_t w[4];
uint64_t d[2];
} msa_reg_t;
template <typename T>
void run_msa_insert(int64_t rs_value, int n, msa_reg_t* w) {
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes);
CpuFeatureScope fscope(&assm, MIPS_SIMD);
__ li(t0, -1);
__ li(t1, rs_value);
__ fill_w(w0, t0);
if (std::is_same<T, int8_t>::value) {
DCHECK(n < 16);
__ insert_b(w0, n, t1);
} else if (std::is_same<T, int16_t>::value) {
DCHECK(n < 8);
__ insert_h(w0, n, t1);
} else if (std::is_same<T, int32_t>::value) {
DCHECK(n < 4);
__ insert_w(w0, n, t1);
} else if (std::is_same<T, int64_t>::value) {
DCHECK(n < 2);
__ insert_d(w0, n, t1);
} else {
UNREACHABLE();
}
__ copy_u_w(t2, w0, 0);
__ sw(t2, MemOperand(a0, 0));
__ copy_u_w(t2, w0, 1);
__ sw(t2, MemOperand(a0, 4));
__ copy_u_w(t2, w0, 2);
__ sw(t2, MemOperand(a0, 8));
__ copy_u_w(t2, w0, 3);
__ sw(t2, MemOperand(a0, 12));
__ jr(ra);
__ nop();
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
#ifdef OBJECT_PRINT
code->Print(std::cout);
#endif
F3 f = FUNCTION_CAST<F3>(code->entry());
(CALL_GENERATED_CODE(isolate, f, w, 0, 0, 0, 0));
}
TEST(MSA_insert) {
if ((kArchVariant != kMips64r6) || !CpuFeatures::IsSupported(MIPS_SIMD))
return;
CcTest::InitializeVM();
struct TestCaseInsert {
uint64_t input;
int n;
uint64_t exp_res_lo;
uint64_t exp_res_hi;
};
struct TestCaseInsert tc_b[] = {
// input, n, exp_res_lo, exp_res_hi
{0xa2, 13, 0xffffffffffffffffu, 0xffffa2ffffffffffu},
{0x73, 10, 0xffffffffffffffffu, 0xffffffffff73ffffu},
{0x3494, 5, 0xffff94ffffffffffu, 0xffffffffffffffffu},
{0xa6b8, 1, 0xffffffffffffb8ffu, 0xffffffffffffffffu}};
for (size_t i = 0; i < sizeof(tc_b) / sizeof(TestCaseInsert); ++i) {
msa_reg_t res;
run_msa_insert<int8_t>(tc_b[i].input, tc_b[i].n, &res);
CHECK_EQ(tc_b[i].exp_res_lo, res.d[0]);
CHECK_EQ(tc_b[i].exp_res_hi, res.d[1]);
}
struct TestCaseInsert tc_h[] = {
// input, n, exp_res_lo, exp_res_hi
{0x85a2, 7, 0xffffffffffffffffu, 0x85a2ffffffffffffu},
{0xe873, 5, 0xffffffffffffffffu, 0xffffffffe873ffffu},
{0x3494, 3, 0x3494ffffffffffffu, 0xffffffffffffffffu},
{0xa6b8, 1, 0xffffffffa6b8ffffu, 0xffffffffffffffffu}};
for (size_t i = 0; i < sizeof(tc_h) / sizeof(TestCaseInsert); ++i) {
msa_reg_t res;
run_msa_insert<int16_t>(tc_h[i].input, tc_h[i].n, &res);
CHECK_EQ(tc_h[i].exp_res_lo, res.d[0]);
CHECK_EQ(tc_h[i].exp_res_hi, res.d[1]);
}
struct TestCaseInsert tc_w[] = {
// input, n, exp_res_lo, exp_res_hi
{0xd2f085a2u, 3, 0xffffffffffffffffu, 0xd2f085a2ffffffffu},
{0x4567e873u, 2, 0xffffffffffffffffu, 0xffffffff4567e873u},
{0xacdb3494u, 1, 0xacdb3494ffffffffu, 0xffffffffffffffffu},
{0x89aba6b8u, 0, 0xffffffff89aba6b8u, 0xffffffffffffffffu}};
for (size_t i = 0; i < sizeof(tc_w) / sizeof(TestCaseInsert); ++i) {
msa_reg_t res;
run_msa_insert<int32_t>(tc_w[i].input, tc_w[i].n, &res);
CHECK_EQ(tc_w[i].exp_res_lo, res.d[0]);
CHECK_EQ(tc_w[i].exp_res_hi, res.d[1]);
}
struct TestCaseInsert tc_d[] = {
// input, n, exp_res_lo, exp_res_hi
{0xf35862e13e38f8b0, 1, 0xffffffffffffffffu, 0xf35862e13e38f8b0},
{0x4f41ffdef2bfe636, 0, 0x4f41ffdef2bfe636, 0xffffffffffffffffu}};
for (size_t i = 0; i < sizeof(tc_d) / sizeof(TestCaseInsert); ++i) {
msa_reg_t res;
run_msa_insert<int64_t>(tc_d[i].input, tc_d[i].n, &res);
CHECK_EQ(tc_d[i].exp_res_lo, res.d[0]);
CHECK_EQ(tc_d[i].exp_res_hi, res.d[1]);
}
}
struct ExpResShf {
uint8_t i8;
uint64_t lo;
uint64_t hi;
};
void run_msa_i8(SecondaryField opcode, uint64_t ws_lo, uint64_t ws_hi,
uint8_t i8) {
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;
uint64_t wd_lo = 0xf35862e13e38f8b0;
uint64_t wd_hi = 0x4f41ffdef2bfe636;
#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(ws_lo, ws_hi, w0)
switch (opcode) {
case ANDI_B:
__ andi_b(w2, w0, i8);
break;
case ORI_B:
__ ori_b(w2, w0, i8);
break;
case NORI_B:
__ nori_b(w2, w0, i8);
break;
case XORI_B:
__ xori_b(w2, w0, i8);
break;
case BMNZI_B:
LOAD_W_REG(wd_lo, wd_hi, w2);
__ bmnzi_b(w2, w0, i8);
break;
case BMZI_B:
LOAD_W_REG(wd_lo, wd_hi, w2);
__ bmzi_b(w2, w0, i8);
break;
case BSELI_B:
LOAD_W_REG(wd_lo, wd_hi, w2);
__ bseli_b(w2, w0, i8);
break;
case SHF_B:
__ shf_b(w2, w0, i8);
break;
case SHF_H:
__ shf_h(w2, w0, i8);
break;
case SHF_W:
__ shf_w(w2, w0, i8);
break;
default:
UNREACHABLE();
}
__ copy_u_w(t2, w2, 0);
__ sw(t2, MemOperand(a0, 0));
__ copy_u_w(t2, w2, 1);
__ sw(t2, MemOperand(a0, 4));
__ copy_u_w(t2, w2, 2);
__ sw(t2, MemOperand(a0, 8));
__ copy_u_w(t2, w2, 3);
__ sw(t2, MemOperand(a0, 12));
__ jr(ra);
__ nop();
#undef LOAD_W_REG
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
#ifdef OBJECT_PRINT
code->Print(std::cout);
#endif
F3 f = FUNCTION_CAST<F3>(code->entry());
(CALL_GENERATED_CODE(isolate, f, &res, 0, 0, 0, 0));
uint64_t mask = i8 * 0x0101010101010101ull;
switch (opcode) {
case ANDI_B:
CHECK_EQ(ws_lo & mask, res.d[0]);
CHECK_EQ(ws_hi & mask, res.d[1]);
break;
case ORI_B:
CHECK_EQ(ws_lo | mask, res.d[0]);
CHECK_EQ(ws_hi | mask, res.d[1]);
break;
case NORI_B:
CHECK_EQ(~(ws_lo | mask), res.d[0]);
CHECK_EQ(~(ws_hi | mask), res.d[1]);
break;
case XORI_B:
CHECK_EQ(ws_lo ^ mask, res.d[0]);
CHECK_EQ(ws_hi ^ mask, res.d[1]);
break;
case BMNZI_B:
CHECK_EQ((ws_lo & mask) | (wd_lo & ~mask), res.d[0]);
CHECK_EQ((ws_hi & mask) | (wd_hi & ~mask), res.d[1]);
break;
case BMZI_B:
CHECK_EQ((ws_lo & ~mask) | (wd_lo & mask), res.d[0]);
CHECK_EQ((ws_hi & ~mask) | (wd_hi & mask), res.d[1]);
break;
case BSELI_B:
CHECK_EQ((ws_lo & ~wd_lo) | (mask & wd_lo), res.d[0]);
CHECK_EQ((ws_hi & ~wd_hi) | (mask & wd_hi), res.d[1]);
break;
case SHF_B: {
struct ExpResShf exp_b[] = {
// i8, exp_lo, exp_hi
{0xffu, 0x11111111b9b9b9b9, 0xf7f7f7f7c8c8c8c8},
{0x0u, 0x62626262dfdfdfdf, 0xd6d6d6d6c8c8c8c8},
{0xe4u, 0xf35862e13e38f8b0, 0x4f41ffdef2bfe636},
{0x1bu, 0x1b756911c3d9a7b9, 0xae94a5f79c8aefc8},
{0xb1u, 0x662b6253e8c4df12, 0x0d3ad6803f8bc88b},
{0x4eu, 0x62e1f358f8b03e38, 0xffde4f41e636f2bf},
{0x27u, 0x1b697511c3a7d9b9, 0xaea594f79cef8ac8}};
for (size_t i = 0; i < sizeof(exp_b) / sizeof(ExpResShf); ++i) {
if (exp_b[i].i8 == i8) {
CHECK_EQ(exp_b[i].lo, res.d[0]);
CHECK_EQ(exp_b[i].hi, res.d[1]);
}
}
} break;
case SHF_H: {
struct ExpResShf exp_h[] = {
// i8, exp_lo, exp_hi
{0xffu, 0x1169116911691169, 0xf7a5f7a5f7a5f7a5},
{0x0u, 0x12df12df12df12df, 0x8bc88bc88bc88bc8},
{0xe4u, 0xf35862e13e38f8b0, 0x4f41ffdef2bfe636},
{0x1bu, 0xd9c3b9a7751b1169, 0x8a9cc8ef94aef7a5},
{0xb1u, 0x53622b6612dfc4e8, 0x80d63a0d8bc88b3f},
{0x4eu, 0x3e38f8b0f35862e1, 0xf2bfe6364f41ffde},
{0x27u, 0xd9c3751bb9a71169, 0x8a9c94aec8eff7a5}};
for (size_t i = 0; i < sizeof(exp_h) / sizeof(ExpResShf); ++i) {
if (exp_h[i].i8 == i8) {
CHECK_EQ(exp_h[i].lo, res.d[0]);
CHECK_EQ(exp_h[i].hi, res.d[1]);
}
}
} break;
case SHF_W: {
struct ExpResShf exp_w[] = {
// i8, exp_lo, exp_hi
{0xffu, 0xf7a594aef7a594ae, 0xf7a594aef7a594ae},
{0x0u, 0xc4e812dfc4e812df, 0xc4e812dfc4e812df},
{0xe4u, 0xf35862e13e38f8b0, 0x4f41ffdef2bfe636},
{0x1bu, 0xc8ef8a9cf7a594ae, 0xb9a7d9c31169751b},
{0xb1u, 0xc4e812df2b665362, 0x8b3f8bc83a0d80d6},
{0x4eu, 0x4f41ffdef2bfe636, 0xf35862e13e38f8b0},
{0x27u, 0x1169751bf7a594ae, 0xb9a7d9c3c8ef8a9c}};
for (size_t i = 0; i < sizeof(exp_w) / sizeof(ExpResShf); ++i) {
if (exp_w[i].i8 == i8) {
CHECK_EQ(exp_w[i].lo, res.d[0]);
CHECK_EQ(exp_w[i].hi, res.d[1]);
}
}
} break;
default:
UNREACHABLE();
}
}
struct TestCaseMsaI8 {
uint64_t input_lo;
uint64_t input_hi;
uint8_t i8;
};
TEST(MSA_andi_ori_nori_xori) {
if ((kArchVariant != kMips64r6) || !CpuFeatures::IsSupported(MIPS_SIMD))
return;
CcTest::InitializeVM();
struct TestCaseMsaI8 tc[] = {// input_lo, input_hi, i8
{0x1169751bb9a7d9c3, 0xf7a594aec8ef8a9c, 0xffu},
{0x2b665362c4e812df, 0x3a0d80d68b3f8bc8, 0x0u},
{0x1169751bb9a7d9c3, 0xf7a594aec8ef8a9c, 0x3bu},
{0x2b665362c4e812df, 0x3a0d80d68b3f8bc8, 0xd9u}};
for (size_t i = 0; i < sizeof(tc) / sizeof(TestCaseMsaI8); ++i) {
run_msa_i8(ANDI_B, tc[i].input_lo, tc[i].input_hi, tc[i].i8);
run_msa_i8(ORI_B, tc[i].input_lo, tc[i].input_hi, tc[i].i8);
run_msa_i8(NORI_B, tc[i].input_lo, tc[i].input_hi, tc[i].i8);
run_msa_i8(XORI_B, tc[i].input_lo, tc[i].input_hi, tc[i].i8);
}
}
TEST(MSA_bmnzi_bmzi_bseli) {
if ((kArchVariant != kMips64r6) || !CpuFeatures::IsSupported(MIPS_SIMD))
return;
CcTest::InitializeVM();
struct TestCaseMsaI8 tc[] = {// input_lo, input_hi, i8
{0x1169751bb9a7d9c3, 0xf7a594aec8ef8a9c, 0xffu},
{0x2b665362c4e812df, 0x3a0d80d68b3f8bc8, 0x0u},
{0x1169751bb9a7d9c3, 0xf7a594aec8ef8a9c, 0x3bu},
{0x2b665362c4e812df, 0x3a0d80d68b3f8bc8, 0xd9u}};
for (size_t i = 0; i < sizeof(tc) / sizeof(TestCaseMsaI8); ++i) {
run_msa_i8(BMNZI_B, tc[i].input_lo, tc[i].input_hi, tc[i].i8);
run_msa_i8(BMZI_B, tc[i].input_lo, tc[i].input_hi, tc[i].i8);
run_msa_i8(BSELI_B, tc[i].input_lo, tc[i].input_hi, tc[i].i8);
}
}
TEST(MSA_shf) {
if ((kArchVariant != kMips64r6) || !CpuFeatures::IsSupported(MIPS_SIMD))
return;
CcTest::InitializeVM();
struct TestCaseMsaI8 tc[] = {
// input_lo, input_hi, i8
{0x1169751bb9a7d9c3, 0xf7a594aec8ef8a9c, 0xffu}, // 3333
{0x2b665362c4e812df, 0x3a0d80d68b3f8bc8, 0x0u}, // 0000
{0xf35862e13e38f8b0, 0x4f41ffdef2bfe636, 0xe4u}, // 3210
{0x1169751bb9a7d9c3, 0xf7a594aec8ef8a9c, 0x1bu}, // 0123
{0x2b665362c4e812df, 0x3a0d80d68b3f8bc8, 0xb1u}, // 2301
{0xf35862e13e38f8b0, 0x4f41ffdef2bfe636, 0x4eu}, // 1032
{0x1169751bb9a7d9c3, 0xf7a594aec8ef8a9c, 0x27u} // 0213
};
for (size_t i = 0; i < sizeof(tc) / sizeof(TestCaseMsaI8); ++i) {
run_msa_i8(SHF_B, tc[i].input_lo, tc[i].input_hi, tc[i].i8);
run_msa_i8(SHF_H, tc[i].input_lo, tc[i].input_hi, tc[i].i8);
run_msa_i8(SHF_W, tc[i].input_lo, tc[i].input_hi, tc[i].i8);
}
}
#undef __