}
-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);
}
-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);
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);
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);
case BC1: // Branch on coprocessor condition.
case BC1EQZ:
case BC1NEZ:
- case SELEQZ_C:
- case SELNEZ_C:
return kImmediateType;
default:
return kRegisterType;
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);
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;
}
+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:
}
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();
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;
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();
}
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);
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;
}
-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;
}
+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);
}
-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);
}
-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);
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);
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);
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);
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);
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");
}
+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:
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);
}
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();
}
-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:
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();
}
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);
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);
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;
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.
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;
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;
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,
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);
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;
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;
+
+ 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();
- CHECK_EQ(test.i, 0xf3);
- CHECK_EQ(test.j, 0x0);
- CHECK_EQ(test.k, 0);
- CHECK_EQ(test.l, 0xf3);
+ 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));
}
}
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;
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));
}
}
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) {
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();
+ }
+}
}
-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();
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();
+ }
+}