Commit 6d9025ef authored by Dusan Simicic's avatar Dusan Simicic Committed by Commit Bot

MIPS[64]: Implement MSA Bit instructions in simulator

Add support for slli, srai, srli, bclri, bseti, bnegi, binsli, binsri,
sat_s, sat_u, srari, srlri MSA instructions in mips32 and mips64
simulators.

Bug: 
Change-Id: I1a351a23c733f0bfbc829f25874df26295327afc
Reviewed-on: https://chromium-review.googlesource.com/568020Reviewed-by: 's avatarIvica Bogosavljevic <ivica.bogosavljevic@imgtec.com>
Commit-Queue: Ivica Bogosavljevic <ivica.bogosavljevic@imgtec.com>
Cr-Commit-Position: refs/heads/master@{#46764}
parent 176a2b24
......@@ -4583,25 +4583,127 @@ void Simulator::DecodeTypeMsaELM() {
}
}
void Simulator::DecodeTypeMsaBIT() {
DCHECK(IsMipsArchVariant(kMips32r6));
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
uint32_t opcode = instr_.InstructionBits() & kMsaBITMask;
template <typename T>
T Simulator::MsaBitInstrHelper(uint32_t opcode, T wd, T ws, int32_t m) {
typedef typename std::make_unsigned<T>::type uT;
T res;
switch (opcode) {
case SLLI:
res = static_cast<T>(ws << m);
break;
case SRAI:
res = static_cast<T>(ArithmeticShiftRight(ws, m));
break;
case SRLI:
res = static_cast<T>(static_cast<uT>(ws) >> m);
break;
case BCLRI:
res = static_cast<T>(static_cast<T>(~(1ull << m)) & ws);
break;
case BSETI:
res = static_cast<T>(static_cast<T>(1ull << m) | ws);
break;
case BNEGI:
case BINSLI:
case BINSRI:
case SAT_S:
case SAT_U:
res = static_cast<T>(static_cast<T>(1ull << m) ^ ws);
break;
case BINSLI: {
int elem_size = 8 * sizeof(T);
int bits = m + 1;
if (bits == elem_size) {
res = static_cast<T>(ws);
} else {
uint64_t mask = ((1ull << bits) - 1) << (elem_size - bits);
res = static_cast<T>((static_cast<T>(mask) & ws) |
(static_cast<T>(~mask) & wd));
}
} break;
case BINSRI: {
int elem_size = 8 * sizeof(T);
int bits = m + 1;
if (bits == elem_size) {
res = static_cast<T>(ws);
} else {
uint64_t mask = (1ull << bits) - 1;
res = static_cast<T>((static_cast<T>(mask) & ws) |
(static_cast<T>(~mask) & wd));
}
} break;
case SAT_S: {
#define M_MAX_INT(x) static_cast<int64_t>((1LL << ((x)-1)) - 1)
#define M_MIN_INT(x) static_cast<int64_t>(-(1LL << ((x)-1)))
int shift = 64 - 8 * sizeof(T);
int64_t ws_i64 = (static_cast<int64_t>(ws) << shift) >> shift;
res = static_cast<T>(ws_i64 < M_MIN_INT(m + 1)
? M_MIN_INT(m + 1)
: ws_i64 > M_MAX_INT(m + 1) ? M_MAX_INT(m + 1)
: ws_i64);
#undef M_MAX_INT
#undef M_MIN_INT
} break;
case SAT_U: {
#define M_MAX_UINT(x) static_cast<uint64_t>(-1ULL >> (64 - (x)))
uint64_t mask = static_cast<uint64_t>(-1ULL >> (64 - 8 * sizeof(T)));
uint64_t ws_u64 = static_cast<uint64_t>(ws) & mask;
res = static_cast<T>(ws_u64 < M_MAX_UINT(m + 1) ? ws_u64
: M_MAX_UINT(m + 1));
#undef M_MAX_UINT
} break;
case SRARI:
if (!m) {
res = static_cast<T>(ws);
} else {
res = static_cast<T>(ArithmeticShiftRight(ws, m)) +
static_cast<T>((ws >> (m - 1)) & 0x1);
}
break;
case SRLRI:
UNIMPLEMENTED();
if (!m) {
res = static_cast<T>(ws);
} else {
res = static_cast<T>(static_cast<uT>(ws) >> m) +
static_cast<T>((ws >> (m - 1)) & 0x1);
}
break;
default:
UNREACHABLE();
}
return res;
}
void Simulator::DecodeTypeMsaBIT() {
DCHECK(IsMipsArchVariant(kMips32r6));
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
uint32_t opcode = instr_.InstructionBits() & kMsaBITMask;
int32_t m = instr_.MsaBitMValue();
msa_reg_t wd, ws;
#define MSA_BIT_DF(elem, num_of_lanes) \
get_msa_register(instr_.WsValue(), ws.elem); \
if (opcode == BINSLI || opcode == BINSRI) { \
get_msa_register(instr_.WdValue(), wd.elem); \
} \
for (int i = 0; i < num_of_lanes; i++) { \
wd.elem[i] = MsaBitInstrHelper(opcode, wd.elem[i], ws.elem[i], m); \
} \
set_msa_register(instr_.WdValue(), wd.elem); \
TraceMSARegWr(wd.elem)
switch (DecodeMsaDataFormat()) {
case MSA_BYTE:
DCHECK(m < kMSARegSize / kMSALanesByte);
MSA_BIT_DF(b, kMSALanesByte);
break;
case MSA_HALF:
DCHECK(m < kMSARegSize / kMSALanesHalf);
MSA_BIT_DF(h, kMSALanesHalf);
break;
case MSA_WORD:
DCHECK(m < kMSARegSize / kMSALanesWord);
MSA_BIT_DF(w, kMSALanesWord);
break;
case MSA_DWORD:
DCHECK(m < kMSARegSize / kMSALanesDword);
MSA_BIT_DF(d, kMSALanesDword);
break;
default:
UNREACHABLE();
......
......@@ -424,6 +424,8 @@ class Simulator {
void DecodeTypeMsa2RF();
template <typename T>
T MsaI5InstrHelper(uint32_t opcode, T ws, int32_t i5);
template <typename T>
T MsaBitInstrHelper(uint32_t opcode, T wd, T ws, int32_t m);
inline int32_t rs_reg() const { return instr_.RsValue(); }
inline int32_t rs() const { return get_register(rs_reg()); }
......
......@@ -4808,25 +4808,127 @@ void Simulator::DecodeTypeMsaELM() {
}
}
void Simulator::DecodeTypeMsaBIT() {
DCHECK(kArchVariant == kMips64r6);
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
uint32_t opcode = instr_.InstructionBits() & kMsaBITMask;
template <typename T>
T Simulator::MsaBitInstrHelper(uint32_t opcode, T wd, T ws, int32_t m) {
typedef typename std::make_unsigned<T>::type uT;
T res;
switch (opcode) {
case SLLI:
res = static_cast<T>(ws << m);
break;
case SRAI:
res = static_cast<T>(ArithmeticShiftRight(ws, m));
break;
case SRLI:
res = static_cast<T>(static_cast<uT>(ws) >> m);
break;
case BCLRI:
res = static_cast<T>(static_cast<T>(~(1ull << m)) & ws);
break;
case BSETI:
res = static_cast<T>(static_cast<T>(1ull << m) | ws);
break;
case BNEGI:
case BINSLI:
case BINSRI:
case SAT_S:
case SAT_U:
res = static_cast<T>(static_cast<T>(1ull << m) ^ ws);
break;
case BINSLI: {
int elem_size = 8 * sizeof(T);
int bits = m + 1;
if (bits == elem_size) {
res = static_cast<T>(ws);
} else {
uint64_t mask = ((1ull << bits) - 1) << (elem_size - bits);
res = static_cast<T>((static_cast<T>(mask) & ws) |
(static_cast<T>(~mask) & wd));
}
} break;
case BINSRI: {
int elem_size = 8 * sizeof(T);
int bits = m + 1;
if (bits == elem_size) {
res = static_cast<T>(ws);
} else {
uint64_t mask = (1ull << bits) - 1;
res = static_cast<T>((static_cast<T>(mask) & ws) |
(static_cast<T>(~mask) & wd));
}
} break;
case SAT_S: {
#define M_MAX_INT(x) static_cast<int64_t>((1LL << ((x)-1)) - 1)
#define M_MIN_INT(x) static_cast<int64_t>(-(1LL << ((x)-1)))
int shift = 64 - 8 * sizeof(T);
int64_t ws_i64 = (static_cast<int64_t>(ws) << shift) >> shift;
res = static_cast<T>(ws_i64 < M_MIN_INT(m + 1)
? M_MIN_INT(m + 1)
: ws_i64 > M_MAX_INT(m + 1) ? M_MAX_INT(m + 1)
: ws_i64);
#undef M_MAX_INT
#undef M_MIN_INT
} break;
case SAT_U: {
#define M_MAX_UINT(x) static_cast<uint64_t>(-1ULL >> (64 - (x)))
uint64_t mask = static_cast<uint64_t>(-1ULL >> (64 - 8 * sizeof(T)));
uint64_t ws_u64 = static_cast<uint64_t>(ws) & mask;
res = static_cast<T>(ws_u64 < M_MAX_UINT(m + 1) ? ws_u64
: M_MAX_UINT(m + 1));
#undef M_MAX_UINT
} break;
case SRARI:
if (!m) {
res = static_cast<T>(ws);
} else {
res = static_cast<T>(ArithmeticShiftRight(ws, m)) +
static_cast<T>((ws >> (m - 1)) & 0x1);
}
break;
case SRLRI:
UNIMPLEMENTED();
if (!m) {
res = static_cast<T>(ws);
} else {
res = static_cast<T>(static_cast<uT>(ws) >> m) +
static_cast<T>((ws >> (m - 1)) & 0x1);
}
break;
default:
UNREACHABLE();
}
return res;
}
void Simulator::DecodeTypeMsaBIT() {
DCHECK(kArchVariant == kMips64r6);
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
uint32_t opcode = instr_.InstructionBits() & kMsaBITMask;
int32_t m = instr_.MsaBitMValue();
msa_reg_t wd, ws;
#define MSA_BIT_DF(elem, num_of_lanes) \
get_msa_register(instr_.WsValue(), ws.elem); \
if (opcode == BINSLI || opcode == BINSRI) { \
get_msa_register(instr_.WdValue(), wd.elem); \
} \
for (int i = 0; i < num_of_lanes; i++) { \
wd.elem[i] = MsaBitInstrHelper(opcode, wd.elem[i], ws.elem[i], m); \
} \
set_msa_register(instr_.WdValue(), wd.elem); \
TraceMSARegWr(wd.elem)
switch (DecodeMsaDataFormat()) {
case MSA_BYTE:
DCHECK(m < kMSARegSize / kMSALanesByte);
MSA_BIT_DF(b, kMSALanesByte);
break;
case MSA_HALF:
DCHECK(m < kMSARegSize / kMSALanesHalf);
MSA_BIT_DF(h, kMSALanesHalf);
break;
case MSA_WORD:
DCHECK(m < kMSARegSize / kMSALanesWord);
MSA_BIT_DF(w, kMSALanesWord);
break;
case MSA_DWORD:
DCHECK(m < kMSARegSize / kMSALanesDword);
MSA_BIT_DF(d, kMSALanesDword);
break;
default:
UNREACHABLE();
......
......@@ -441,6 +441,8 @@ class Simulator {
void DecodeTypeMsa2RF();
template <typename T>
T MsaI5InstrHelper(uint32_t opcode, T ws, int32_t i5);
template <typename T>
T MsaBitInstrHelper(uint32_t opcode, T wd, T ws, int32_t m);
// Executing is handled based on the instruction type.
void DecodeTypeRegister();
......
This diff is collapsed.
This diff is collapsed.
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