MIPS: Major fixes and clean-up in asm. for instruction encoding.
- Fixed single float register type instruction en[de]coding in assembler and disassembler. - Added max and min instructions for r6 and corresponding tests. - Fixed selection instruction for boundary cases in simulator. - Update assembler tests to be more thorough wrt boundary cases. TEST=cctest/test-assembler-mips64/MIPS17, MIPS18 cctest/test-disasm-mips64/Type1 cctest/test-assembler-mips/MIPS16, MIPS17 cctest/test-disasm-mips/Type1 BUG= Review URL: https://codereview.chromium.org/1057323002 Cr-Commit-Position: refs/heads/master@{#27601}
This commit is contained in:
parent
2fbfc9faec
commit
4b5af7b32e
@ -1903,28 +1903,39 @@ void Assembler::movf(Register rd, Register rs, uint16_t cc) {
|
||||
}
|
||||
|
||||
|
||||
void Assembler::seleqz(Register rs, Register rt, Register rd) {
|
||||
void Assembler::sel(SecondaryField fmt, FPURegister fd, FPURegister fs,
|
||||
FPURegister ft) {
|
||||
DCHECK(IsMipsArchVariant(kMips32r6));
|
||||
DCHECK((fmt == D) || (fmt == S));
|
||||
|
||||
Instr instr = COP1 | fmt << kRsShift | ft.code() << kFtShift |
|
||||
fs.code() << kFsShift | fd.code() << kFdShift | SEL;
|
||||
emit(instr);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::seleqz(Register rd, Register rs, Register rt) {
|
||||
DCHECK(IsMipsArchVariant(kMips32r6));
|
||||
GenInstrRegister(SPECIAL, rs, rt, rd, 0, SELEQZ_S);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::seleqz(SecondaryField fmt, FPURegister fd, FPURegister ft,
|
||||
FPURegister fs) {
|
||||
void Assembler::seleqz(SecondaryField fmt, FPURegister fd, FPURegister fs,
|
||||
FPURegister ft) {
|
||||
DCHECK(IsMipsArchVariant(kMips32r6));
|
||||
DCHECK((fmt == D) || (fmt == S));
|
||||
GenInstrRegister(COP1, fmt, ft, fs, fd, SELEQZ_C);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::selnez(Register rs, Register rt, Register rd) {
|
||||
void Assembler::selnez(Register rd, Register rs, Register rt) {
|
||||
DCHECK(IsMipsArchVariant(kMips32r6));
|
||||
GenInstrRegister(SPECIAL, rs, rt, rd, 0, SELNEZ_S);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::selnez(SecondaryField fmt, FPURegister fd, FPURegister ft,
|
||||
FPURegister fs) {
|
||||
void Assembler::selnez(SecondaryField fmt, FPURegister fd, FPURegister fs,
|
||||
FPURegister ft) {
|
||||
DCHECK(IsMipsArchVariant(kMips32r6));
|
||||
DCHECK((fmt == D) || (fmt == S));
|
||||
GenInstrRegister(COP1, fmt, ft, fs, fd, SELNEZ_C);
|
||||
@ -2244,32 +2255,32 @@ void Assembler::ceil_l_d(FPURegister fd, FPURegister fs) {
|
||||
}
|
||||
|
||||
|
||||
void Assembler::min(SecondaryField fmt, FPURegister fd, FPURegister ft,
|
||||
FPURegister fs) {
|
||||
void Assembler::min(SecondaryField fmt, FPURegister fd, FPURegister fs,
|
||||
FPURegister ft) {
|
||||
DCHECK(IsMipsArchVariant(kMips32r6));
|
||||
DCHECK((fmt == D) || (fmt == S));
|
||||
GenInstrRegister(COP1, fmt, ft, fs, fd, MIN);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::mina(SecondaryField fmt, FPURegister fd, FPURegister ft,
|
||||
FPURegister fs) {
|
||||
void Assembler::mina(SecondaryField fmt, FPURegister fd, FPURegister fs,
|
||||
FPURegister ft) {
|
||||
DCHECK(IsMipsArchVariant(kMips32r6));
|
||||
DCHECK((fmt == D) || (fmt == S));
|
||||
GenInstrRegister(COP1, fmt, ft, fs, fd, MINA);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::max(SecondaryField fmt, FPURegister fd, FPURegister ft,
|
||||
FPURegister fs) {
|
||||
void Assembler::max(SecondaryField fmt, FPURegister fd, FPURegister fs,
|
||||
FPURegister ft) {
|
||||
DCHECK(IsMipsArchVariant(kMips32r6));
|
||||
DCHECK((fmt == D) || (fmt == S));
|
||||
GenInstrRegister(COP1, fmt, ft, fs, fd, MAX);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::maxa(SecondaryField fmt, FPURegister fd, FPURegister ft,
|
||||
FPURegister fs) {
|
||||
void Assembler::maxa(SecondaryField fmt, FPURegister fd, FPURegister fs,
|
||||
FPURegister ft) {
|
||||
DCHECK(IsMipsArchVariant(kMips32r6));
|
||||
DCHECK((fmt == D) || (fmt == S));
|
||||
GenInstrRegister(COP1, fmt, ft, fs, fd, MAXA);
|
||||
|
@ -852,14 +852,13 @@ class Assembler : public AssemblerBase {
|
||||
void movt(Register rd, Register rs, uint16_t cc = 0);
|
||||
void movf(Register rd, Register rs, uint16_t cc = 0);
|
||||
|
||||
void sel(SecondaryField fmt, FPURegister fd, FPURegister ft,
|
||||
FPURegister fs, uint8_t sel);
|
||||
void seleqz(Register rs, Register rt, Register rd);
|
||||
void seleqz(SecondaryField fmt, FPURegister fd, FPURegister ft,
|
||||
FPURegister fs);
|
||||
void selnez(Register rs, Register rt, Register rd);
|
||||
void selnez(SecondaryField fmt, FPURegister fd, FPURegister ft,
|
||||
FPURegister fs);
|
||||
void sel(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
|
||||
void seleqz(Register rd, Register rs, Register rt);
|
||||
void seleqz(SecondaryField fmt, FPURegister fd, FPURegister fs,
|
||||
FPURegister ft);
|
||||
void selnez(Register rd, Register rs, Register rt);
|
||||
void selnez(SecondaryField fmt, FPURegister fd, FPURegister fs,
|
||||
FPURegister ft);
|
||||
|
||||
// Bit twiddling.
|
||||
void clz(Register rd, Register rs);
|
||||
@ -924,10 +923,10 @@ class Assembler : public AssemblerBase {
|
||||
void ceil_l_s(FPURegister fd, FPURegister fs);
|
||||
void ceil_l_d(FPURegister fd, FPURegister fs);
|
||||
|
||||
void min(SecondaryField fmt, FPURegister fd, FPURegister ft, FPURegister fs);
|
||||
void mina(SecondaryField fmt, FPURegister fd, FPURegister ft, FPURegister fs);
|
||||
void max(SecondaryField fmt, FPURegister fd, FPURegister ft, FPURegister fs);
|
||||
void maxa(SecondaryField fmt, FPURegister fd, FPURegister ft, FPURegister fs);
|
||||
void min(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
|
||||
void mina(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
|
||||
void max(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
|
||||
void maxa(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
|
||||
|
||||
void cvt_s_w(FPURegister fd, FPURegister fs);
|
||||
void cvt_s_l(FPURegister fd, FPURegister fs);
|
||||
|
@ -282,8 +282,6 @@ Instruction::Type Instruction::InstructionType() const {
|
||||
case BC1: // Branch on coprocessor condition.
|
||||
case BC1EQZ:
|
||||
case BC1NEZ:
|
||||
case SELEQZ_C:
|
||||
case SELNEZ_C:
|
||||
return kImmediateType;
|
||||
default:
|
||||
return kRegisterType;
|
||||
|
@ -106,6 +106,7 @@ class Decoder {
|
||||
void DecodeTypeRegisterSRsType(Instruction* instr);
|
||||
void DecodeTypeRegisterDRsType(Instruction* instr);
|
||||
void DecodeTypeRegisterLRsType(Instruction* instr);
|
||||
void DecodeTypeRegisterWRsType(Instruction* instr);
|
||||
void DecodeTypeRegisterSPECIAL(Instruction* instr);
|
||||
void DecodeTypeRegisterSPECIAL2(Instruction* instr);
|
||||
void DecodeTypeRegisterSPECIAL3(Instruction* instr);
|
||||
@ -486,6 +487,27 @@ void Decoder::Unknown(Instruction* instr) {
|
||||
|
||||
bool Decoder::DecodeTypeRegisterRsType(Instruction* instr) {
|
||||
switch (instr->FunctionFieldRaw()) {
|
||||
case MIN:
|
||||
Format(instr, "min.'t 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case MAX:
|
||||
Format(instr, "max.'t 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case MINA:
|
||||
Format(instr, "mina.'t 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case MAXA:
|
||||
Format(instr, "maxa.'t 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case SEL:
|
||||
Format(instr, "sel.'t 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case SELEQZ_C:
|
||||
Format(instr, "seleqz.'t 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case SELNEZ_C:
|
||||
Format(instr, "selnez.'t 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case ADD_D:
|
||||
Format(instr, "add.'t 'fd, 'fs, 'ft");
|
||||
break;
|
||||
@ -630,6 +652,53 @@ void Decoder::DecodeTypeRegisterLRsType(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeTypeRegisterWRsType(Instruction* instr) {
|
||||
switch (instr->FunctionValue()) {
|
||||
case CVT_S_W: // Convert word to float (single).
|
||||
Format(instr, "cvt.s.w 'fd, 'fs");
|
||||
break;
|
||||
case CVT_D_W: // Convert word to double.
|
||||
Format(instr, "cvt.d.w 'fd, 'fs");
|
||||
break;
|
||||
case CMP_AF:
|
||||
Format(instr, "cmp.af.s 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case CMP_UN:
|
||||
Format(instr, "cmp.un.s 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case CMP_EQ:
|
||||
Format(instr, "cmp.eq.s 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case CMP_UEQ:
|
||||
Format(instr, "cmp.ueq.s 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case CMP_LT:
|
||||
Format(instr, "cmp.lt.s 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case CMP_ULT:
|
||||
Format(instr, "cmp.ult.s 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case CMP_LE:
|
||||
Format(instr, "cmp.le.s 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case CMP_ULE:
|
||||
Format(instr, "cmp.ule.s 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case CMP_OR:
|
||||
Format(instr, "cmp.or.s 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case CMP_UNE:
|
||||
Format(instr, "cmp.une.s 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case CMP_NE:
|
||||
Format(instr, "cmp.ne.s 'fd, 'fs, 'ft");
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeTypeRegisterSPECIAL(Instruction* instr) {
|
||||
switch (instr->FunctionFieldRaw()) {
|
||||
case JR:
|
||||
@ -805,10 +874,10 @@ void Decoder::DecodeTypeRegisterSPECIAL(Instruction* instr) {
|
||||
}
|
||||
break;
|
||||
case SELEQZ_S:
|
||||
Format(instr, "seleqz 'rs, 'rt, 'rd");
|
||||
Format(instr, "seleqz 'rd, 'rs, 'rt");
|
||||
break;
|
||||
case SELNEZ_S:
|
||||
Format(instr, "selnez 'rs, 'rt, 'rd");
|
||||
Format(instr, "selnez 'rd, 'rs, 'rt");
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
@ -888,21 +957,12 @@ void Decoder::DecodeTypeRegister(Instruction* instr) {
|
||||
case D:
|
||||
DecodeTypeRegisterDRsType(instr);
|
||||
break;
|
||||
case W:
|
||||
switch (instr->FunctionFieldRaw()) {
|
||||
case CVT_S_W: // Convert word to float (single).
|
||||
Format(instr, "cvt.s.w 'fd, 'fs");
|
||||
break;
|
||||
case CVT_D_W: // Convert word to double.
|
||||
Format(instr, "cvt.d.w 'fd, 'fs");
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
case L:
|
||||
DecodeTypeRegisterLRsType(instr);
|
||||
break;
|
||||
case W:
|
||||
DecodeTypeRegisterWRsType(instr);
|
||||
break;
|
||||
case PS:
|
||||
UNIMPLEMENTED_MIPS();
|
||||
break;
|
||||
@ -951,138 +1011,6 @@ void Decoder::DecodeTypeImmediate(Instruction* instr) {
|
||||
case BC1NEZ:
|
||||
Format(instr, "bc1nez 'ft, 'imm16u");
|
||||
break;
|
||||
case W: // CMP.S instruction.
|
||||
switch (instr->FunctionValue()) {
|
||||
case CMP_AF:
|
||||
Format(instr, "cmp.af.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_UN:
|
||||
Format(instr, "cmp.un.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_EQ:
|
||||
Format(instr, "cmp.eq.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_UEQ:
|
||||
Format(instr, "cmp.ueq.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_LT:
|
||||
Format(instr, "cmp.lt.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_ULT:
|
||||
Format(instr, "cmp.ult.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_LE:
|
||||
Format(instr, "cmp.le.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_ULE:
|
||||
Format(instr, "cmp.ule.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_OR:
|
||||
Format(instr, "cmp.or.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_UNE:
|
||||
Format(instr, "cmp.une.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_NE:
|
||||
Format(instr, "cmp.ne.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
case L: // CMP.D instruction.
|
||||
switch (instr->FunctionValue()) {
|
||||
case CMP_AF:
|
||||
Format(instr, "cmp.af.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_UN:
|
||||
Format(instr, "cmp.un.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_EQ:
|
||||
Format(instr, "cmp.eq.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_UEQ:
|
||||
Format(instr, "cmp.ueq.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_LT:
|
||||
Format(instr, "cmp.lt.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_ULT:
|
||||
Format(instr, "cmp.ult.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_LE:
|
||||
Format(instr, "cmp.le.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_ULE:
|
||||
Format(instr, "cmp.ule.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_OR:
|
||||
Format(instr, "cmp.or.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_UNE:
|
||||
Format(instr, "cmp.une.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_NE:
|
||||
Format(instr, "cmp.ne.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
case S:
|
||||
switch (instr->FunctionValue()) {
|
||||
case SEL:
|
||||
Format(instr, "sel.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case SELEQZ_C:
|
||||
Format(instr, "seleqz.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case SELNEZ_C:
|
||||
Format(instr, "selnez.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case MIN:
|
||||
Format(instr, "min.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case MINA:
|
||||
Format(instr, "mina.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case MAX:
|
||||
Format(instr, "max.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case MAXA:
|
||||
Format(instr, "maxa.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
case D:
|
||||
switch (instr->FunctionValue()) {
|
||||
case SEL:
|
||||
Format(instr, "sel.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case SELEQZ_C:
|
||||
Format(instr, "seleqz.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case SELNEZ_C:
|
||||
Format(instr, "selnez.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case MIN:
|
||||
Format(instr, "min.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case MINA:
|
||||
Format(instr, "mina.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case MAX:
|
||||
Format(instr, "max.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case MAXA:
|
||||
Format(instr, "maxa.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
@ -2137,15 +2137,20 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr,
|
||||
const int32_t& fs_reg,
|
||||
const int32_t& ft_reg,
|
||||
const int32_t& fd_reg) {
|
||||
double ft, fs;
|
||||
double ft, fs, fd;
|
||||
uint32_t cc, fcsr_cc;
|
||||
int64_t i64;
|
||||
fs = get_fpu_register_double(fs_reg);
|
||||
ft = get_fpu_register_double(ft_reg);
|
||||
int64_t ft_int = static_cast<int64_t>(ft);
|
||||
int64_t ft_int = bit_cast<int64_t>(ft);
|
||||
int64_t fd_int = bit_cast<int64_t>(fd);
|
||||
cc = instr->FCccValue();
|
||||
fcsr_cc = get_fcsr_condition_bit(cc);
|
||||
switch (instr->FunctionFieldRaw()) {
|
||||
case SEL:
|
||||
DCHECK(IsMipsArchVariant(kMips32r6));
|
||||
set_fpu_register_double(fd_reg, (fd_int & 0x1) == 0 ? fs : ft);
|
||||
break;
|
||||
case SELEQZ_C:
|
||||
DCHECK(IsMipsArchVariant(kMips32r6));
|
||||
set_fpu_register_double(fd_reg, (ft_int & 0x1) == 0 ? fs : 0.0);
|
||||
@ -2154,6 +2159,33 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr,
|
||||
DCHECK(IsMipsArchVariant(kMips32r6));
|
||||
set_fpu_register_double(fd_reg, (ft_int & 0x1) != 0 ? fs : 0.0);
|
||||
break;
|
||||
case MIN:
|
||||
DCHECK(IsMipsArchVariant(kMips32r6));
|
||||
fs = get_fpu_register_double(fs_reg);
|
||||
if (std::isnan(fs) && std::isnan(ft)) {
|
||||
set_fpu_register_double(fd_reg, fs);
|
||||
} else if (std::isnan(fs) && !std::isnan(ft)) {
|
||||
set_fpu_register_double(fd_reg, ft);
|
||||
} else if (!std::isnan(fs) && std::isnan(ft)) {
|
||||
set_fpu_register_double(fd_reg, fs);
|
||||
} else {
|
||||
set_fpu_register_double(fd_reg, (fs >= ft) ? ft : fs);
|
||||
}
|
||||
break;
|
||||
case MAX:
|
||||
DCHECK(IsMipsArchVariant(kMips32r6));
|
||||
fs = get_fpu_register_double(fs_reg);
|
||||
if (std::isnan(fs) && std::isnan(ft)) {
|
||||
set_fpu_register_double(fd_reg, fs);
|
||||
} else if (std::isnan(fs) && !std::isnan(ft)) {
|
||||
set_fpu_register_double(fd_reg, ft);
|
||||
} else if (!std::isnan(fs) && std::isnan(ft)) {
|
||||
set_fpu_register_double(fd_reg, fs);
|
||||
} else {
|
||||
set_fpu_register_double(fd_reg, (fs <= ft) ? ft : fs);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case ADD_D:
|
||||
set_fpu_register_double(fd_reg, fs + ft);
|
||||
break;
|
||||
|
@ -2100,11 +2100,10 @@ void Assembler::movf(Register rd, Register rs, uint16_t cc) {
|
||||
}
|
||||
|
||||
|
||||
void Assembler::sel(SecondaryField fmt, FPURegister fd,
|
||||
FPURegister ft, FPURegister fs, uint8_t sel) {
|
||||
void Assembler::sel(SecondaryField fmt, FPURegister fd, FPURegister fs,
|
||||
FPURegister ft) {
|
||||
DCHECK(kArchVariant == kMips64r6);
|
||||
DCHECK(fmt == D);
|
||||
DCHECK(fmt == S);
|
||||
DCHECK((fmt == D) || (fmt == S));
|
||||
|
||||
Instr instr = COP1 | fmt << kRsShift | ft.code() << kFtShift |
|
||||
fs.code() << kFsShift | fd.code() << kFdShift | SEL;
|
||||
@ -2112,31 +2111,47 @@ void Assembler::sel(SecondaryField fmt, FPURegister fd,
|
||||
}
|
||||
|
||||
|
||||
void Assembler::max(SecondaryField fmt, FPURegister fd, FPURegister fs,
|
||||
FPURegister ft) {
|
||||
DCHECK(kArchVariant == kMips64r6);
|
||||
DCHECK((fmt == D) || (fmt == S));
|
||||
GenInstrRegister(COP1, fmt, ft, fs, fd, MAX);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::min(SecondaryField fmt, FPURegister fd, FPURegister fs,
|
||||
FPURegister ft) {
|
||||
DCHECK(kArchVariant == kMips64r6);
|
||||
DCHECK((fmt == D) || (fmt == S));
|
||||
GenInstrRegister(COP1, fmt, ft, fs, fd, MIN);
|
||||
}
|
||||
|
||||
|
||||
// GPR.
|
||||
void Assembler::seleqz(Register rs, Register rt, Register rd) {
|
||||
void Assembler::seleqz(Register rd, Register rs, Register rt) {
|
||||
DCHECK(kArchVariant == kMips64r6);
|
||||
GenInstrRegister(SPECIAL, rs, rt, rd, 0, SELEQZ_S);
|
||||
}
|
||||
|
||||
|
||||
// FPR.
|
||||
void Assembler::seleqz(SecondaryField fmt, FPURegister fd,
|
||||
FPURegister ft, FPURegister fs) {
|
||||
void Assembler::seleqz(SecondaryField fmt, FPURegister fd, FPURegister fs,
|
||||
FPURegister ft) {
|
||||
DCHECK((fmt == D) || (fmt == S));
|
||||
GenInstrRegister(COP1, fmt, ft, fs, fd, SELEQZ_C);
|
||||
}
|
||||
|
||||
|
||||
// GPR.
|
||||
void Assembler::selnez(Register rs, Register rt, Register rd) {
|
||||
void Assembler::selnez(Register rd, Register rs, Register rt) {
|
||||
DCHECK(kArchVariant == kMips64r6);
|
||||
GenInstrRegister(SPECIAL, rs, rt, rd, 0, SELNEZ_S);
|
||||
}
|
||||
|
||||
|
||||
// FPR.
|
||||
void Assembler::selnez(SecondaryField fmt, FPURegister fd,
|
||||
FPURegister ft, FPURegister fs) {
|
||||
void Assembler::selnez(SecondaryField fmt, FPURegister fd, FPURegister fs,
|
||||
FPURegister ft) {
|
||||
DCHECK(kArchVariant == kMips64r6);
|
||||
DCHECK((fmt == D) || (fmt == S));
|
||||
GenInstrRegister(COP1, fmt, ft, fs, fd, SELNEZ_C);
|
||||
@ -2442,14 +2457,6 @@ void Assembler::ceil_l_d(FPURegister fd, FPURegister fs) {
|
||||
}
|
||||
|
||||
|
||||
void Assembler::min(SecondaryField fmt, FPURegister fd, FPURegister ft,
|
||||
FPURegister fs) {
|
||||
DCHECK(kArchVariant == kMips64r6);
|
||||
DCHECK((fmt == D) || (fmt == S));
|
||||
GenInstrRegister(COP1, fmt, ft, fs, fd, MIN);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::mina(SecondaryField fmt, FPURegister fd, FPURegister ft,
|
||||
FPURegister fs) {
|
||||
DCHECK(kArchVariant == kMips64r6);
|
||||
@ -2458,14 +2465,6 @@ void Assembler::mina(SecondaryField fmt, FPURegister fd, FPURegister ft,
|
||||
}
|
||||
|
||||
|
||||
void Assembler::max(SecondaryField fmt, FPURegister fd, FPURegister ft,
|
||||
FPURegister fs) {
|
||||
DCHECK(kArchVariant == kMips64r6);
|
||||
DCHECK((fmt == D) || (fmt == S));
|
||||
GenInstrRegister(COP1, fmt, ft, fs, fd, MAX);
|
||||
}
|
||||
|
||||
|
||||
void Assembler::maxa(SecondaryField fmt, FPURegister fd, FPURegister ft,
|
||||
FPURegister fs) {
|
||||
DCHECK(kArchVariant == kMips64r6);
|
||||
|
@ -880,15 +880,13 @@ class Assembler : public AssemblerBase {
|
||||
void movt(Register rd, Register rs, uint16_t cc = 0);
|
||||
void movf(Register rd, Register rs, uint16_t cc = 0);
|
||||
|
||||
void sel(SecondaryField fmt, FPURegister fd, FPURegister ft,
|
||||
FPURegister fs, uint8_t sel);
|
||||
void seleqz(Register rs, Register rt, Register rd);
|
||||
void seleqz(SecondaryField fmt, FPURegister fd, FPURegister ft,
|
||||
FPURegister fs);
|
||||
void sel(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
|
||||
void seleqz(Register rd, Register rs, Register rt);
|
||||
void seleqz(SecondaryField fmt, FPURegister fd, FPURegister fs,
|
||||
FPURegister ft);
|
||||
void selnez(Register rs, Register rt, Register rd);
|
||||
void selnez(SecondaryField fmt, FPURegister fd, FPURegister ft,
|
||||
FPURegister fs);
|
||||
|
||||
void selnez(SecondaryField fmt, FPURegister fd, FPURegister fs,
|
||||
FPURegister ft);
|
||||
// Bit twiddling.
|
||||
void clz(Register rd, Register rs);
|
||||
void ins_(Register rt, Register rs, uint16_t pos, uint16_t size);
|
||||
@ -955,10 +953,10 @@ class Assembler : public AssemblerBase {
|
||||
void ceil_l_s(FPURegister fd, FPURegister fs);
|
||||
void ceil_l_d(FPURegister fd, FPURegister fs);
|
||||
|
||||
void min(SecondaryField fmt, FPURegister fd, FPURegister ft, FPURegister fs);
|
||||
void mina(SecondaryField fmt, FPURegister fd, FPURegister ft, FPURegister fs);
|
||||
void max(SecondaryField fmt, FPURegister fd, FPURegister ft, FPURegister fs);
|
||||
void maxa(SecondaryField fmt, FPURegister fd, FPURegister ft, FPURegister fs);
|
||||
void min(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
|
||||
void mina(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
|
||||
void max(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
|
||||
void maxa(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
|
||||
|
||||
void cvt_s_w(FPURegister fd, FPURegister fs);
|
||||
void cvt_s_l(FPURegister fd, FPURegister fs);
|
||||
|
@ -106,6 +106,7 @@ class Decoder {
|
||||
void DecodeTypeRegisterSRsType(Instruction* instr);
|
||||
void DecodeTypeRegisterDRsType(Instruction* instr);
|
||||
void DecodeTypeRegisterLRsType(Instruction* instr);
|
||||
void DecodeTypeRegisterWRsType(Instruction* instr);
|
||||
void DecodeTypeRegisterSPECIAL(Instruction* instr);
|
||||
void DecodeTypeRegisterSPECIAL2(Instruction* instr);
|
||||
void DecodeTypeRegisterSPECIAL3(Instruction* instr);
|
||||
@ -113,10 +114,6 @@ class Decoder {
|
||||
void DecodeTypeRegisterCOP1X(Instruction* instr);
|
||||
int DecodeTypeRegister(Instruction* instr);
|
||||
|
||||
void DecodeTypeImmediateCOP1W(Instruction* instr);
|
||||
void DecodeTypeImmediateCOP1L(Instruction* instr);
|
||||
void DecodeTypeImmediateCOP1S(Instruction* instr);
|
||||
void DecodeTypeImmediateCOP1D(Instruction* instr);
|
||||
void DecodeTypeImmediateCOP1(Instruction* instr);
|
||||
void DecodeTypeImmediateREGIMM(Instruction* instr);
|
||||
void DecodeTypeImmediate(Instruction* instr);
|
||||
@ -521,10 +518,22 @@ int Decoder::DecodeBreakInstr(Instruction* instr) {
|
||||
bool Decoder::DecodeTypeRegisterRsType(Instruction* instr) {
|
||||
switch (instr->FunctionFieldRaw()) {
|
||||
case SELEQZ_C:
|
||||
Format(instr, "seleqz.'t 'ft, 'fs, 'fd");
|
||||
Format(instr, "seleqz.'t 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case SELNEZ_C:
|
||||
Format(instr, "selnez.'t 'ft, 'fs, 'fd");
|
||||
Format(instr, "selnez.'t 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case MIN:
|
||||
Format(instr, "min.'t 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case MAX:
|
||||
Format(instr, "max.'t 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case MINA:
|
||||
Format(instr, "mina.'t 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case MAXA:
|
||||
Format(instr, "maxa.'t 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case ADD_D:
|
||||
Format(instr, "add.'t 'fd, 'fs, 'ft");
|
||||
@ -679,6 +688,53 @@ void Decoder::DecodeTypeRegisterLRsType(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeTypeRegisterWRsType(Instruction* instr) {
|
||||
switch (instr->FunctionValue()) {
|
||||
case CVT_S_W: // Convert word to float (single).
|
||||
Format(instr, "cvt.s.w 'fd, 'fs");
|
||||
break;
|
||||
case CVT_D_W: // Convert word to double.
|
||||
Format(instr, "cvt.d.w 'fd, 'fs");
|
||||
break;
|
||||
case CMP_AF:
|
||||
Format(instr, "cmp.af.s 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case CMP_UN:
|
||||
Format(instr, "cmp.un.s 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case CMP_EQ:
|
||||
Format(instr, "cmp.eq.s 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case CMP_UEQ:
|
||||
Format(instr, "cmp.ueq.s 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case CMP_LT:
|
||||
Format(instr, "cmp.lt.s 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case CMP_ULT:
|
||||
Format(instr, "cmp.ult.s 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case CMP_LE:
|
||||
Format(instr, "cmp.le.s 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case CMP_ULE:
|
||||
Format(instr, "cmp.ule.s 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case CMP_OR:
|
||||
Format(instr, "cmp.or.s 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case CMP_UNE:
|
||||
Format(instr, "cmp.une.s 'fd, 'fs, 'ft");
|
||||
break;
|
||||
case CMP_NE:
|
||||
Format(instr, "cmp.ne.s 'fd, 'fs, 'ft");
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeTypeRegisterCOP1(Instruction* instr) {
|
||||
switch (instr->RsFieldRaw()) {
|
||||
case MFC1:
|
||||
@ -713,13 +769,7 @@ void Decoder::DecodeTypeRegisterCOP1(Instruction* instr) {
|
||||
DecodeTypeRegisterDRsType(instr);
|
||||
break;
|
||||
case W:
|
||||
switch (instr->FunctionFieldRaw()) {
|
||||
case CVT_D_W: // Convert word to double.
|
||||
Format(instr, "cvt.d.w 'fd, 'fs");
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
DecodeTypeRegisterWRsType(instr);
|
||||
break;
|
||||
case L:
|
||||
DecodeTypeRegisterLRsType(instr);
|
||||
@ -1013,10 +1063,10 @@ void Decoder::DecodeTypeRegisterSPECIAL(Instruction* instr) {
|
||||
}
|
||||
break;
|
||||
case SELEQZ_S:
|
||||
Format(instr, "seleqz 'rs, 'rt, 'rd");
|
||||
Format(instr, "seleqz 'rd, 'rs, 'rt");
|
||||
break;
|
||||
case SELNEZ_S:
|
||||
Format(instr, "selnez 'rs, 'rt, 'rd");
|
||||
Format(instr, "selnez 'rd, 'rs, 'rt");
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
@ -1090,146 +1140,6 @@ int Decoder::DecodeTypeRegister(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeTypeImmediateCOP1D(Instruction* instr) {
|
||||
switch (instr->FunctionValue()) {
|
||||
case SEL:
|
||||
Format(instr, "sel.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case SELEQZ_C:
|
||||
Format(instr, "seleqz.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case SELNEZ_C:
|
||||
Format(instr, "selnez.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case MIN:
|
||||
Format(instr, "min.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case MINA:
|
||||
Format(instr, "mina.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case MAX:
|
||||
Format(instr, "max.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case MAXA:
|
||||
Format(instr, "maxa.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeTypeImmediateCOP1L(Instruction* instr) {
|
||||
switch (instr->FunctionValue()) {
|
||||
case CMP_AF:
|
||||
Format(instr, "cmp.af.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_UN:
|
||||
Format(instr, "cmp.un.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_EQ:
|
||||
Format(instr, "cmp.eq.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_UEQ:
|
||||
Format(instr, "cmp.ueq.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_LT:
|
||||
Format(instr, "cmp.lt.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_ULT:
|
||||
Format(instr, "cmp.ult.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_LE:
|
||||
Format(instr, "cmp.le.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_ULE:
|
||||
Format(instr, "cmp.ule.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_OR:
|
||||
Format(instr, "cmp.or.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_UNE:
|
||||
Format(instr, "cmp.une.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_NE:
|
||||
Format(instr, "cmp.ne.D 'ft, 'fs, 'fd");
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeTypeImmediateCOP1S(Instruction* instr) {
|
||||
switch (instr->FunctionValue()) {
|
||||
case SEL:
|
||||
Format(instr, "sel.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case SELEQZ_C:
|
||||
Format(instr, "seleqz.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case SELNEZ_C:
|
||||
Format(instr, "selnez.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case MIN:
|
||||
Format(instr, "min.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case MINA:
|
||||
Format(instr, "mina.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case MAX:
|
||||
Format(instr, "max.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case MAXA:
|
||||
Format(instr, "maxa.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeTypeImmediateCOP1W(Instruction* instr) {
|
||||
switch (instr->FunctionValue()) {
|
||||
case CMP_AF:
|
||||
Format(instr, "cmp.af.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_UN:
|
||||
Format(instr, "cmp.un.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_EQ:
|
||||
Format(instr, "cmp.eq.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_UEQ:
|
||||
Format(instr, "cmp.ueq.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_LT:
|
||||
Format(instr, "cmp.lt.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_ULT:
|
||||
Format(instr, "cmp.ult.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_LE:
|
||||
Format(instr, "cmp.le.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_ULE:
|
||||
Format(instr, "cmp.ule.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_OR:
|
||||
Format(instr, "cmp.or.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_UNE:
|
||||
Format(instr, "cmp.une.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
case CMP_NE:
|
||||
Format(instr, "cmp.ne.S 'ft, 'fs, 'fd");
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeTypeImmediateCOP1(Instruction* instr) {
|
||||
switch (instr->RsFieldRaw()) {
|
||||
case BC1:
|
||||
@ -1245,18 +1155,6 @@ void Decoder::DecodeTypeImmediateCOP1(Instruction* instr) {
|
||||
case BC1NEZ:
|
||||
Format(instr, "bc1nez 'ft, 'imm16u");
|
||||
break;
|
||||
case W: // CMP.S instruction.
|
||||
DecodeTypeImmediateCOP1W(instr);
|
||||
break;
|
||||
case L: // CMP.D instruction.
|
||||
DecodeTypeImmediateCOP1L(instr);
|
||||
break;
|
||||
case S:
|
||||
DecodeTypeImmediateCOP1S(instr);
|
||||
break;
|
||||
case D:
|
||||
DecodeTypeImmediateCOP1D(instr);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
@ -2273,7 +2273,7 @@ void Simulator::ConfigureTypeRegister(Instruction* instr,
|
||||
void Simulator::DecodeTypeRegisterSRsType(Instruction* instr,
|
||||
const int32_t& fs_reg,
|
||||
const int32_t& ft_reg,
|
||||
const int64_t& fd_reg) {
|
||||
const int32_t& fd_reg) {
|
||||
float fs, ft;
|
||||
fs = get_fpu_register_float(fs_reg);
|
||||
ft = get_fpu_register_float(ft_reg);
|
||||
@ -2339,16 +2339,22 @@ void Simulator::DecodeTypeRegisterSRsType(Instruction* instr,
|
||||
|
||||
void Simulator::DecodeTypeRegisterDRsType(Instruction* instr,
|
||||
const int32_t& fs_reg,
|
||||
const int64_t& ft_reg,
|
||||
const int32_t& ft_reg,
|
||||
const int32_t& fd_reg) {
|
||||
double ft, fs;
|
||||
double ft, fs, fd;
|
||||
uint32_t cc, fcsr_cc;
|
||||
fs = get_fpu_register_double(fs_reg);
|
||||
ft = get_fpu_register_double(ft_reg);
|
||||
fd = get_fpu_register_double(fd_reg);
|
||||
cc = instr->FCccValue();
|
||||
fcsr_cc = get_fcsr_condition_bit(cc);
|
||||
int64_t ft_int = static_cast<int64_t>(ft);
|
||||
int64_t ft_int = bit_cast<int64_t>(ft);
|
||||
int64_t fd_int = bit_cast<int64_t>(fd);
|
||||
switch (instr->FunctionFieldRaw()) {
|
||||
case SEL:
|
||||
DCHECK(kArchVariant == kMips64r6);
|
||||
set_fpu_register_double(fd_reg, (fd_int & 0x1) == 0 ? fs : ft);
|
||||
break;
|
||||
case SELEQZ_C:
|
||||
DCHECK(kArchVariant == kMips64r6);
|
||||
set_fpu_register_double(fd_reg, (ft_int & 0x1) == 0 ? fs : 0.0);
|
||||
@ -2357,6 +2363,32 @@ void Simulator::DecodeTypeRegisterDRsType(Instruction* instr,
|
||||
DCHECK(kArchVariant == kMips64r6);
|
||||
set_fpu_register_double(fd_reg, (ft_int & 0x1) != 0 ? fs : 0.0);
|
||||
break;
|
||||
case MIN:
|
||||
DCHECK(kArchVariant == kMips64r6);
|
||||
fs = get_fpu_register_double(fs_reg);
|
||||
if (std::isnan(fs) && std::isnan(ft)) {
|
||||
set_fpu_register_double(fd_reg, fs);
|
||||
} else if (std::isnan(fs) && !std::isnan(ft)) {
|
||||
set_fpu_register_double(fd_reg, ft);
|
||||
} else if (!std::isnan(fs) && std::isnan(ft)) {
|
||||
set_fpu_register_double(fd_reg, fs);
|
||||
} else {
|
||||
set_fpu_register_double(fd_reg, (fs >= ft) ? ft : fs);
|
||||
}
|
||||
break;
|
||||
case MAX:
|
||||
DCHECK(kArchVariant == kMips64r6);
|
||||
fs = get_fpu_register_double(fs_reg);
|
||||
if (std::isnan(fs) && std::isnan(ft)) {
|
||||
set_fpu_register_double(fd_reg, fs);
|
||||
} else if (std::isnan(fs) && !std::isnan(ft)) {
|
||||
set_fpu_register_double(fd_reg, ft);
|
||||
} else if (!std::isnan(fs) && std::isnan(ft)) {
|
||||
set_fpu_register_double(fd_reg, fs);
|
||||
} else {
|
||||
set_fpu_register_double(fd_reg, (fs <= ft) ? ft : fs);
|
||||
}
|
||||
break;
|
||||
case ADD_D:
|
||||
set_fpu_register_double(fd_reg, fs + ft);
|
||||
break;
|
||||
@ -2595,10 +2627,10 @@ void Simulator::DecodeTypeRegisterLRsType(Instruction* instr,
|
||||
|
||||
|
||||
void Simulator::DecodeTypeRegisterCOP1(
|
||||
Instruction* instr, const int64_t& rs_reg, const int64_t& rs,
|
||||
const uint64_t& rs_u, const int64_t& rt_reg, const int64_t& rt,
|
||||
const uint64_t& rt_u, const int64_t& rd_reg, const int32_t& fr_reg,
|
||||
const int32_t& fs_reg, const int32_t& ft_reg, const int64_t& fd_reg,
|
||||
Instruction* instr, const int32_t& rs_reg, const int64_t& rs,
|
||||
const uint64_t& rs_u, const int32_t& rt_reg, const int64_t& rt,
|
||||
const uint64_t& rt_u, const int32_t& rd_reg, const int32_t& fr_reg,
|
||||
const int32_t& fs_reg, const int32_t& ft_reg, const int32_t& fd_reg,
|
||||
int64_t& alu_out) {
|
||||
switch (instr->RsFieldRaw()) {
|
||||
case BC1: // Branch on coprocessor condition.
|
||||
@ -2652,7 +2684,7 @@ void Simulator::DecodeTypeRegisterCOP1X(Instruction* instr,
|
||||
const int32_t& fr_reg,
|
||||
const int32_t& fs_reg,
|
||||
const int32_t& ft_reg,
|
||||
const int64_t& fd_reg) {
|
||||
const int32_t& fd_reg) {
|
||||
switch (instr->FunctionFieldRaw()) {
|
||||
case MADD_D:
|
||||
double fr, ft, fs;
|
||||
@ -2886,10 +2918,10 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
|
||||
const uint64_t rt_u = static_cast<uint32_t>(rt);
|
||||
const int64_t rd_reg = instr->RdValue();
|
||||
|
||||
const int32_t fr_reg = instr->FrValue();
|
||||
const int32_t fs_reg = instr->FsValue();
|
||||
const int32_t ft_reg = instr->FtValue();
|
||||
const int64_t fd_reg = instr->FdValue();
|
||||
const int32_t fr_reg = instr->FrValue();
|
||||
const int32_t fs_reg = instr->FsValue();
|
||||
const int32_t ft_reg = instr->FtValue();
|
||||
const int32_t fd_reg = instr->FdValue();
|
||||
int64_t i64hilo = 0;
|
||||
uint64_t u64hilo = 0;
|
||||
|
||||
|
@ -313,17 +313,17 @@ class Simulator {
|
||||
inline int32_t SetDoubleLOW(double* addr);
|
||||
|
||||
// functions called from DecodeTypeRegister
|
||||
void DecodeTypeRegisterCOP1(Instruction* instr, const int64_t& rs_reg,
|
||||
void DecodeTypeRegisterCOP1(Instruction* instr, const int32_t& rs_reg,
|
||||
const int64_t& rs, const uint64_t& rs_u,
|
||||
const int64_t& rt_reg, const int64_t& rt,
|
||||
const uint64_t& rt_u, const int64_t& rd_reg,
|
||||
const int32_t& rt_reg, const int64_t& rt,
|
||||
const uint64_t& rt_u, const int32_t& rd_reg,
|
||||
const int32_t& fr_reg, const int32_t& fs_reg,
|
||||
const int32_t& ft_reg, const int64_t& fd_reg,
|
||||
const int32_t& ft_reg, const int32_t& fd_reg,
|
||||
int64_t& alu_out);
|
||||
|
||||
void DecodeTypeRegisterCOP1X(Instruction* instr, const int32_t& fr_reg,
|
||||
const int32_t& fs_reg, const int32_t& ft_reg,
|
||||
const int64_t& fd_reg);
|
||||
const int32_t& fd_reg);
|
||||
|
||||
void DecodeTypeRegisterSPECIAL(
|
||||
Instruction* instr, const int64_t& rs_reg, const int64_t& rs,
|
||||
@ -341,10 +341,10 @@ class Simulator {
|
||||
int64_t& alu_out);
|
||||
|
||||
void DecodeTypeRegisterSRsType(Instruction* instr, const int32_t& fs_reg,
|
||||
const int32_t& ft_reg, const int64_t& fd_reg);
|
||||
const int32_t& ft_reg, const int32_t& fd_reg);
|
||||
|
||||
void DecodeTypeRegisterDRsType(Instruction* instr, const int32_t& fs_reg,
|
||||
const int64_t& ft_reg, const int32_t& fd_reg);
|
||||
const int32_t& ft_reg, const int32_t& fd_reg);
|
||||
|
||||
void DecodeTypeRegisterWRsType(Instruction* instr, const int32_t& fs_reg,
|
||||
const int32_t& fd_reg, int64_t& alu_out);
|
||||
|
@ -1342,53 +1342,26 @@ TEST(MIPS16) {
|
||||
double f;
|
||||
double g;
|
||||
double h;
|
||||
double i;
|
||||
double j;
|
||||
double k;
|
||||
double l;
|
||||
} Test;
|
||||
|
||||
Test test;
|
||||
// Integer part of test.
|
||||
__ addiu(t1, zero_reg, 1); // t1 = 1
|
||||
__ seleqz(t1, zero_reg, t3); // t3 = 1
|
||||
__ seleqz(t3, t1, zero_reg); // t3 = 1
|
||||
__ sw(t3, MemOperand(a0, OFFSET_OF(Test, a))); // a = 1
|
||||
__ seleqz(t1, t1, t2); // t2 = 0
|
||||
__ seleqz(t2, t1, t1); // t2 = 0
|
||||
__ sw(t2, MemOperand(a0, OFFSET_OF(Test, b))); // b = 0
|
||||
__ selnez(t1, zero_reg, t3); // t3 = 1;
|
||||
__ selnez(t3, t1, zero_reg); // t3 = 1;
|
||||
__ sw(t3, MemOperand(a0, OFFSET_OF(Test, c))); // c = 0
|
||||
__ selnez(t1, t1, t3); // t3 = 1
|
||||
__ selnez(t3, t1, t1); // t3 = 1
|
||||
__ sw(t3, MemOperand(a0, OFFSET_OF(Test, d))); // d = 1
|
||||
// Floating point part of test S format.
|
||||
__ li(t0, 0x80);
|
||||
__ mtc1(t0, f4);
|
||||
__ cvt_d_w(f4, f4); // f4 = 0x80
|
||||
__ li(t0, 0xf3);
|
||||
__ mtc1(t0, f6);
|
||||
__ cvt_d_w(f6, f6); // f6 = 0xf3
|
||||
__ seleqz(S, f8, f4, f6); // f8 = 0xf3
|
||||
__ seleqz(S, f10, f6, f6); // f10 = 0
|
||||
__ sdc1(f8, MemOperand(a0, OFFSET_OF(Test, e))); // e = 0xf3
|
||||
__ sdc1(f10, MemOperand(a0, OFFSET_OF(Test, f))); // f = 0
|
||||
__ selnez(S, f8, f4, f6); // f8 = 0
|
||||
__ selnez(S, f10, f6, f6); // f10 = 0xf3
|
||||
__ sdc1(f8, MemOperand(a0, OFFSET_OF(Test, g))); // g = 0
|
||||
__ sdc1(f10, MemOperand(a0, OFFSET_OF(Test, h))); // h = 0xf3
|
||||
|
||||
__ li(t0, 0x80);
|
||||
__ mtc1(t0, f4);
|
||||
__ cvt_d_w(f4, f4); // f4 = 0x80
|
||||
__ li(t0, 0xf3);
|
||||
__ mtc1(t0, f6);
|
||||
__ cvt_d_w(f6, f6); // f6 = 0xf3
|
||||
__ seleqz(D, f8, f4, f6); // f8 = 0xf3
|
||||
__ seleqz(D, f10, f6, f6); // f10 = 0
|
||||
__ sdc1(f8, MemOperand(a0, OFFSET_OF(Test, i))); // i = 0xf3
|
||||
__ sdc1(f10, MemOperand(a0, OFFSET_OF(Test, j))); // j = 0
|
||||
__ selnez(S, f8, f4, f6); // f8 = 0
|
||||
__ selnez(S, f10, f6, f6); // f10 = 0xf3
|
||||
__ sdc1(f8, MemOperand(a0, OFFSET_OF(Test, k))); // k = 0
|
||||
__ sdc1(f10, MemOperand(a0, OFFSET_OF(Test, l))); // l = 0xf3
|
||||
// Floating point part of test.
|
||||
__ ldc1(f0, MemOperand(a0, OFFSET_OF(Test, e)) ); // src
|
||||
__ ldc1(f2, MemOperand(a0, OFFSET_OF(Test, f)) ); // test
|
||||
__ seleqz(D, f4, f0, f2);
|
||||
__ selnez(D, f6, f0, f2);
|
||||
__ sdc1(f4, MemOperand(a0, OFFSET_OF(Test, g)) ); // src
|
||||
__ sdc1(f6, MemOperand(a0, OFFSET_OF(Test, h)) ); // src
|
||||
__ jr(ra);
|
||||
__ nop();
|
||||
CodeDesc desc;
|
||||
@ -1404,15 +1377,92 @@ TEST(MIPS16) {
|
||||
CHECK_EQ(test.c, 0);
|
||||
CHECK_EQ(test.d, 1);
|
||||
|
||||
CHECK_EQ(test.e, 0xf3);
|
||||
CHECK_EQ(test.f, 0x0);
|
||||
CHECK_EQ(test.g, 0);
|
||||
CHECK_EQ(test.h, 0xf3);
|
||||
const int test_size = 3;
|
||||
const int input_size = 5;
|
||||
|
||||
CHECK_EQ(test.i, 0xf3);
|
||||
CHECK_EQ(test.j, 0x0);
|
||||
CHECK_EQ(test.k, 0);
|
||||
CHECK_EQ(test.l, 0xf3);
|
||||
double inputs[input_size] = {0.0, 65.2, -70.32,
|
||||
18446744073709551621.0, -18446744073709551621.0};
|
||||
double outputs[input_size] = {0.0, 65.2, -70.32,
|
||||
18446744073709551621.0, -18446744073709551621.0};
|
||||
double tests[test_size*2] = {2.8, 2.9, -2.8, -2.9,
|
||||
18446744073709551616.0, 18446744073709555712.0};
|
||||
for (int j=0;j < test_size;j+=2) {
|
||||
for (int i=0;i < input_size;i++) {
|
||||
test.e = inputs[i];
|
||||
test.f = tests[j];
|
||||
(CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
|
||||
CHECK_EQ(test.g, outputs[i]);
|
||||
CHECK_EQ(test.h, 0);
|
||||
|
||||
test.f = tests[j+1];
|
||||
(CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
|
||||
CHECK_EQ(test.g, 0);
|
||||
CHECK_EQ(test.h, outputs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(MIPS17) {
|
||||
if (IsMipsArchVariant(kMips32r6)) {
|
||||
CcTest::InitializeVM();
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
HandleScope scope(isolate);
|
||||
MacroAssembler assm(isolate, NULL, 0);
|
||||
|
||||
typedef struct test_float {
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double d;
|
||||
} TestFloat;
|
||||
|
||||
TestFloat test;
|
||||
|
||||
__ ldc1(f4, MemOperand(a0, OFFSET_OF(TestFloat, a)));
|
||||
__ ldc1(f8, MemOperand(a0, OFFSET_OF(TestFloat, b)));
|
||||
__ min(D, f10, f8, f4);
|
||||
__ max(D, f12, f8, f4);
|
||||
__ sdc1(f10, MemOperand(a0, OFFSET_OF(TestFloat, c)));
|
||||
__ sdc1(f12, MemOperand(a0, OFFSET_OF(TestFloat, d)));
|
||||
__ jr(ra);
|
||||
__ nop();
|
||||
|
||||
CodeDesc desc;
|
||||
assm.GetCode(&desc);
|
||||
Handle<Code> code = isolate->factory()->NewCode(
|
||||
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
|
||||
F3 f = FUNCTION_CAST<F3>(code->entry());
|
||||
test.a = 2.0; // a goes to fs
|
||||
test.b = 3.0; // b goes to ft
|
||||
(CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
|
||||
CHECK_EQ(test.c, 2.0);
|
||||
CHECK_EQ(test.d, 3.0);
|
||||
|
||||
test.a = 3.0; // a goes to fs
|
||||
test.b = 2.0; // b goes to ft
|
||||
(CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
|
||||
CHECK_EQ(test.c, 2.0);
|
||||
CHECK_EQ(test.d, 3.0);
|
||||
|
||||
test.a = std::numeric_limits<double>::quiet_NaN();
|
||||
test.b = 3.0; // b goes to ft
|
||||
(CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
|
||||
CHECK_EQ(test.c, 3.0);
|
||||
CHECK_EQ(test.d, 3.0);
|
||||
|
||||
test.b = std::numeric_limits<double>::quiet_NaN();
|
||||
test.a = 3.0; // b goes to ft
|
||||
(CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
|
||||
CHECK_EQ(test.c, 3.0);
|
||||
CHECK_EQ(test.d, 3.0);
|
||||
|
||||
test.a = std::numeric_limits<double>::quiet_NaN();
|
||||
test.b = std::numeric_limits<double>::quiet_NaN();
|
||||
(CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
|
||||
DCHECK(std::isnan(test.c));
|
||||
DCHECK(std::isnan(test.d));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1448,38 +1448,30 @@ TEST(MIPS17) {
|
||||
int b;
|
||||
int c;
|
||||
int d;
|
||||
double i;
|
||||
double j;
|
||||
double k;
|
||||
double l;
|
||||
double e;
|
||||
double f;
|
||||
double g;
|
||||
double h;
|
||||
} Test;
|
||||
|
||||
Test test;
|
||||
// Integer part of test.
|
||||
__ addiu(t1, zero_reg, 1); // t1 = 1
|
||||
__ seleqz(t1, zero_reg, t3); // t3 = 1
|
||||
__ seleqz(t3, t1, zero_reg); // t3 = 1
|
||||
__ sw(t3, MemOperand(a0, OFFSET_OF(Test, a))); // a = 1
|
||||
__ seleqz(t1, t1, t2); // t2 = 0
|
||||
__ seleqz(t2, t1, t1); // t2 = 0
|
||||
__ sw(t2, MemOperand(a0, OFFSET_OF(Test, b))); // b = 0
|
||||
__ selnez(t1, zero_reg, t3); // t3 = 1;
|
||||
__ selnez(t3, t1, zero_reg); // t3 = 1;
|
||||
__ sw(t3, MemOperand(a0, OFFSET_OF(Test, c))); // c = 0
|
||||
__ selnez(t1, t1, t3); // t3 = 1
|
||||
__ selnez(t3, t1, t1); // t3 = 1
|
||||
__ sw(t3, MemOperand(a0, OFFSET_OF(Test, d))); // d = 1
|
||||
// Floating point part of test.
|
||||
__ li(t0, 0x80);
|
||||
__ mtc1(t0, f4);
|
||||
__ cvt_d_w(f4, f4); // f4=0x80
|
||||
__ li(t0, 0xf3);
|
||||
__ mtc1(t0, f6);
|
||||
__ cvt_d_w(f6, f6); // f6 = 0xf3
|
||||
__ seleqz(D, f8, f4, f6); // f8 = 0xf3
|
||||
__ seleqz(D, f10, f6, f6); // f10 = 0
|
||||
__ sdc1(f8, MemOperand(a0, OFFSET_OF(Test, i))); // i = 0xf3
|
||||
__ sdc1(f10, MemOperand(a0, OFFSET_OF(Test, j))); // j = 0
|
||||
__ selnez(D, f8, f4, f6); // f8 = 0
|
||||
__ selnez(D, f10, f6, f6); // f10 = 0xf3
|
||||
__ sdc1(f8, MemOperand(a0, OFFSET_OF(Test, k))); // k = 0
|
||||
__ sdc1(f10, MemOperand(a0, OFFSET_OF(Test, l))); // l = 0xf3
|
||||
__ ldc1(f0, MemOperand(a0, OFFSET_OF(Test, e)) ); // src
|
||||
__ ldc1(f2, MemOperand(a0, OFFSET_OF(Test, f)) ); // test
|
||||
__ seleqz(D, f4, f0, f2);
|
||||
__ selnez(D, f6, f0, f2);
|
||||
__ sdc1(f4, MemOperand(a0, OFFSET_OF(Test, g)) ); // src
|
||||
__ sdc1(f6, MemOperand(a0, OFFSET_OF(Test, h)) ); // src
|
||||
__ jr(ra);
|
||||
__ nop();
|
||||
CodeDesc desc;
|
||||
@ -1495,10 +1487,92 @@ TEST(MIPS17) {
|
||||
CHECK_EQ(test.c, 0);
|
||||
CHECK_EQ(test.d, 1);
|
||||
|
||||
CHECK_EQ(test.i, 0xf3);
|
||||
CHECK_EQ(test.j, 0x0);
|
||||
CHECK_EQ(test.k, 0);
|
||||
CHECK_EQ(test.l, 0xf3);
|
||||
const int test_size = 3;
|
||||
const int input_size = 5;
|
||||
|
||||
double inputs[input_size] = {0.0, 65.2, -70.32,
|
||||
18446744073709551621.0, -18446744073709551621.0};
|
||||
double outputs[input_size] = {0.0, 65.2, -70.32,
|
||||
18446744073709551621.0, -18446744073709551621.0};
|
||||
double tests[test_size*2] = {2.8, 2.9, -2.8, -2.9,
|
||||
18446744073709551616.0, 18446744073709555712.0};
|
||||
for (int j=0;j < test_size;j+=2) {
|
||||
for (int i=0;i < input_size;i++) {
|
||||
test.e = inputs[i];
|
||||
test.f = tests[j];
|
||||
(CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
|
||||
CHECK_EQ(test.g, outputs[i]);
|
||||
CHECK_EQ(test.h, 0);
|
||||
|
||||
test.f = tests[j+1];
|
||||
(CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
|
||||
CHECK_EQ(test.g, 0);
|
||||
CHECK_EQ(test.h, outputs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(MIPS18) {
|
||||
if (kArchVariant == kMips64r6) {
|
||||
CcTest::InitializeVM();
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
HandleScope scope(isolate);
|
||||
MacroAssembler assm(isolate, NULL, 0);
|
||||
|
||||
typedef struct test_float {
|
||||
double a;
|
||||
double b;
|
||||
double c;
|
||||
double d;
|
||||
} TestFloat;
|
||||
|
||||
TestFloat test;
|
||||
|
||||
__ ldc1(f4, MemOperand(a0, OFFSET_OF(TestFloat, a)));
|
||||
__ ldc1(f8, MemOperand(a0, OFFSET_OF(TestFloat, b)));
|
||||
__ min(D, f10, f8, f4);
|
||||
__ max(D, f12, f8, f4);
|
||||
__ sdc1(f10, MemOperand(a0, OFFSET_OF(TestFloat, c)));
|
||||
__ sdc1(f12, MemOperand(a0, OFFSET_OF(TestFloat, d)));
|
||||
__ jr(ra);
|
||||
__ nop();
|
||||
|
||||
CodeDesc desc;
|
||||
assm.GetCode(&desc);
|
||||
Handle<Code> code = isolate->factory()->NewCode(
|
||||
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
|
||||
F3 f = FUNCTION_CAST<F3>(code->entry());
|
||||
test.a = 2.0; // a goes to fs
|
||||
test.b = 3.0; // b goes to ft
|
||||
(CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
|
||||
CHECK_EQ(test.c, 2.0);
|
||||
CHECK_EQ(test.d, 3.0);
|
||||
|
||||
test.a = 3.0; // a goes to fs
|
||||
test.b = 2.0; // b goes to ft
|
||||
(CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
|
||||
CHECK_EQ(test.c, 2.0);
|
||||
CHECK_EQ(test.d, 3.0);
|
||||
|
||||
test.a = std::numeric_limits<double>::quiet_NaN();
|
||||
test.b = 3.0; // b goes to ft
|
||||
(CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
|
||||
CHECK_EQ(test.c, 3.0);
|
||||
CHECK_EQ(test.d, 3.0);
|
||||
|
||||
test.b = std::numeric_limits<double>::quiet_NaN();
|
||||
test.a = 3.0; // b goes to ft
|
||||
(CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
|
||||
CHECK_EQ(test.c, 3.0);
|
||||
CHECK_EQ(test.d, 3.0);
|
||||
|
||||
test.a = std::numeric_limits<double>::quiet_NaN();
|
||||
test.b = std::numeric_limits<double>::quiet_NaN();
|
||||
(CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
|
||||
DCHECK(std::isnan(test.c));
|
||||
DCHECK(std::isnan(test.d));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,20 +90,6 @@ bool DisassembleAndCompare(byte* pc, const char* compare_string) {
|
||||
if (failure) { \
|
||||
V8_Fatal(__FILE__, __LINE__, "MIPS Disassembler tests failed.\n"); \
|
||||
}
|
||||
// tests only seleqz, selnez, seleqz.fmt and selnez.fmt
|
||||
TEST(Type1) {
|
||||
SET_UP();
|
||||
if (IsMipsArchVariant(kMips32r6)) {
|
||||
COMPARE(seleqz(a0, a1, a2), "00853035 seleqz a0, a1, a2");
|
||||
COMPARE(selnez(a0, a1, a2), "00853037 selnez a0, a1, a2");
|
||||
|
||||
COMPARE(seleqz(S, f0, f1, f2), "45000894 seleqz.S f0, f1, f2");
|
||||
COMPARE(selnez(S, f0, f1, f2), "45000897 selnez.S f0, f1, f2");
|
||||
COMPARE(seleqz(D, f3, f4, f5), "00853035 seleqz.D f3, f4, f5");
|
||||
COMPARE(selnez(D, f3, f4, f5), "00853037 selnez.D f3, f4, f5");
|
||||
}
|
||||
VERIFY_RUN();
|
||||
}
|
||||
|
||||
|
||||
TEST(Type0) {
|
||||
@ -537,3 +523,21 @@ TEST(Type0) {
|
||||
|
||||
VERIFY_RUN();
|
||||
}
|
||||
|
||||
|
||||
// Tests only seleqz, selnez, seleqz.fmt and selnez.fmt
|
||||
TEST(Type1) {
|
||||
if (IsMipsArchVariant(kMips32r6)) {
|
||||
SET_UP();
|
||||
COMPARE(seleqz(a0, a1, a2), "00a62035 seleqz a0, a1, a2");
|
||||
COMPARE(selnez(a0, a1, a2), "00a62037 selnez a0, a1, a2");
|
||||
|
||||
|
||||
COMPARE(seleqz(D, f3, f4, f5), "462520d4 seleqz.d f3, f4, f5");
|
||||
COMPARE(selnez(D, f3, f4, f5), "462520d7 selnez.d f3, f4, f5");
|
||||
|
||||
COMPARE(min(D, f3, f4, f5), "462520dc min.d f3, f4, f5");
|
||||
COMPARE(max(D, f3, f4, f5), "462520de max.d f3, f4, f5");
|
||||
VERIFY_RUN();
|
||||
}
|
||||
}
|
||||
|
@ -92,25 +92,6 @@ if (failure) { \
|
||||
}
|
||||
|
||||
|
||||
TEST(Type1) {
|
||||
if (kArchVariant == kMips64r6) {
|
||||
SET_UP();
|
||||
COMPARE(seleqz(a0, a1, a2), "00853035 seleqz a0, a1, a2");
|
||||
COMPARE(selnez(a0, a1, a2), "00853037 selnez a0, a1, a2");
|
||||
|
||||
|
||||
COMPARE(seleqz(D, f3, f4, f5), "462428d4 seleqz.D f4, f5, f3");
|
||||
COMPARE(selnez(D, f3, f4, f5), "462428d7 selnez.D f4, f5, f3");
|
||||
|
||||
/*COMPARE(min(D, f3, f4, f5),
|
||||
"462428dc min.D f4, f5, f3");
|
||||
COMPARE(max(D, f3, f4, f5),
|
||||
"462428de max.D f4, f5, f3");*/
|
||||
VERIFY_RUN();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(Type0) {
|
||||
SET_UP();
|
||||
|
||||
@ -690,3 +671,20 @@ TEST(Type0) {
|
||||
|
||||
VERIFY_RUN();
|
||||
}
|
||||
|
||||
|
||||
TEST(Type1) {
|
||||
if (kArchVariant == kMips64r6) {
|
||||
SET_UP();
|
||||
COMPARE(seleqz(a0, a1, a2), "00a62035 seleqz a0, a1, a2");
|
||||
COMPARE(selnez(a0, a1, a2), "00a62037 selnez a0, a1, a2");
|
||||
|
||||
|
||||
COMPARE(seleqz(D, f3, f4, f5), "462520d4 seleqz.d f3, f4, f5");
|
||||
COMPARE(selnez(D, f3, f4, f5), "462520d7 selnez.d f3, f4, f5");
|
||||
|
||||
COMPARE(min(D, f3, f4, f5), "462520dc min.d f3, f4, f5");
|
||||
COMPARE(max(D, f3, f4, f5), "462520de max.d f3, f4, f5");
|
||||
VERIFY_RUN();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user