Reland "MIPS[64] Implementation of MSA instructions on builtin simulator"
This is reland of 3e0bf580e8
Original change's description:
> This commit is a step toward enabling test-run-wasm-simd tests for MIPS.
> 36 of those were failing in V8 builtin simulator because some instructions
> were not implemented. Also there are minor fixes to some of the already
> implemented instructions.
>
> This commit has only 32-bit implementation. After review I will add
> 64-bit version.
>
> Bug:
> Change-Id: I25b0cac352db3efb56b922ace64ab2aaef82472d
> Reviewed-on: https://chromium-review.googlesource.com/744008
> Reviewed-by: Ivica Bogosavljevic <ivica.bogosavljevic@mips.com>
> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
> Commit-Queue: Ivica Bogosavljevic <ivica.bogosavljevic@mips.com>
> Cr-Commit-Position: refs/heads/master@{#49439}
Bug:
Change-Id: I3a904caf675d314186c02c1c843d1e6a91a21a14
Reviewed-on: https://chromium-review.googlesource.com/776813
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Ivica Bogosavljevic <ivica.bogosavljevic@mips.com>
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Commit-Queue: Ivica Bogosavljevic <ivica.bogosavljevic@mips.com>
Cr-Commit-Position: refs/heads/master@{#49666}
This commit is contained in:
parent
42bc9e8c64
commit
25d4f93740
@ -4671,9 +4671,12 @@ void Simulator::DecodeTypeMsaELM() {
|
||||
DCHECK_EQ(rd_reg(), kMSACSRRegister);
|
||||
SetResult(sa(), bit_cast<int32_t>(MSACSR_));
|
||||
break;
|
||||
case MOVE_V:
|
||||
UNIMPLEMENTED();
|
||||
break;
|
||||
case MOVE_V: {
|
||||
msa_reg_t ws;
|
||||
get_msa_register(ws_reg(), &ws);
|
||||
set_msa_register(wd_reg(), &ws);
|
||||
TraceMSARegWr(&ws);
|
||||
} break;
|
||||
default:
|
||||
opcode &= kMsaELMMask;
|
||||
switch (opcode) {
|
||||
@ -4742,7 +4745,50 @@ void Simulator::DecodeTypeMsaELM() {
|
||||
UNREACHABLE();
|
||||
}
|
||||
} break;
|
||||
case SLDI:
|
||||
case SLDI: {
|
||||
uint8_t v[32];
|
||||
msa_reg_t ws;
|
||||
msa_reg_t wd;
|
||||
get_msa_register(ws_reg(), &ws);
|
||||
get_msa_register(wd_reg(), &wd);
|
||||
#define SLDI_DF(s, k) \
|
||||
for (unsigned i = 0; i < s; i++) { \
|
||||
v[i] = ws.b[s * k + i]; \
|
||||
v[i + s] = wd.b[s * k + i]; \
|
||||
} \
|
||||
for (unsigned i = 0; i < s; i++) { \
|
||||
wd.b[s * k + i] = v[i + n]; \
|
||||
}
|
||||
switch (DecodeMsaDataFormat()) {
|
||||
case MSA_BYTE:
|
||||
DCHECK(n < kMSALanesByte);
|
||||
SLDI_DF(kMSARegSize / sizeof(int8_t) / kBitsPerByte, 0)
|
||||
break;
|
||||
case MSA_HALF:
|
||||
DCHECK(n < kMSALanesHalf);
|
||||
for (int k = 0; k < 2; ++k) {
|
||||
SLDI_DF(kMSARegSize / sizeof(int16_t) / kBitsPerByte, k)
|
||||
}
|
||||
break;
|
||||
case MSA_WORD:
|
||||
DCHECK(n < kMSALanesWord);
|
||||
for (int k = 0; k < 4; ++k) {
|
||||
SLDI_DF(kMSARegSize / sizeof(int32_t) / kBitsPerByte, k)
|
||||
}
|
||||
break;
|
||||
case MSA_DWORD:
|
||||
DCHECK(n < kMSALanesDword);
|
||||
for (int k = 0; k < 8; ++k) {
|
||||
SLDI_DF(kMSARegSize / sizeof(int64_t) / kBitsPerByte, k)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
set_msa_register(wd_reg(), &wd);
|
||||
TraceMSARegWr(&wd);
|
||||
} break;
|
||||
#undef SLDI_DF
|
||||
case SPLATI:
|
||||
case INSVE:
|
||||
UNIMPLEMENTED();
|
||||
@ -4879,6 +4925,7 @@ void Simulator::DecodeTypeMsaBIT() {
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
#undef MSA_BIT_DF
|
||||
}
|
||||
|
||||
void Simulator::DecodeTypeMsaMI10() {
|
||||
@ -5161,13 +5208,6 @@ T Simulator::Msa3RInstrHelper(uint32_t opcode, T wd, T ws, T wt) {
|
||||
case DPSUB_U:
|
||||
case SLD:
|
||||
case SPLAT:
|
||||
case PCKEV:
|
||||
case PCKOD:
|
||||
case ILVL:
|
||||
case ILVR:
|
||||
case ILVEV:
|
||||
case ILVOD:
|
||||
case VSHF:
|
||||
UNIMPLEMENTED();
|
||||
break;
|
||||
case SRAR: {
|
||||
@ -5179,51 +5219,210 @@ T Simulator::Msa3RInstrHelper(uint32_t opcode, T wd, T ws, T wt) {
|
||||
int bit = wt_modulo == 0 ? 0 : (wsu >> (wt_modulo - 1)) & 1;
|
||||
res = static_cast<T>((wsu >> wt_modulo) + bit);
|
||||
} break;
|
||||
case HADD_S:
|
||||
case HADD_U:
|
||||
case HSUB_S:
|
||||
case HSUB_U:
|
||||
UNIMPLEMENTED();
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename T_int, typename T_reg>
|
||||
void Msa3RInstrHelper_shuffle(const uint32_t opcode, T_reg ws, T_reg wt,
|
||||
T_reg wd, const int i, const int num_of_lanes) {
|
||||
T_int *ws_p, *wt_p, *wd_p;
|
||||
ws_p = reinterpret_cast<T_int*>(ws);
|
||||
wt_p = reinterpret_cast<T_int*>(wt);
|
||||
wd_p = reinterpret_cast<T_int*>(wd);
|
||||
switch (opcode) {
|
||||
case PCKEV:
|
||||
wd_p[i] = wt_p[2 * i];
|
||||
wd_p[i + num_of_lanes / 2] = ws_p[2 * i];
|
||||
break;
|
||||
case PCKOD:
|
||||
wd_p[i] = wt_p[2 * i + 1];
|
||||
wd_p[i + num_of_lanes / 2] = ws_p[2 * i + 1];
|
||||
break;
|
||||
case ILVL:
|
||||
wd_p[2 * i] = wt_p[i + num_of_lanes / 2];
|
||||
wd_p[2 * i + 1] = ws_p[i + num_of_lanes / 2];
|
||||
break;
|
||||
case ILVR:
|
||||
wd_p[2 * i] = wt_p[i];
|
||||
wd_p[2 * i + 1] = ws_p[i];
|
||||
break;
|
||||
case ILVEV:
|
||||
wd_p[2 * i] = wt_p[2 * i];
|
||||
wd_p[2 * i + 1] = ws_p[2 * i];
|
||||
break;
|
||||
case ILVOD:
|
||||
wd_p[2 * i] = wt_p[2 * i + 1];
|
||||
wd_p[2 * i + 1] = ws_p[2 * i + 1];
|
||||
break;
|
||||
case VSHF: {
|
||||
const int mask_not_valid = 0xc0;
|
||||
const int mask_6_bits = 0x3f;
|
||||
if ((wd_p[i] & mask_not_valid)) {
|
||||
wd_p[i] = 0;
|
||||
} else {
|
||||
int k = (wd_p[i] & mask_6_bits) % (num_of_lanes * 2);
|
||||
wd_p[i] = k >= num_of_lanes ? ws_p[k - num_of_lanes] : wt_p[k];
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T_int, typename T_smaller_int, typename T_reg>
|
||||
void Msa3RInstrHelper_horizontal(const uint32_t opcode, T_reg ws, T_reg wt,
|
||||
T_reg wd, const int i,
|
||||
const int num_of_lanes) {
|
||||
typedef typename std::make_unsigned<T_int>::type T_uint;
|
||||
typedef typename std::make_unsigned<T_smaller_int>::type T_smaller_uint;
|
||||
T_int* wd_p;
|
||||
T_smaller_int *ws_p, *wt_p;
|
||||
ws_p = reinterpret_cast<T_smaller_int*>(ws);
|
||||
wt_p = reinterpret_cast<T_smaller_int*>(wt);
|
||||
wd_p = reinterpret_cast<T_int*>(wd);
|
||||
T_uint* wd_pu;
|
||||
T_smaller_uint *ws_pu, *wt_pu;
|
||||
ws_pu = reinterpret_cast<T_smaller_uint*>(ws);
|
||||
wt_pu = reinterpret_cast<T_smaller_uint*>(wt);
|
||||
wd_pu = reinterpret_cast<T_uint*>(wd);
|
||||
switch (opcode) {
|
||||
case HADD_S:
|
||||
wd_p[i] =
|
||||
static_cast<T_int>(ws_p[2 * i + 1]) + static_cast<T_int>(wt_p[2 * i]);
|
||||
break;
|
||||
case HADD_U:
|
||||
wd_pu[i] = static_cast<T_uint>(ws_pu[2 * i + 1]) +
|
||||
static_cast<T_uint>(wt_pu[2 * i]);
|
||||
break;
|
||||
case HSUB_S:
|
||||
wd_p[i] =
|
||||
static_cast<T_int>(ws_p[2 * i + 1]) - static_cast<T_int>(wt_p[2 * i]);
|
||||
break;
|
||||
case HSUB_U:
|
||||
wd_pu[i] = static_cast<T_uint>(ws_pu[2 * i + 1]) -
|
||||
static_cast<T_uint>(wt_pu[2 * i]);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
void Simulator::DecodeTypeMsa3R() {
|
||||
DCHECK(IsMipsArchVariant(kMips32r6));
|
||||
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
|
||||
uint32_t opcode = instr_.InstructionBits() & kMsa3RMask;
|
||||
msa_reg_t ws, wd, wt;
|
||||
|
||||
get_msa_register(ws_reg(), &ws);
|
||||
get_msa_register(wt_reg(), &wt);
|
||||
get_msa_register(wd_reg(), &wd);
|
||||
switch (opcode) {
|
||||
case HADD_S:
|
||||
case HADD_U:
|
||||
case HSUB_S:
|
||||
case HSUB_U:
|
||||
#define HORIZONTAL_ARITHMETIC_DF(num_of_lanes, int_type, lesser_int_type) \
|
||||
for (int i = 0; i < num_of_lanes; ++i) { \
|
||||
Msa3RInstrHelper_horizontal<int_type, lesser_int_type>( \
|
||||
opcode, &ws, &wt, &wd, i, num_of_lanes); \
|
||||
}
|
||||
switch (DecodeMsaDataFormat()) {
|
||||
case MSA_HALF:
|
||||
HORIZONTAL_ARITHMETIC_DF(kMSALanesHalf, int16_t, int8_t);
|
||||
break;
|
||||
case MSA_WORD:
|
||||
HORIZONTAL_ARITHMETIC_DF(kMSALanesWord, int32_t, int16_t);
|
||||
break;
|
||||
case MSA_DWORD:
|
||||
HORIZONTAL_ARITHMETIC_DF(kMSALanesDword, int64_t, int32_t);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
#undef HORIZONTAL_ARITHMETIC_DF
|
||||
case VSHF:
|
||||
#define VSHF_DF(num_of_lanes, int_type) \
|
||||
for (int i = 0; i < num_of_lanes; ++i) { \
|
||||
Msa3RInstrHelper_shuffle<int_type>(opcode, &ws, &wt, &wd, i, \
|
||||
num_of_lanes); \
|
||||
}
|
||||
switch (DecodeMsaDataFormat()) {
|
||||
case MSA_BYTE:
|
||||
VSHF_DF(kMSALanesByte, int8_t);
|
||||
break;
|
||||
case MSA_HALF:
|
||||
VSHF_DF(kMSALanesHalf, int16_t);
|
||||
break;
|
||||
case MSA_WORD:
|
||||
VSHF_DF(kMSALanesWord, int32_t);
|
||||
break;
|
||||
case MSA_DWORD:
|
||||
VSHF_DF(kMSALanesDword, int64_t);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
#undef VSHF_DF
|
||||
break;
|
||||
case PCKEV:
|
||||
case PCKOD:
|
||||
case ILVL:
|
||||
case ILVR:
|
||||
case ILVEV:
|
||||
case ILVOD:
|
||||
#define INTERLEAVE_PACK_DF(num_of_lanes, int_type) \
|
||||
for (int i = 0; i < num_of_lanes / 2; ++i) { \
|
||||
Msa3RInstrHelper_shuffle<int_type>(opcode, &ws, &wt, &wd, i, \
|
||||
num_of_lanes); \
|
||||
}
|
||||
switch (DecodeMsaDataFormat()) {
|
||||
case MSA_BYTE:
|
||||
INTERLEAVE_PACK_DF(kMSALanesByte, int8_t);
|
||||
break;
|
||||
case MSA_HALF:
|
||||
INTERLEAVE_PACK_DF(kMSALanesHalf, int16_t);
|
||||
break;
|
||||
case MSA_WORD:
|
||||
INTERLEAVE_PACK_DF(kMSALanesWord, int32_t);
|
||||
break;
|
||||
case MSA_DWORD:
|
||||
INTERLEAVE_PACK_DF(kMSALanesDword, int64_t);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
#undef INTERLEAVE_PACK_DF
|
||||
default:
|
||||
#define MSA_3R_DF(elem, num_of_lanes) \
|
||||
get_msa_register(instr_.WdValue(), wd.elem); \
|
||||
get_msa_register(instr_.WsValue(), ws.elem); \
|
||||
get_msa_register(instr_.WtValue(), wt.elem); \
|
||||
for (int i = 0; i < num_of_lanes; i++) { \
|
||||
wd.elem[i] = Msa3RInstrHelper(opcode, wd.elem[i], ws.elem[i], wt.elem[i]); \
|
||||
} \
|
||||
set_msa_register(instr_.WdValue(), wd.elem); \
|
||||
TraceMSARegWr(wd.elem);
|
||||
}
|
||||
|
||||
switch (DecodeMsaDataFormat()) {
|
||||
case MSA_BYTE:
|
||||
MSA_3R_DF(b, kMSALanesByte);
|
||||
break;
|
||||
case MSA_HALF:
|
||||
MSA_3R_DF(h, kMSALanesHalf);
|
||||
break;
|
||||
case MSA_WORD:
|
||||
MSA_3R_DF(w, kMSALanesWord);
|
||||
break;
|
||||
case MSA_DWORD:
|
||||
MSA_3R_DF(d, kMSALanesDword);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
switch (DecodeMsaDataFormat()) {
|
||||
case MSA_BYTE:
|
||||
MSA_3R_DF(b, kMSALanesByte);
|
||||
break;
|
||||
case MSA_HALF:
|
||||
MSA_3R_DF(h, kMSALanesHalf);
|
||||
break;
|
||||
case MSA_WORD:
|
||||
MSA_3R_DF(w, kMSALanesWord);
|
||||
break;
|
||||
case MSA_DWORD:
|
||||
MSA_3R_DF(d, kMSALanesDword);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
#undef MSA_3R_DF
|
||||
break;
|
||||
}
|
||||
set_msa_register(wd_reg(), &wd);
|
||||
TraceMSARegWr(&wd);
|
||||
}
|
||||
|
||||
template <typename T_int, typename T_fp, typename T_reg>
|
||||
@ -5321,7 +5520,7 @@ void Msa3RFInstrHelper(uint32_t opcode, T_reg ws, T_reg wt, T_reg& wd) {
|
||||
break;
|
||||
case FDIV: {
|
||||
if (t_element == 0) {
|
||||
wd = std::numeric_limits<T_fp>::quiet_NaN();
|
||||
wd = bit_cast<T_int>(std::numeric_limits<T_fp>::quiet_NaN());
|
||||
} else {
|
||||
wd = bit_cast<T_int>(s_element / t_element);
|
||||
}
|
||||
@ -5541,6 +5740,7 @@ void Simulator::DecodeTypeMsa3RF() {
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
#undef PACK_FLOAT16
|
||||
#undef FEXDO_DF
|
||||
case FTQ:
|
||||
#define FTQ_DF(source, dst, fp_type, int_type) \
|
||||
@ -5887,8 +6087,8 @@ T_int Msa2RFInstrHelper(uint32_t opcode, T_src src, T_dst& dst,
|
||||
const T_int min_int = std::numeric_limits<T_int>::min();
|
||||
if (std::isnan(element)) {
|
||||
dst = 0;
|
||||
} else if (element > max_int || element < min_int) {
|
||||
dst = element > max_int ? max_int : min_int;
|
||||
} else if (element >= max_int || element <= min_int) {
|
||||
dst = element >= max_int ? max_int : min_int;
|
||||
} else {
|
||||
dst = static_cast<T_int>(std::trunc(element));
|
||||
}
|
||||
@ -5899,8 +6099,8 @@ T_int Msa2RFInstrHelper(uint32_t opcode, T_src src, T_dst& dst,
|
||||
const T_uint max_int = std::numeric_limits<T_uint>::max();
|
||||
if (std::isnan(element)) {
|
||||
dst = 0;
|
||||
} else if (element > max_int || element < 0) {
|
||||
dst = element > max_int ? max_int : 0;
|
||||
} else if (element >= max_int || element <= 0) {
|
||||
dst = element >= max_int ? max_int : 0;
|
||||
} else {
|
||||
dst = static_cast<T_uint>(std::trunc(element));
|
||||
}
|
||||
@ -6009,8 +6209,8 @@ T_int Msa2RFInstrHelper(uint32_t opcode, T_src src, T_dst& dst,
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename T_int, typename T_fp, typename T_reg, typename T_i>
|
||||
T_int Msa2RFInstrHelper2(uint32_t opcode, T_reg ws, T_i i) {
|
||||
template <typename T_int, typename T_fp, typename T_reg>
|
||||
T_int Msa2RFInstrHelper2(uint32_t opcode, T_reg ws, int i) {
|
||||
switch (opcode) {
|
||||
#define EXTRACT_FLOAT16_SIGN(fp16) (fp16 >> 15)
|
||||
#define EXTRACT_FLOAT16_EXP(fp16) (fp16 >> 10 & 0x1f)
|
||||
@ -6231,6 +6431,30 @@ void Simulator::DecodeTypeImmediate() {
|
||||
}
|
||||
};
|
||||
|
||||
auto BranchHelper_MSA = [this, &next_pc, imm16,
|
||||
&execute_branch_delay_instruction](bool do_branch) {
|
||||
execute_branch_delay_instruction = true;
|
||||
int32_t current_pc = get_pc();
|
||||
const int32_t bitsIn16Int = sizeof(int16_t) * kBitsPerByte;
|
||||
if (do_branch) {
|
||||
if (FLAG_debug_code) {
|
||||
int16_t bits = imm16 & 0xfc;
|
||||
if (imm16 >= 0) {
|
||||
CHECK_EQ(bits, 0);
|
||||
} else {
|
||||
CHECK_EQ(bits ^ 0xfc, 0);
|
||||
}
|
||||
}
|
||||
// jump range :[pc + kInstrSize - 512 * kInstrSize,
|
||||
// pc + kInstrSize + 511 * kInstrSize]
|
||||
int16_t offset = static_cast<int16_t>(imm16 << (bitsIn16Int - 10)) >>
|
||||
(bitsIn16Int - 12);
|
||||
next_pc = current_pc + offset + Instruction::kInstrSize;
|
||||
} else {
|
||||
next_pc = current_pc + 2 * Instruction::kInstrSize;
|
||||
}
|
||||
};
|
||||
|
||||
auto BranchAndLinkCompactHelper = [this, &next_pc](bool do_branch, int bits) {
|
||||
int32_t current_pc = get_pc();
|
||||
CheckForbiddenSlot(current_pc);
|
||||
@ -6273,18 +6497,66 @@ void Simulator::DecodeTypeImmediate() {
|
||||
case BC1NEZ:
|
||||
BranchHelper(get_fpu_register(ft_reg) & 0x1);
|
||||
break;
|
||||
case BZ_V:
|
||||
case BZ_V: {
|
||||
msa_reg_t wt;
|
||||
get_msa_register(wt_reg(), &wt);
|
||||
BranchHelper_MSA(wt.d[0] == 0 && wt.d[1] == 0);
|
||||
} break;
|
||||
#define BZ_DF(witdh, lanes) \
|
||||
{ \
|
||||
msa_reg_t wt; \
|
||||
get_msa_register(wt_reg(), &wt); \
|
||||
int i; \
|
||||
for (i = 0; i < lanes; ++i) { \
|
||||
if (wt.witdh[i] == 0) { \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
BranchHelper_MSA(i != lanes); \
|
||||
}
|
||||
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:
|
||||
UNIMPLEMENTED();
|
||||
BZ_DF(b, kMSALanesByte)
|
||||
break;
|
||||
case BZ_H:
|
||||
BZ_DF(h, kMSALanesHalf)
|
||||
break;
|
||||
case BZ_W:
|
||||
BZ_DF(w, kMSALanesWord)
|
||||
break;
|
||||
case BZ_D:
|
||||
BZ_DF(d, kMSALanesDword)
|
||||
break;
|
||||
#undef BZ_DF
|
||||
case BNZ_V: {
|
||||
msa_reg_t wt;
|
||||
get_msa_register(wt_reg(), &wt);
|
||||
BranchHelper_MSA(wt.d[0] != 0 || wt.d[1] != 0);
|
||||
} break;
|
||||
#define BNZ_DF(witdh, lanes) \
|
||||
{ \
|
||||
msa_reg_t wt; \
|
||||
get_msa_register(wt_reg(), &wt); \
|
||||
int i; \
|
||||
for (i = 0; i < lanes; ++i) { \
|
||||
if (wt.witdh[i] == 0) { \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
BranchHelper_MSA(i == lanes); \
|
||||
}
|
||||
case BNZ_B:
|
||||
BNZ_DF(b, kMSALanesByte)
|
||||
break;
|
||||
case BNZ_H:
|
||||
BNZ_DF(h, kMSALanesHalf)
|
||||
break;
|
||||
case BNZ_W:
|
||||
BNZ_DF(w, kMSALanesWord)
|
||||
break;
|
||||
case BNZ_D:
|
||||
BNZ_DF(d, kMSALanesDword)
|
||||
break;
|
||||
#undef BNZ_DF
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
@ -4883,9 +4883,12 @@ void Simulator::DecodeTypeMsaELM() {
|
||||
DCHECK_EQ(rd_reg(), kMSACSRRegister);
|
||||
SetResult(sa(), static_cast<int64_t>(bit_cast<int32_t>(MSACSR_)));
|
||||
break;
|
||||
case MOVE_V:
|
||||
UNIMPLEMENTED();
|
||||
break;
|
||||
case MOVE_V: {
|
||||
msa_reg_t ws;
|
||||
get_msa_register(ws_reg(), &ws);
|
||||
set_msa_register(wd_reg(), &ws);
|
||||
TraceMSARegWr(&ws);
|
||||
} break;
|
||||
default:
|
||||
opcode &= kMsaELMMask;
|
||||
switch (opcode) {
|
||||
@ -4967,7 +4970,50 @@ void Simulator::DecodeTypeMsaELM() {
|
||||
UNREACHABLE();
|
||||
}
|
||||
} break;
|
||||
case SLDI:
|
||||
case SLDI: {
|
||||
uint8_t v[32];
|
||||
msa_reg_t ws;
|
||||
msa_reg_t wd;
|
||||
get_msa_register(ws_reg(), &ws);
|
||||
get_msa_register(wd_reg(), &wd);
|
||||
#define SLDI_DF(s, k) \
|
||||
for (unsigned i = 0; i < s; i++) { \
|
||||
v[i] = ws.b[s * k + i]; \
|
||||
v[i + s] = wd.b[s * k + i]; \
|
||||
} \
|
||||
for (unsigned i = 0; i < s; i++) { \
|
||||
wd.b[s * k + i] = v[i + n]; \
|
||||
}
|
||||
switch (DecodeMsaDataFormat()) {
|
||||
case MSA_BYTE:
|
||||
DCHECK(n < kMSALanesByte);
|
||||
SLDI_DF(kMSARegSize / sizeof(int8_t) / kBitsPerByte, 0)
|
||||
break;
|
||||
case MSA_HALF:
|
||||
DCHECK(n < kMSALanesHalf);
|
||||
for (int k = 0; k < 2; ++k) {
|
||||
SLDI_DF(kMSARegSize / sizeof(int16_t) / kBitsPerByte, k)
|
||||
}
|
||||
break;
|
||||
case MSA_WORD:
|
||||
DCHECK(n < kMSALanesWord);
|
||||
for (int k = 0; k < 4; ++k) {
|
||||
SLDI_DF(kMSARegSize / sizeof(int32_t) / kBitsPerByte, k)
|
||||
}
|
||||
break;
|
||||
case MSA_DWORD:
|
||||
DCHECK(n < kMSALanesDword);
|
||||
for (int k = 0; k < 8; ++k) {
|
||||
SLDI_DF(kMSARegSize / sizeof(int64_t) / kBitsPerByte, k)
|
||||
}
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
set_msa_register(wd_reg(), &wd);
|
||||
TraceMSARegWr(&wd);
|
||||
} break;
|
||||
#undef SLDI_DF
|
||||
case SPLATI:
|
||||
case INSVE:
|
||||
UNIMPLEMENTED();
|
||||
@ -5104,6 +5150,7 @@ void Simulator::DecodeTypeMsaBIT() {
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
#undef MSA_BIT_DF
|
||||
}
|
||||
|
||||
void Simulator::DecodeTypeMsaMI10() {
|
||||
@ -5386,13 +5433,6 @@ T Simulator::Msa3RInstrHelper(uint32_t opcode, T wd, T ws, T wt) {
|
||||
case DPSUB_U:
|
||||
case SLD:
|
||||
case SPLAT:
|
||||
case PCKEV:
|
||||
case PCKOD:
|
||||
case ILVL:
|
||||
case ILVR:
|
||||
case ILVEV:
|
||||
case ILVOD:
|
||||
case VSHF:
|
||||
UNIMPLEMENTED();
|
||||
break;
|
||||
case SRAR: {
|
||||
@ -5404,51 +5444,209 @@ T Simulator::Msa3RInstrHelper(uint32_t opcode, T wd, T ws, T wt) {
|
||||
int bit = wt_modulo == 0 ? 0 : (wsu >> (wt_modulo - 1)) & 1;
|
||||
res = static_cast<T>((wsu >> wt_modulo) + bit);
|
||||
} break;
|
||||
case HADD_S:
|
||||
case HADD_U:
|
||||
case HSUB_S:
|
||||
case HSUB_U:
|
||||
UNIMPLEMENTED();
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
template <typename T_int, typename T_reg>
|
||||
void Msa3RInstrHelper_shuffle(const uint32_t opcode, T_reg ws, T_reg wt,
|
||||
T_reg wd, const int i, const int num_of_lanes) {
|
||||
T_int *ws_p, *wt_p, *wd_p;
|
||||
ws_p = reinterpret_cast<T_int*>(ws);
|
||||
wt_p = reinterpret_cast<T_int*>(wt);
|
||||
wd_p = reinterpret_cast<T_int*>(wd);
|
||||
switch (opcode) {
|
||||
case PCKEV:
|
||||
wd_p[i] = wt_p[2 * i];
|
||||
wd_p[i + num_of_lanes / 2] = ws_p[2 * i];
|
||||
break;
|
||||
case PCKOD:
|
||||
wd_p[i] = wt_p[2 * i + 1];
|
||||
wd_p[i + num_of_lanes / 2] = ws_p[2 * i + 1];
|
||||
break;
|
||||
case ILVL:
|
||||
wd_p[2 * i] = wt_p[i + num_of_lanes / 2];
|
||||
wd_p[2 * i + 1] = ws_p[i + num_of_lanes / 2];
|
||||
break;
|
||||
case ILVR:
|
||||
wd_p[2 * i] = wt_p[i];
|
||||
wd_p[2 * i + 1] = ws_p[i];
|
||||
break;
|
||||
case ILVEV:
|
||||
wd_p[2 * i] = wt_p[2 * i];
|
||||
wd_p[2 * i + 1] = ws_p[2 * i];
|
||||
break;
|
||||
case ILVOD:
|
||||
wd_p[2 * i] = wt_p[2 * i + 1];
|
||||
wd_p[2 * i + 1] = ws_p[2 * i + 1];
|
||||
break;
|
||||
case VSHF: {
|
||||
const int mask_not_valid = 0xc0;
|
||||
const int mask_6_bits = 0x3f;
|
||||
if ((wd_p[i] & mask_not_valid)) {
|
||||
wd_p[i] = 0;
|
||||
} else {
|
||||
int k = (wd_p[i] & mask_6_bits) % (num_of_lanes * 2);
|
||||
wd_p[i] = k >= num_of_lanes ? ws_p[k - num_of_lanes] : wt_p[k];
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T_int, typename T_smaller_int, typename T_reg>
|
||||
void Msa3RInstrHelper_horizontal(const uint32_t opcode, T_reg ws, T_reg wt,
|
||||
T_reg wd, const int i,
|
||||
const int num_of_lanes) {
|
||||
typedef typename std::make_unsigned<T_int>::type T_uint;
|
||||
typedef typename std::make_unsigned<T_smaller_int>::type T_smaller_uint;
|
||||
T_int* wd_p;
|
||||
T_smaller_int *ws_p, *wt_p;
|
||||
ws_p = reinterpret_cast<T_smaller_int*>(ws);
|
||||
wt_p = reinterpret_cast<T_smaller_int*>(wt);
|
||||
wd_p = reinterpret_cast<T_int*>(wd);
|
||||
T_uint* wd_pu;
|
||||
T_smaller_uint *ws_pu, *wt_pu;
|
||||
ws_pu = reinterpret_cast<T_smaller_uint*>(ws);
|
||||
wt_pu = reinterpret_cast<T_smaller_uint*>(wt);
|
||||
wd_pu = reinterpret_cast<T_uint*>(wd);
|
||||
switch (opcode) {
|
||||
case HADD_S:
|
||||
wd_p[i] =
|
||||
static_cast<T_int>(ws_p[2 * i + 1]) + static_cast<T_int>(wt_p[2 * i]);
|
||||
break;
|
||||
case HADD_U:
|
||||
wd_pu[i] = static_cast<T_uint>(ws_pu[2 * i + 1]) +
|
||||
static_cast<T_uint>(wt_pu[2 * i]);
|
||||
break;
|
||||
case HSUB_S:
|
||||
wd_p[i] =
|
||||
static_cast<T_int>(ws_p[2 * i + 1]) - static_cast<T_int>(wt_p[2 * i]);
|
||||
break;
|
||||
case HSUB_U:
|
||||
wd_pu[i] = static_cast<T_uint>(ws_pu[2 * i + 1]) -
|
||||
static_cast<T_uint>(wt_pu[2 * i]);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
void Simulator::DecodeTypeMsa3R() {
|
||||
DCHECK_EQ(kArchVariant, kMips64r6);
|
||||
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
|
||||
uint32_t opcode = instr_.InstructionBits() & kMsa3RMask;
|
||||
msa_reg_t ws, wd, wt;
|
||||
|
||||
get_msa_register(ws_reg(), &ws);
|
||||
get_msa_register(wt_reg(), &wt);
|
||||
get_msa_register(wd_reg(), &wd);
|
||||
switch (opcode) {
|
||||
case HADD_S:
|
||||
case HADD_U:
|
||||
case HSUB_S:
|
||||
case HSUB_U:
|
||||
#define HORIZONTAL_ARITHMETIC_DF(num_of_lanes, int_type, lesser_int_type) \
|
||||
for (int i = 0; i < num_of_lanes; ++i) { \
|
||||
Msa3RInstrHelper_horizontal<int_type, lesser_int_type>( \
|
||||
opcode, &ws, &wt, &wd, i, num_of_lanes); \
|
||||
}
|
||||
switch (DecodeMsaDataFormat()) {
|
||||
case MSA_HALF:
|
||||
HORIZONTAL_ARITHMETIC_DF(kMSALanesHalf, int16_t, int8_t);
|
||||
break;
|
||||
case MSA_WORD:
|
||||
HORIZONTAL_ARITHMETIC_DF(kMSALanesWord, int32_t, int16_t);
|
||||
break;
|
||||
case MSA_DWORD:
|
||||
HORIZONTAL_ARITHMETIC_DF(kMSALanesDword, int64_t, int32_t);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
#undef HORIZONTAL_ARITHMETIC_DF
|
||||
case VSHF:
|
||||
#define VSHF_DF(num_of_lanes, int_type) \
|
||||
for (int i = 0; i < num_of_lanes; ++i) { \
|
||||
Msa3RInstrHelper_shuffle<int_type>(opcode, &ws, &wt, &wd, i, \
|
||||
num_of_lanes); \
|
||||
}
|
||||
switch (DecodeMsaDataFormat()) {
|
||||
case MSA_BYTE:
|
||||
VSHF_DF(kMSALanesByte, int8_t);
|
||||
break;
|
||||
case MSA_HALF:
|
||||
VSHF_DF(kMSALanesHalf, int16_t);
|
||||
break;
|
||||
case MSA_WORD:
|
||||
VSHF_DF(kMSALanesWord, int32_t);
|
||||
break;
|
||||
case MSA_DWORD:
|
||||
VSHF_DF(kMSALanesDword, int64_t);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
#undef VSHF_DF
|
||||
break;
|
||||
case PCKEV:
|
||||
case PCKOD:
|
||||
case ILVL:
|
||||
case ILVR:
|
||||
case ILVEV:
|
||||
case ILVOD:
|
||||
#define INTERLEAVE_PACK_DF(num_of_lanes, int_type) \
|
||||
for (int i = 0; i < num_of_lanes / 2; ++i) { \
|
||||
Msa3RInstrHelper_shuffle<int_type>(opcode, &ws, &wt, &wd, i, \
|
||||
num_of_lanes); \
|
||||
}
|
||||
switch (DecodeMsaDataFormat()) {
|
||||
case MSA_BYTE:
|
||||
INTERLEAVE_PACK_DF(kMSALanesByte, int8_t);
|
||||
break;
|
||||
case MSA_HALF:
|
||||
INTERLEAVE_PACK_DF(kMSALanesHalf, int16_t);
|
||||
break;
|
||||
case MSA_WORD:
|
||||
INTERLEAVE_PACK_DF(kMSALanesWord, int32_t);
|
||||
break;
|
||||
case MSA_DWORD:
|
||||
INTERLEAVE_PACK_DF(kMSALanesDword, int64_t);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
#undef INTERLEAVE_PACK_DF
|
||||
default:
|
||||
#define MSA_3R_DF(elem, num_of_lanes) \
|
||||
get_msa_register(instr_.WdValue(), wd.elem); \
|
||||
get_msa_register(instr_.WsValue(), ws.elem); \
|
||||
get_msa_register(instr_.WtValue(), wt.elem); \
|
||||
for (int i = 0; i < num_of_lanes; i++) { \
|
||||
wd.elem[i] = Msa3RInstrHelper(opcode, wd.elem[i], ws.elem[i], wt.elem[i]); \
|
||||
} \
|
||||
set_msa_register(instr_.WdValue(), wd.elem); \
|
||||
TraceMSARegWr(wd.elem);
|
||||
|
||||
switch (DecodeMsaDataFormat()) {
|
||||
case MSA_BYTE:
|
||||
MSA_3R_DF(b, kMSALanesByte);
|
||||
break;
|
||||
case MSA_HALF:
|
||||
MSA_3R_DF(h, kMSALanesHalf);
|
||||
break;
|
||||
case MSA_WORD:
|
||||
MSA_3R_DF(w, kMSALanesWord);
|
||||
break;
|
||||
case MSA_DWORD:
|
||||
MSA_3R_DF(d, kMSALanesDword);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
switch (DecodeMsaDataFormat()) {
|
||||
case MSA_BYTE:
|
||||
MSA_3R_DF(b, kMSALanesByte);
|
||||
break;
|
||||
case MSA_HALF:
|
||||
MSA_3R_DF(h, kMSALanesHalf);
|
||||
break;
|
||||
case MSA_WORD:
|
||||
MSA_3R_DF(w, kMSALanesWord);
|
||||
break;
|
||||
case MSA_DWORD:
|
||||
MSA_3R_DF(d, kMSALanesDword);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
#undef MSA_3R_DF
|
||||
break;
|
||||
}
|
||||
set_msa_register(wd_reg(), &wd);
|
||||
TraceMSARegWr(&wd);
|
||||
}
|
||||
|
||||
template <typename T_int, typename T_fp, typename T_reg>
|
||||
@ -5546,7 +5744,7 @@ void Msa3RFInstrHelper(uint32_t opcode, T_reg ws, T_reg wt, T_reg& wd) {
|
||||
break;
|
||||
case FDIV: {
|
||||
if (t_element == 0) {
|
||||
wd = std::numeric_limits<T_fp>::quiet_NaN();
|
||||
wd = bit_cast<T_int>(std::numeric_limits<T_fp>::quiet_NaN());
|
||||
} else {
|
||||
wd = bit_cast<T_int>(s_element / t_element);
|
||||
}
|
||||
@ -5766,6 +5964,7 @@ void Simulator::DecodeTypeMsa3RF() {
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
#undef PACK_FLOAT16
|
||||
#undef FEXDO_DF
|
||||
case FTQ:
|
||||
#define FTQ_DF(source, dst, fp_type, int_type) \
|
||||
@ -6119,8 +6318,8 @@ T_int Msa2RFInstrHelper(uint32_t opcode, T_src src, T_dst& dst,
|
||||
const T_int min_int = std::numeric_limits<T_int>::min();
|
||||
if (std::isnan(element)) {
|
||||
dst = 0;
|
||||
} else if (element > max_int || element < min_int) {
|
||||
dst = element > max_int ? max_int : min_int;
|
||||
} else if (element >= max_int || element <= min_int) {
|
||||
dst = element >= max_int ? max_int : min_int;
|
||||
} else {
|
||||
dst = static_cast<T_int>(std::trunc(element));
|
||||
}
|
||||
@ -6131,8 +6330,8 @@ T_int Msa2RFInstrHelper(uint32_t opcode, T_src src, T_dst& dst,
|
||||
const T_uint max_int = std::numeric_limits<T_uint>::max();
|
||||
if (std::isnan(element)) {
|
||||
dst = 0;
|
||||
} else if (element > max_int || element < 0) {
|
||||
dst = element > max_int ? max_int : 0;
|
||||
} else if (element >= max_int || element <= 0) {
|
||||
dst = element >= max_int ? max_int : 0;
|
||||
} else {
|
||||
dst = static_cast<T_uint>(std::trunc(element));
|
||||
}
|
||||
@ -6241,8 +6440,8 @@ T_int Msa2RFInstrHelper(uint32_t opcode, T_src src, T_dst& dst,
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename T_int, typename T_fp, typename T_reg, typename T_i>
|
||||
T_int Msa2RFInstrHelper2(uint32_t opcode, T_reg ws, T_i i) {
|
||||
template <typename T_int, typename T_fp, typename T_reg>
|
||||
T_int Msa2RFInstrHelper2(uint32_t opcode, T_reg ws, int i) {
|
||||
switch (opcode) {
|
||||
#define EXTRACT_FLOAT16_SIGN(fp16) (fp16 >> 15)
|
||||
#define EXTRACT_FLOAT16_EXP(fp16) (fp16 >> 10 & 0x1f)
|
||||
@ -6472,6 +6671,30 @@ void Simulator::DecodeTypeImmediate() {
|
||||
}
|
||||
};
|
||||
|
||||
auto BranchHelper_MSA = [this, &next_pc, imm16,
|
||||
&execute_branch_delay_instruction](bool do_branch) {
|
||||
execute_branch_delay_instruction = true;
|
||||
int64_t current_pc = get_pc();
|
||||
const int32_t bitsIn16Int = sizeof(int16_t) * kBitsPerByte;
|
||||
if (do_branch) {
|
||||
if (FLAG_debug_code) {
|
||||
int16_t bits = imm16 & 0xfc;
|
||||
if (imm16 >= 0) {
|
||||
CHECK_EQ(bits, 0);
|
||||
} else {
|
||||
CHECK_EQ(bits ^ 0xfc, 0);
|
||||
}
|
||||
}
|
||||
// jump range :[pc + kInstrSize - 512 * kInstrSize,
|
||||
// pc + kInstrSize + 511 * kInstrSize]
|
||||
int16_t offset = static_cast<int16_t>(imm16 << (bitsIn16Int - 10)) >>
|
||||
(bitsIn16Int - 12);
|
||||
next_pc = current_pc + offset + Instruction::kInstrSize;
|
||||
} else {
|
||||
next_pc = current_pc + 2 * Instruction::kInstrSize;
|
||||
}
|
||||
};
|
||||
|
||||
auto BranchAndLinkCompactHelper = [this, &next_pc](bool do_branch, int bits) {
|
||||
int64_t current_pc = get_pc();
|
||||
CheckForbiddenSlot(current_pc);
|
||||
@ -6513,18 +6736,66 @@ void Simulator::DecodeTypeImmediate() {
|
||||
case BC1NEZ:
|
||||
BranchHelper(get_fpu_register(ft_reg) & 0x1);
|
||||
break;
|
||||
case BZ_V:
|
||||
case BZ_V: {
|
||||
msa_reg_t wt;
|
||||
get_msa_register(wt_reg(), &wt);
|
||||
BranchHelper_MSA(wt.d[0] == 0 && wt.d[1] == 0);
|
||||
} break;
|
||||
#define BZ_DF(witdh, lanes) \
|
||||
{ \
|
||||
msa_reg_t wt; \
|
||||
get_msa_register(wt_reg(), &wt); \
|
||||
int i; \
|
||||
for (i = 0; i < lanes; ++i) { \
|
||||
if (wt.witdh[i] == 0) { \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
BranchHelper_MSA(i != lanes); \
|
||||
}
|
||||
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:
|
||||
UNIMPLEMENTED();
|
||||
BZ_DF(b, kMSALanesByte)
|
||||
break;
|
||||
case BZ_H:
|
||||
BZ_DF(h, kMSALanesHalf)
|
||||
break;
|
||||
case BZ_W:
|
||||
BZ_DF(w, kMSALanesWord)
|
||||
break;
|
||||
case BZ_D:
|
||||
BZ_DF(d, kMSALanesDword)
|
||||
break;
|
||||
#undef BZ_DF
|
||||
case BNZ_V: {
|
||||
msa_reg_t wt;
|
||||
get_msa_register(wt_reg(), &wt);
|
||||
BranchHelper_MSA(wt.d[0] != 0 || wt.d[1] != 0);
|
||||
} break;
|
||||
#define BNZ_DF(witdh, lanes) \
|
||||
{ \
|
||||
msa_reg_t wt; \
|
||||
get_msa_register(wt_reg(), &wt); \
|
||||
int i; \
|
||||
for (i = 0; i < lanes; ++i) { \
|
||||
if (wt.witdh[i] == 0) { \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
BranchHelper_MSA(i == lanes); \
|
||||
}
|
||||
case BNZ_B:
|
||||
BNZ_DF(b, kMSALanesByte)
|
||||
break;
|
||||
case BNZ_H:
|
||||
BNZ_DF(h, kMSALanesHalf)
|
||||
break;
|
||||
case BNZ_W:
|
||||
BNZ_DF(w, kMSALanesWord)
|
||||
break;
|
||||
case BNZ_D:
|
||||
BNZ_DF(d, kMSALanesDword)
|
||||
break;
|
||||
#undef BNZ_DF
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
@ -288,7 +288,7 @@ T SaturateAdd(T a, T b) {
|
||||
template <typename T>
|
||||
T SaturateSub(T a, T b) {
|
||||
if (std::is_signed<T>::value) {
|
||||
if (a > 0 && b < 0) {
|
||||
if (a >= 0 && b < 0) {
|
||||
if (a > std::numeric_limits<T>::max() + b) {
|
||||
return std::numeric_limits<T>::max();
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -176,6 +176,7 @@ v8_source_set("unittests_sources") {
|
||||
"test-utils.cc",
|
||||
"test-utils.h",
|
||||
"unicode-unittest.cc",
|
||||
"utils-unittest.cc",
|
||||
"value-serializer-unittest.cc",
|
||||
"wasm/control-transfer-unittest.cc",
|
||||
"wasm/decoder-unittest.cc",
|
||||
|
@ -149,6 +149,7 @@
|
||||
'test-utils.h',
|
||||
'test-utils.cc',
|
||||
'unicode-unittest.cc',
|
||||
'utils-unittest.cc',
|
||||
'value-serializer-unittest.cc',
|
||||
'zone/segmentpool-unittest.cc',
|
||||
'zone/zone-allocator-unittest.cc',
|
||||
|
113
test/unittests/utils-unittest.cc
Normal file
113
test/unittests/utils-unittest.cc
Normal file
@ -0,0 +1,113 @@
|
||||
// Copyright 2014 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "src/utils.h"
|
||||
#include "testing/gtest-support.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
template <typename T>
|
||||
class UtilsTest : public ::testing::Test {};
|
||||
|
||||
typedef ::testing::Types<signed char, unsigned char,
|
||||
short, // NOLINT(runtime/int)
|
||||
unsigned short, // NOLINT(runtime/int)
|
||||
int, unsigned int, long, // NOLINT(runtime/int)
|
||||
unsigned long, // NOLINT(runtime/int)
|
||||
long long, // NOLINT(runtime/int)
|
||||
unsigned long long, // NOLINT(runtime/int)
|
||||
int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t,
|
||||
int64_t, uint64_t>
|
||||
IntegerTypes;
|
||||
|
||||
TYPED_TEST_CASE(UtilsTest, IntegerTypes);
|
||||
|
||||
TYPED_TEST(UtilsTest, SaturateSub) {
|
||||
TypeParam min = std::numeric_limits<TypeParam>::min();
|
||||
TypeParam max = std::numeric_limits<TypeParam>::max();
|
||||
EXPECT_EQ(SaturateSub<TypeParam>(min, 0), min);
|
||||
EXPECT_EQ(SaturateSub<TypeParam>(max, 0), max);
|
||||
EXPECT_EQ(SaturateSub<TypeParam>(max, min), max);
|
||||
EXPECT_EQ(SaturateSub<TypeParam>(min, max), min);
|
||||
EXPECT_EQ(SaturateSub<TypeParam>(min, max / 3), min);
|
||||
EXPECT_EQ(SaturateSub<TypeParam>(min + 1, 2), min);
|
||||
if (std::numeric_limits<TypeParam>::is_signed) {
|
||||
EXPECT_EQ(SaturateSub<TypeParam>(min, min), static_cast<TypeParam>(0));
|
||||
EXPECT_EQ(SaturateSub<TypeParam>(0, min), max);
|
||||
EXPECT_EQ(SaturateSub<TypeParam>(max / 3, min), max);
|
||||
EXPECT_EQ(SaturateSub<TypeParam>(max / 5, min), max);
|
||||
EXPECT_EQ(SaturateSub<TypeParam>(min / 3, max), min);
|
||||
EXPECT_EQ(SaturateSub<TypeParam>(min / 9, max), min);
|
||||
EXPECT_EQ(SaturateSub<TypeParam>(max, min / 3), max);
|
||||
EXPECT_EQ(SaturateSub<TypeParam>(min, max / 3), min);
|
||||
EXPECT_EQ(SaturateSub<TypeParam>(max / 3 * 2, min / 2), max);
|
||||
EXPECT_EQ(SaturateSub<TypeParam>(min / 3 * 2, max / 2), min);
|
||||
} else {
|
||||
EXPECT_EQ(SaturateSub<TypeParam>(min, min), min);
|
||||
EXPECT_EQ(SaturateSub<TypeParam>(0, min), min);
|
||||
EXPECT_EQ(SaturateSub<TypeParam>(0, max), min);
|
||||
EXPECT_EQ(SaturateSub<TypeParam>(max / 3, max), min);
|
||||
EXPECT_EQ(SaturateSub<TypeParam>(max - 3, max), min);
|
||||
}
|
||||
TypeParam test_cases[] = {static_cast<TypeParam>(min / 23),
|
||||
static_cast<TypeParam>(max / 3),
|
||||
63,
|
||||
static_cast<TypeParam>(min / 6),
|
||||
static_cast<TypeParam>(max / 55),
|
||||
static_cast<TypeParam>(min / 2),
|
||||
static_cast<TypeParam>(max / 2),
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
42};
|
||||
TRACED_FOREACH(TypeParam, x, test_cases) {
|
||||
TRACED_FOREACH(TypeParam, y, test_cases) {
|
||||
if (std::numeric_limits<TypeParam>::is_signed) {
|
||||
EXPECT_EQ(SaturateSub<TypeParam>(x, y), x - y);
|
||||
} else {
|
||||
EXPECT_EQ(SaturateSub<TypeParam>(x, y), y > x ? min : x - y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST(UtilsTest, SaturateAdd) {
|
||||
TypeParam min = std::numeric_limits<TypeParam>::min();
|
||||
TypeParam max = std::numeric_limits<TypeParam>::max();
|
||||
EXPECT_EQ(SaturateAdd<TypeParam>(min, min), min);
|
||||
EXPECT_EQ(SaturateAdd<TypeParam>(max, max), max);
|
||||
EXPECT_EQ(SaturateAdd<TypeParam>(min, min / 3), min);
|
||||
EXPECT_EQ(SaturateAdd<TypeParam>(max / 8 * 7, max / 3 * 2), max);
|
||||
EXPECT_EQ(SaturateAdd<TypeParam>(min / 3 * 2, min / 8 * 7), min);
|
||||
EXPECT_EQ(SaturateAdd<TypeParam>(max / 20 * 18, max / 25 * 18), max);
|
||||
EXPECT_EQ(SaturateAdd<TypeParam>(min / 3 * 2, min / 3 * 2), min);
|
||||
EXPECT_EQ(SaturateAdd<TypeParam>(max - 1, 2), max);
|
||||
EXPECT_EQ(SaturateAdd<TypeParam>(max - 100, 101), max);
|
||||
TypeParam test_cases[] = {static_cast<TypeParam>(min / 23),
|
||||
static_cast<TypeParam>(max / 3),
|
||||
63,
|
||||
static_cast<TypeParam>(min / 6),
|
||||
static_cast<TypeParam>(max / 55),
|
||||
static_cast<TypeParam>(min / 2),
|
||||
static_cast<TypeParam>(max / 2),
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
42};
|
||||
TRACED_FOREACH(TypeParam, x, test_cases) {
|
||||
TRACED_FOREACH(TypeParam, y, test_cases) {
|
||||
EXPECT_EQ(SaturateAdd<TypeParam>(x, y), x + y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
Loading…
Reference in New Issue
Block a user