Commit 2a6a87d7 authored by Djordje.Pesic's avatar Djordje.Pesic Committed by Commit bot

MIPS: Add float instructions and test coverage, part one

Implement assembler, disassembler tests for all instructions for mips32 and mips64. Additionally, add missing single precision float instructions for r2 and r6 architecture variants in assembler, simulator and disassembler with corresponding tests.

Review URL: https://codereview.chromium.org/1119203003

Cr-Commit-Position: refs/heads/master@{#28402}
parent 19a421c6
......@@ -1903,45 +1903,12 @@ void Assembler::movf(Register rd, Register rs, uint16_t cc) {
}
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 fs,
FPURegister ft) {
DCHECK(IsMipsArchVariant(kMips32r6));
DCHECK((fmt == D) || (fmt == S));
GenInstrRegister(COP1, fmt, ft, fs, fd, SELEQZ_C);
}
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 fs,
FPURegister ft) {
DCHECK(IsMipsArchVariant(kMips32r6));
DCHECK((fmt == D) || (fmt == S));
GenInstrRegister(COP1, fmt, ft, fs, fd, SELNEZ_C);
}
// Bit twiddling.
void Assembler::clz(Register rd, Register rs) {
if (!IsMipsArchVariant(kMips32r6)) {
......@@ -2110,10 +2077,127 @@ void Assembler::DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
}
void Assembler::movn_s(FPURegister fd, FPURegister fs, Register rt) {
DCHECK(IsMipsArchVariant(kMips32r2));
GenInstrRegister(COP1, S, rt, fs, fd, MOVN_C);
}
void Assembler::movn_d(FPURegister fd, FPURegister fs, Register rt) {
DCHECK(IsMipsArchVariant(kMips32r2));
GenInstrRegister(COP1, D, rt, fs, fd, MOVN_C);
}
void Assembler::sel(SecondaryField fmt, FPURegister fd, FPURegister fs,
FPURegister ft) {
DCHECK(IsMipsArchVariant(kMips32r6));
DCHECK((fmt == D) || (fmt == S));
GenInstrRegister(COP1, fmt, ft, fs, fd, SEL);
}
void Assembler::sel_s(FPURegister fd, FPURegister fs, FPURegister ft) {
sel(S, fd, fs, ft);
}
void Assembler::sel_d(FPURegister fd, FPURegister fs, FPURegister ft) {
sel(D, fd, fs, ft);
}
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 rd, Register rs, Register rt) {
DCHECK(IsMipsArchVariant(kMips32r6));
GenInstrRegister(SPECIAL, rs, rt, rd, 0, SELNEZ_S);
}
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::seleqz_d(FPURegister fd, FPURegister fs, FPURegister ft) {
seleqz(D, fd, fs, ft);
}
void Assembler::seleqz_s(FPURegister fd, FPURegister fs, FPURegister ft) {
seleqz(S, fd, fs, ft);
}
void Assembler::selnez_d(FPURegister fd, FPURegister fs, FPURegister ft) {
selnez(D, fd, fs, ft);
}
void Assembler::selnez_s(FPURegister fd, FPURegister fs, FPURegister ft) {
selnez(S, fd, fs, ft);
}
void Assembler::movz_s(FPURegister fd, FPURegister fs, Register rt) {
DCHECK(IsMipsArchVariant(kMips32r2));
GenInstrRegister(COP1, S, rt, fs, fd, MOVZ_C);
}
void Assembler::movz_d(FPURegister fd, FPURegister fs, Register rt) {
DCHECK(IsMipsArchVariant(kMips32r2));
GenInstrRegister(COP1, D, rt, fs, fd, MOVZ_C);
}
void Assembler::movt_s(FPURegister fd, FPURegister fs, uint16_t cc) {
DCHECK(IsMipsArchVariant(kMips32r2));
FPURegister ft;
ft.code_ = (cc & 0x0007) << 2 | 1;
GenInstrRegister(COP1, S, ft, fs, fd, MOVF);
}
void Assembler::movt_d(FPURegister fd, FPURegister fs, uint16_t cc) {
DCHECK(IsMipsArchVariant(kMips32r2));
FPURegister ft;
ft.code_ = (cc & 0x0007) << 2 | 1;
GenInstrRegister(COP1, D, ft, fs, fd, MOVF);
}
void Assembler::movf_s(FPURegister fd, FPURegister fs, uint16_t cc) {
DCHECK(IsMipsArchVariant(kMips32r2));
FPURegister ft;
ft.code_ = (cc & 0x0007) << 2 | 0;
GenInstrRegister(COP1, S, ft, fs, fd, MOVF);
}
void Assembler::movf_d(FPURegister fd, FPURegister fs, uint16_t cc) {
DCHECK(IsMipsArchVariant(kMips32r2));
FPURegister ft;
ft.code_ = (cc & 0x0007) << 2 | 0;
GenInstrRegister(COP1, D, ft, fs, fd, MOVF);
}
// Arithmetic.
void Assembler::add_s(FPURegister fd, FPURegister fs, FPURegister ft) {
GenInstrRegister(COP1, S, ft, fs, fd, ADD_D);
GenInstrRegister(COP1, S, ft, fs, fd, ADD_S);
}
......@@ -2123,7 +2207,7 @@ void Assembler::add_d(FPURegister fd, FPURegister fs, FPURegister ft) {
void Assembler::sub_s(FPURegister fd, FPURegister fs, FPURegister ft) {
GenInstrRegister(COP1, S, ft, fs, fd, SUB_D);
GenInstrRegister(COP1, S, ft, fs, fd, SUB_S);
}
......@@ -2133,7 +2217,7 @@ void Assembler::sub_d(FPURegister fd, FPURegister fs, FPURegister ft) {
void Assembler::mul_s(FPURegister fd, FPURegister fs, FPURegister ft) {
GenInstrRegister(COP1, S, ft, fs, fd, MUL_D);
GenInstrRegister(COP1, S, ft, fs, fd, MUL_S);
}
......@@ -2150,7 +2234,7 @@ void Assembler::madd_d(FPURegister fd, FPURegister fr, FPURegister fs,
void Assembler::div_s(FPURegister fd, FPURegister fs, FPURegister ft) {
GenInstrRegister(COP1, S, ft, fs, fd, DIV_D);
GenInstrRegister(COP1, S, ft, fs, fd, DIV_S);
}
......@@ -2160,7 +2244,7 @@ void Assembler::div_d(FPURegister fd, FPURegister fs, FPURegister ft) {
void Assembler::abs_s(FPURegister fd, FPURegister fs) {
GenInstrRegister(COP1, S, f0, fs, fd, ABS_D);
GenInstrRegister(COP1, S, f0, fs, fd, ABS_S);
}
......@@ -2170,12 +2254,17 @@ void Assembler::abs_d(FPURegister fd, FPURegister fs) {
void Assembler::mov_d(FPURegister fd, FPURegister fs) {
GenInstrRegister(COP1, D, f0, fs, fd, MOV_D);
GenInstrRegister(COP1, D, f0, fs, fd, MOV_S);
}
void Assembler::mov_s(FPURegister fd, FPURegister fs) {
GenInstrRegister(COP1, S, f0, fs, fd, MOV_D);
}
void Assembler::neg_s(FPURegister fd, FPURegister fs) {
GenInstrRegister(COP1, S, f0, fs, fd, NEG_D);
GenInstrRegister(COP1, S, f0, fs, fd, NEG_S);
}
......@@ -2185,7 +2274,7 @@ void Assembler::neg_d(FPURegister fd, FPURegister fs) {
void Assembler::sqrt_s(FPURegister fd, FPURegister fs) {
GenInstrRegister(COP1, S, f0, fs, fd, SQRT_D);
GenInstrRegister(COP1, S, f0, fs, fd, SQRT_S);
}
......@@ -2194,6 +2283,26 @@ void Assembler::sqrt_d(FPURegister fd, FPURegister fs) {
}
void Assembler::rsqrt_s(FPURegister fd, FPURegister fs) {
GenInstrRegister(COP1, S, f0, fs, fd, RSQRT_S);
}
void Assembler::rsqrt_d(FPURegister fd, FPURegister fs) {
GenInstrRegister(COP1, D, f0, fs, fd, RSQRT_D);
}
void Assembler::recip_d(FPURegister fd, FPURegister fs) {
GenInstrRegister(COP1, D, f0, fs, fd, RECIP_D);
}
void Assembler::recip_s(FPURegister fd, FPURegister fs) {
GenInstrRegister(COP1, S, f0, fs, fd, RECIP_S);
}
// Conversions.
void Assembler::cvt_w_s(FPURegister fd, FPURegister fs) {
......@@ -2251,6 +2360,7 @@ void Assembler::rint_s(FPURegister fd, FPURegister fs) { rint(S, fd, fs); }
void Assembler::rint(SecondaryField fmt, FPURegister fd, FPURegister fs) {
DCHECK(IsMipsArchVariant(kMips32r6));
DCHECK((fmt == D) || (fmt == S));
GenInstrRegister(COP1, fmt, f0, fs, fd, RINT);
}
......
......@@ -853,13 +853,27 @@ class Assembler : public AssemblerBase {
void movf(Register rd, Register rs, uint16_t cc = 0);
void sel(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
void sel_s(FPURegister fd, FPURegister fs, FPURegister ft);
void sel_d(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);
void seleqz_d(FPURegister fd, FPURegister fs, FPURegister ft);
void seleqz_s(FPURegister fd, FPURegister fs, FPURegister ft);
void selnez_d(FPURegister fd, FPURegister fs, FPURegister ft);
void selnez_s(FPURegister fd, FPURegister fs, FPURegister ft);
void movz_s(FPURegister fd, FPURegister fs, Register rt);
void movz_d(FPURegister fd, FPURegister fs, Register rt);
void movt_s(FPURegister fd, FPURegister fs, uint16_t cc);
void movt_d(FPURegister fd, FPURegister fs, uint16_t cc);
void movf_s(FPURegister fd, FPURegister fs, uint16_t cc);
void movf_d(FPURegister fd, FPURegister fs, uint16_t cc);
void movn_s(FPURegister fd, FPURegister fs, Register rt);
void movn_d(FPURegister fd, FPURegister fs, Register rt);
// Bit twiddling.
void clz(Register rd, Register rs);
void ins_(Register rt, Register rs, uint16_t pos, uint16_t size);
......@@ -896,10 +910,15 @@ class Assembler : public AssemblerBase {
void abs_s(FPURegister fd, FPURegister fs);
void abs_d(FPURegister fd, FPURegister fs);
void mov_d(FPURegister fd, FPURegister fs);
void mov_s(FPURegister fd, FPURegister fs);
void neg_s(FPURegister fd, FPURegister fs);
void neg_d(FPURegister fd, FPURegister fs);
void sqrt_s(FPURegister fd, FPURegister fs);
void sqrt_d(FPURegister fd, FPURegister fs);
void rsqrt_s(FPURegister fd, FPURegister fs);
void rsqrt_d(FPURegister fd, FPURegister fs);
void recip_d(FPURegister fd, FPURegister fs);
void recip_s(FPURegister fd, FPURegister fs);
// Conversion.
void cvt_w_s(FPURegister fd, FPURegister fs);
......
......@@ -457,6 +457,14 @@ enum SecondaryField {
L = ((2 << 3) + 5) << 21,
PS = ((2 << 3) + 6) << 21,
// COP1 Encoding of Function Field When rs=S.
ADD_S = ((0 << 3) + 0),
SUB_S = ((0 << 3) + 1),
MUL_S = ((0 << 3) + 2),
DIV_S = ((0 << 3) + 3),
ABS_S = ((0 << 3) + 5),
SQRT_S = ((0 << 3) + 4),
MOV_S = ((0 << 3) + 6),
NEG_S = ((0 << 3) + 7),
ROUND_L_S = ((1 << 3) + 0),
TRUNC_L_S = ((1 << 3) + 1),
CEIL_L_S = ((1 << 3) + 2),
......@@ -465,6 +473,8 @@ enum SecondaryField {
TRUNC_W_S = ((1 << 3) + 5),
CEIL_W_S = ((1 << 3) + 6),
FLOOR_W_S = ((1 << 3) + 7),
RECIP_S = ((2 << 3) + 5),
RSQRT_S = ((2 << 3) + 6),
CVT_D_S = ((4 << 3) + 1),
CVT_W_S = ((4 << 3) + 4),
CVT_L_S = ((4 << 3) + 5),
......@@ -486,10 +496,8 @@ enum SecondaryField {
TRUNC_W_D = ((1 << 3) + 5),
CEIL_W_D = ((1 << 3) + 6),
FLOOR_W_D = ((1 << 3) + 7),
MIN = ((3 << 3) + 4),
MINA = ((3 << 3) + 5),
MAX = ((3 << 3) + 6),
MAXA = ((3 << 3) + 7),
RECIP_D = ((2 << 3) + 5),
RSQRT_D = ((2 << 3) + 6),
CVT_S_D = ((4 << 3) + 0),
CVT_W_D = ((4 << 3) + 4),
CVT_L_D = ((4 << 3) + 5),
......@@ -543,8 +551,15 @@ enum SecondaryField {
CMP_SUGT = ((3 << 3) + 6), // Reserved, not implemented.
CMP_SOGT = ((3 << 3) + 7), // Reserved, not implemented.
MIN = ((3 << 3) + 4),
MINA = ((3 << 3) + 5),
MAX = ((3 << 3) + 6),
MAXA = ((3 << 3) + 7),
SEL = ((2 << 3) + 0),
MOVZ_C = ((2 << 3) + 2),
MOVN_C = ((2 << 3) + 3),
SELEQZ_C = ((2 << 3) + 4), // COP1 on FPR registers.
MOVF = ((2 << 3) + 1), // Function field for MOVT.fmt and MOVF.fmt
SELNEZ_C = ((2 << 3) + 7), // COP1 on FPR registers.
// COP1 Encoding of Function Field When rs=PS.
// COP1X Encoding of Function Field.
......
......@@ -511,6 +511,19 @@ bool Decoder::DecodeTypeRegisterRsType(Instruction* instr) {
case SELNEZ_C:
Format(instr, "selnez.'t 'fd, 'fs, 'ft");
break;
case MOVZ_C:
Format(instr, "movz.'t 'fd, 'fs, 'rt");
break;
case MOVN_C:
Format(instr, "movn.'t 'fd, 'fs, 'rt");
break;
case MOVF:
if (instr->Bit(16)) {
Format(instr, "movt.'t 'fd, 'fs, 'Cc");
} else {
Format(instr, "movf.'t 'fd, 'fs, 'Cc");
}
break;
case ADD_D:
Format(instr, "add.'t 'fd, 'fs, 'ft");
break;
......@@ -535,6 +548,12 @@ bool Decoder::DecodeTypeRegisterRsType(Instruction* instr) {
case SQRT_D:
Format(instr, "sqrt.'t 'fd, 'fs");
break;
case RECIP_D:
Format(instr, "recip.'t 'fd, 'fs");
break;
case RSQRT_D:
Format(instr, "rsqrt.'t 'fd, 'fs");
break;
case CVT_W_D:
Format(instr, "cvt.w.'t 'fd, 'fs");
break;
......@@ -550,12 +569,21 @@ bool Decoder::DecodeTypeRegisterRsType(Instruction* instr) {
case ROUND_W_D:
Format(instr, "round.w.'t 'fd, 'fs");
break;
case ROUND_L_D:
Format(instr, "round.l.'t 'fd, 'fs");
break;
case FLOOR_W_D:
Format(instr, "floor.w.'t 'fd, 'fs");
break;
case FLOOR_L_D:
Format(instr, "floor.l.'t 'fd, 'fs");
break;
case CEIL_W_D:
Format(instr, "ceil.w.'t 'fd, 'fs");
break;
case CEIL_L_D:
Format(instr, "ceil.l.'t 'fd, 'fs");
break;
case CVT_S_D:
Format(instr, "cvt.s.'t 'fd, 'fs");
break;
......
This diff is collapsed.
......@@ -178,6 +178,9 @@ class Simulator {
void set_fcsr_rounding_mode(FPURoundingMode mode);
unsigned int get_fcsr_rounding_mode();
bool set_fcsr_round_error(double original, double rounded);
bool set_fcsr_round_error(float original, float rounded);
bool set_fcsr_round64_error(double original, double rounded);
bool set_fcsr_round64_error(float original, float rounded);
void round_according_to_fcsr(double toRound, double& rounded,
int32_t& rounded_int, double fs);
// Special case of set_register and get_register to access the raw PC value.
......
......@@ -2140,33 +2140,6 @@ void Assembler::maxa_d(FPURegister fd, FPURegister fs, FPURegister ft) {
}
void Assembler::sel(SecondaryField fmt, FPURegister fd, FPURegister fs,
FPURegister ft) {
DCHECK(kArchVariant == kMips64r6);
DCHECK((fmt == D) || (fmt == S));
Instr instr = COP1 | fmt << kRsShift | ft.code() << kFtShift |
fs.code() << kFsShift | fd.code() << kFdShift | SEL;
emit(instr);
}
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 rd, Register rs, Register rt) {
DCHECK(kArchVariant == kMips64r6);
......@@ -2174,14 +2147,6 @@ void Assembler::seleqz(Register rd, Register rs, Register rt) {
}
// FPR.
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 rd, Register rs, Register rt) {
DCHECK(kArchVariant == kMips64r6);
......@@ -2189,15 +2154,6 @@ void Assembler::selnez(Register rd, Register rs, Register rt) {
}
// FPR.
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);
}
// Bit twiddling.
void Assembler::clz(Register rd, Register rs) {
if (kArchVariant != kMips64r6) {
......@@ -2333,6 +2289,134 @@ void Assembler::DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
}
void Assembler::sel(SecondaryField fmt, FPURegister fd, FPURegister fs,
FPURegister ft) {
DCHECK(kArchVariant == kMips64r6);
DCHECK((fmt == D) || (fmt == S));
GenInstrRegister(COP1, fmt, ft, fs, fd, SEL);
}
void Assembler::sel_s(FPURegister fd, FPURegister fs, FPURegister ft) {
sel(S, fd, fs, ft);
}
void Assembler::sel_d(FPURegister fd, FPURegister fs, FPURegister ft) {
sel(D, fd, fs, ft);
}
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);
}
// FPR.
void Assembler::seleqz(SecondaryField fmt, FPURegister fd, FPURegister fs,
FPURegister ft) {
DCHECK((fmt == D) || (fmt == S));
GenInstrRegister(COP1, fmt, ft, fs, fd, SELEQZ_C);
}
void Assembler::seleqz_d(FPURegister fd, FPURegister fs, FPURegister ft) {
seleqz(D, fd, fs, ft);
}
void Assembler::seleqz_s(FPURegister fd, FPURegister fs, FPURegister ft) {
seleqz(S, fd, fs, ft);
}
void Assembler::selnez_d(FPURegister fd, FPURegister fs, FPURegister ft) {
selnez(D, fd, fs, ft);
}
void Assembler::selnez_s(FPURegister fd, FPURegister fs, FPURegister ft) {
selnez(S, fd, fs, ft);
}
void Assembler::movz_s(FPURegister fd, FPURegister fs, Register rt) {
DCHECK(kArchVariant == kMips64r2);
GenInstrRegister(COP1, S, rt, fs, fd, MOVZ_C);
}
void Assembler::movz_d(FPURegister fd, FPURegister fs, Register rt) {
DCHECK(kArchVariant == kMips64r2);
GenInstrRegister(COP1, D, rt, fs, fd, MOVZ_C);
}
void Assembler::movt_s(FPURegister fd, FPURegister fs, uint16_t cc) {
DCHECK(kArchVariant == kMips64r2);
FPURegister ft;
ft.code_ = (cc & 0x0007) << 2 | 1;
GenInstrRegister(COP1, S, ft, fs, fd, MOVF);
}
void Assembler::movt_d(FPURegister fd, FPURegister fs, uint16_t cc) {
DCHECK(kArchVariant == kMips64r2);
FPURegister ft;
ft.code_ = (cc & 0x0007) << 2 | 1;
GenInstrRegister(COP1, D, ft, fs, fd, MOVF);
}
void Assembler::movf_s(FPURegister fd, FPURegister fs, uint16_t cc) {
DCHECK(kArchVariant == kMips64r2);
FPURegister ft;
ft.code_ = (cc & 0x0007) << 2 | 0;
GenInstrRegister(COP1, S, ft, fs, fd, MOVF);
}
void Assembler::movf_d(FPURegister fd, FPURegister fs, uint16_t cc) {
DCHECK(kArchVariant == kMips64r2);
FPURegister ft;
ft.code_ = (cc & 0x0007) << 2 | 0;
GenInstrRegister(COP1, D, ft, fs, fd, MOVF);
}
void Assembler::movn_s(FPURegister fd, FPURegister fs, Register rt) {
DCHECK(kArchVariant == kMips64r2);
GenInstrRegister(COP1, S, rt, fs, fd, MOVN_C);
}
void Assembler::movn_d(FPURegister fd, FPURegister fs, Register rt) {
DCHECK(kArchVariant == kMips64r2);
GenInstrRegister(COP1, D, rt, fs, fd, MOVN_C);
}
// FPR.
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);
}
// Arithmetic.
void Assembler::add_s(FPURegister fd, FPURegister fs, FPURegister ft) {
......@@ -2396,6 +2480,11 @@ void Assembler::mov_d(FPURegister fd, FPURegister fs) {
}
void Assembler::mov_s(FPURegister fd, FPURegister fs) {
GenInstrRegister(COP1, S, f0, fs, fd, MOV_D);
}
void Assembler::neg_s(FPURegister fd, FPURegister fs) {
GenInstrRegister(COP1, S, f0, fs, fd, NEG_D);
}
......@@ -2416,8 +2505,27 @@ void Assembler::sqrt_d(FPURegister fd, FPURegister fs) {
}
// Conversions.
void Assembler::rsqrt_s(FPURegister fd, FPURegister fs) {
GenInstrRegister(COP1, S, f0, fs, fd, RSQRT_S);
}
void Assembler::rsqrt_d(FPURegister fd, FPURegister fs) {
GenInstrRegister(COP1, D, f0, fs, fd, RSQRT_D);
}
void Assembler::recip_d(FPURegister fd, FPURegister fs) {
GenInstrRegister(COP1, D, f0, fs, fd, RECIP_D);
}
void Assembler::recip_s(FPURegister fd, FPURegister fs) {
GenInstrRegister(COP1, S, f0, fs, fd, RECIP_S);
}
// Conversions.
void Assembler::cvt_w_s(FPURegister fd, FPURegister fs) {
GenInstrRegister(COP1, S, f0, fs, fd, CVT_W_S);
}
......@@ -2476,18 +2584,18 @@ void Assembler::rint_d(FPURegister fd, FPURegister fs) { rint(D, fd, fs); }
void Assembler::rint(SecondaryField fmt, FPURegister fd, FPURegister fs) {
DCHECK(kArchVariant == kMips64r6);
GenInstrRegister(COP1, D, f0, fs, fd, RINT);
GenInstrRegister(COP1, fmt, f0, fs, fd, RINT);
}
void Assembler::cvt_l_s(FPURegister fd, FPURegister fs) {
DCHECK(kArchVariant == kMips64r2);
DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
GenInstrRegister(COP1, S, f0, fs, fd, CVT_L_S);
}
void Assembler::cvt_l_d(FPURegister fd, FPURegister fs) {
DCHECK(kArchVariant == kMips64r2);
DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
GenInstrRegister(COP1, D, f0, fs, fd, CVT_L_D);
}
......@@ -2534,16 +2642,16 @@ void Assembler::ceil_l_d(FPURegister fd, FPURegister fs) {
}
void Assembler::mina(SecondaryField fmt, FPURegister fd, FPURegister ft,
FPURegister fs) {
void Assembler::mina(SecondaryField fmt, FPURegister fd, FPURegister fs,
FPURegister ft) {
DCHECK(kArchVariant == kMips64r6);
DCHECK((fmt == D) || (fmt == S));
GenInstrRegister(COP1, fmt, ft, fs, fd, MINA);
}
void Assembler::maxa(SecondaryField fmt, FPURegister fd, FPURegister ft,
FPURegister fs) {
void Assembler::maxa(SecondaryField fmt, FPURegister fd, FPURegister fs,
FPURegister ft) {
DCHECK(kArchVariant == kMips64r6);
DCHECK((fmt == D) || (fmt == S));
GenInstrRegister(COP1, fmt, ft, fs, fd, MAXA);
......@@ -2556,7 +2664,7 @@ void Assembler::cvt_s_w(FPURegister fd, FPURegister fs) {
void Assembler::cvt_s_l(FPURegister fd, FPURegister fs) {
DCHECK(kArchVariant == kMips64r2);
DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
GenInstrRegister(COP1, L, f0, fs, fd, CVT_S_L);
}
......@@ -2572,7 +2680,7 @@ void Assembler::cvt_d_w(FPURegister fd, FPURegister fs) {
void Assembler::cvt_d_l(FPURegister fd, FPURegister fs) {
DCHECK(kArchVariant == kMips64r2);
DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
GenInstrRegister(COP1, L, f0, fs, fd, CVT_D_L);
}
......@@ -2612,6 +2720,7 @@ void Assembler::c(FPUCondition cond, SecondaryField fmt,
FPURegister fs, FPURegister ft, uint16_t cc) {
DCHECK(kArchVariant != kMips64r6);
DCHECK(is_uint3(cc));
DCHECK(fmt == S || fmt == D);
DCHECK((fmt & ~(31 << kRsShift)) == 0);
Instr instr = COP1 | fmt | ft.code() << kFtShift | fs.code() << kFsShift
| cc << 8 | 3 << 4 | cond;
......
......@@ -881,12 +881,27 @@ class Assembler : public AssemblerBase {
void movf(Register rd, Register rs, uint16_t cc = 0);
void sel(SecondaryField fmt, FPURegister fd, FPURegister fs, FPURegister ft);
void sel_s(FPURegister fd, FPURegister fs, FPURegister ft);
void sel_d(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 fs,
FPURegister ft);
void seleqz_d(FPURegister fd, FPURegister fs, FPURegister ft);
void seleqz_s(FPURegister fd, FPURegister fs, FPURegister ft);
void selnez_d(FPURegister fd, FPURegister fs, FPURegister ft);
void selnez_s(FPURegister fd, FPURegister fs, FPURegister ft);
void movz_s(FPURegister fd, FPURegister fs, Register rt);
void movz_d(FPURegister fd, FPURegister fs, Register rt);
void movt_s(FPURegister fd, FPURegister fs, uint16_t cc);
void movt_d(FPURegister fd, FPURegister fs, uint16_t cc);
void movf_s(FPURegister fd, FPURegister fs, uint16_t cc);
void movf_d(FPURegister fd, FPURegister fs, uint16_t cc);
void movn_s(FPURegister fd, FPURegister fs, Register rt);
void movn_d(FPURegister fd, FPURegister fs, Register rt);
// Bit twiddling.
void clz(Register rd, Register rs);
void ins_(Register rt, Register rs, uint16_t pos, uint16_t size);
......@@ -926,10 +941,15 @@ class Assembler : public AssemblerBase {
void abs_s(FPURegister fd, FPURegister fs);
void abs_d(FPURegister fd, FPURegister fs);
void mov_d(FPURegister fd, FPURegister fs);
void mov_s(FPURegister fd, FPURegister fs);
void neg_s(FPURegister fd, FPURegister fs);
void neg_d(FPURegister fd, FPURegister fs);
void sqrt_s(FPURegister fd, FPURegister fs);
void sqrt_d(FPURegister fd, FPURegister fs);
void rsqrt_s(FPURegister fd, FPURegister fs);
void rsqrt_d(FPURegister fd, FPURegister fs);
void recip_d(FPURegister fd, FPURegister fs);
void recip_s(FPURegister fd, FPURegister fs);
// Conversion.
void cvt_w_s(FPURegister fd, FPURegister fs);
......
......@@ -470,6 +470,14 @@ enum SecondaryField {
L = ((2 << 3) + 5) << 21,
PS = ((2 << 3) + 6) << 21,
// COP1 Encoding of Function Field When rs=S.
ADD_S = ((0 << 3) + 0),
SUB_S = ((0 << 3) + 1),
MUL_S = ((0 << 3) + 2),
DIV_S = ((0 << 3) + 3),
ABS_S = ((0 << 3) + 5),
SQRT_S = ((0 << 3) + 4),
MOV_S = ((0 << 3) + 6),
NEG_S = ((0 << 3) + 7),
ROUND_L_S = ((1 << 3) + 0),
TRUNC_L_S = ((1 << 3) + 1),
CEIL_L_S = ((1 << 3) + 2),
......@@ -478,6 +486,8 @@ enum SecondaryField {
TRUNC_W_S = ((1 << 3) + 5),
CEIL_W_S = ((1 << 3) + 6),
FLOOR_W_S = ((1 << 3) + 7),
RECIP_S = ((2 << 3) + 5),
RSQRT_S = ((2 << 3) + 6),
CVT_D_S = ((4 << 3) + 1),
CVT_W_S = ((4 << 3) + 4),
CVT_L_S = ((4 << 3) + 5),
......@@ -499,10 +509,8 @@ enum SecondaryField {
TRUNC_W_D = ((1 << 3) + 5),
CEIL_W_D = ((1 << 3) + 6),
FLOOR_W_D = ((1 << 3) + 7),
MIN = ((3 << 3) + 4),
MINA = ((3 << 3) + 5),
MAX = ((3 << 3) + 6),
MAXA = ((3 << 3) + 7),
RECIP_D = ((2 << 3) + 5),
RSQRT_D = ((2 << 3) + 6),
CVT_S_D = ((4 << 3) + 0),
CVT_W_D = ((4 << 3) + 4),
CVT_L_D = ((4 << 3) + 5),
......@@ -556,7 +564,14 @@ enum SecondaryField {
CMP_SUGT = ((3 << 3) + 6), // Reserved, not implemented.
CMP_SOGT = ((3 << 3) + 7), // Reserved, not implemented.
MIN = ((3 << 3) + 4),
MINA = ((3 << 3) + 5),
MAX = ((3 << 3) + 6),
MAXA = ((3 << 3) + 7),
SEL = ((2 << 3) + 0),
MOVF = ((2 << 3) + 1), // Function field for MOVT.fmt and MOVF.fmt
MOVZ_C = ((2 << 3) + 2), // COP1 on FPR registers.
MOVN_C = ((2 << 3) + 3), // COP1 on FPR registers.
SELEQZ_C = ((2 << 3) + 4), // COP1 on FPR registers.
SELNEZ_C = ((2 << 3) + 7), // COP1 on FPR registers.
......
......@@ -520,12 +520,28 @@ bool Decoder::DecodeTypeRegisterRsType(Instruction* instr) {
case RINT:
Format(instr, "rint.'t 'fd, 'fs");
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 MOVZ_C:
Format(instr, "movz.'t 'fd, 'fs, 'rt");
break;
case MOVN_C:
Format(instr, "movn.'t 'fd, 'fs, 'rt");
break;
case MOVF:
if (instr->Bit(16)) {
Format(instr, "movt.'t 'fd, 'fs, 'Cc");
} else {
Format(instr, "movf.'t 'fd, 'fs, 'Cc");
}
break;
case MIN:
Format(instr, "min.'t 'fd, 'fs, 'ft");
break;
......@@ -562,6 +578,12 @@ bool Decoder::DecodeTypeRegisterRsType(Instruction* instr) {
case SQRT_D:
Format(instr, "sqrt.'t 'fd, 'fs");
break;
case RECIP_D:
Format(instr, "recip.'t 'fd, 'fs");
break;
case RSQRT_D:
Format(instr, "rsqrt.'t 'fd, 'fs");
break;
case CVT_W_D:
Format(instr, "cvt.w.'t 'fd, 'fs");
break;
......
This diff is collapsed.
......@@ -207,11 +207,14 @@ class Simulator {
bool test_fcsr_bit(uint32_t cc);
bool set_fcsr_round_error(double original, double rounded);
bool set_fcsr_round64_error(double original, double rounded);
bool set_fcsr_round_error(float original, float rounded);
bool set_fcsr_round64_error(float original, float rounded);
void round_according_to_fcsr(double toRound, double& rounded,
int32_t& rounded_int, double fs);
void round64_according_to_fcsr(double toRound, double& rounded,
int64_t& rounded_int, double fs);
void set_fcsr_rounding_mode(FPURoundingMode mode);
unsigned int get_fcsr_rounding_mode();
// Special case of set_register and get_register to access the raw PC value.
void set_pc(int64_t value);
int64_t get_pc() const;
......
This diff is collapsed.
This diff is collapsed.
......@@ -525,21 +525,94 @@ TEST(Type0) {
}
// Tests only seleqz, selnez, seleqz.fmt and selnez.fmt
TEST(Type1) {
SET_UP();
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(seleqz_d(f3, f4, f5), "462520d4 seleqz.d f3, f4, f5");
COMPARE(selnez_d(f3, f4, f5), "462520d7 selnez.d f3, f4, f5");
COMPARE(seleqz_s(f3, f4, f5), "460520d4 seleqz.s f3, f4, f5");
COMPARE(selnez_s(f3, f4, f5), "460520d7 selnez.s 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");
COMPARE(sel_s(f3, f4, f5), "460520d0 sel.s f3, f4, f5");
COMPARE(sel_d(f3, f4, f5), "462520d0 sel.d f3, f4, f5");
COMPARE(rint_d(f8, f6), "4620321a rint.d f8, f6");
COMPARE(rint_s(f8, f6), "4600321a rint.s f8, f6");
COMPARE(min_s(f3, f4, f5), "460520dc min.s f3, f4, f5");
COMPARE(max_s(f3, f4, f5), "460520de max.s f3, f4, f5");
VERIFY_RUN();
COMPARE(mina_d(f3, f4, f5), "462520dd mina.d f3, f4, f5");
COMPARE(mina_s(f3, f4, f5), "460520dd mina.s f3, f4, f5");
COMPARE(maxa_d(f3, f4, f5), "462520df maxa.d f3, f4, f5");
COMPARE(maxa_s(f3, f4, f5), "460520df maxa.s f3, f4, f5");
}
COMPARE(trunc_w_d(f8, f6), "4620320d trunc.w.d f8, f6");
COMPARE(trunc_w_s(f8, f6), "4600320d trunc.w.s f8, f6");
COMPARE(round_w_s(f8, f6), "4600320c round.w.s f8, f6");
COMPARE(round_w_d(f8, f6), "4620320c round.w.d f8, f6");
COMPARE(round_l_s(f8, f6), "46003208 round.l.s f8, f6");
COMPARE(round_l_d(f8, f6), "46203208 round.l.d f8, f6");
COMPARE(floor_w_s(f8, f6), "4600320f floor.w.s f8, f6");
COMPARE(floor_w_d(f8, f6), "4620320f floor.w.d f8, f6");
COMPARE(floor_l_s(f8, f6), "4600320b floor.l.s f8, f6");
COMPARE(floor_l_d(f8, f6), "4620320b floor.l.d f8, f6");
COMPARE(ceil_w_s(f8, f6), "4600320e ceil.w.s f8, f6");
COMPARE(ceil_w_d(f8, f6), "4620320e ceil.w.d f8, f6");
COMPARE(ceil_l_s(f8, f6), "4600320a ceil.l.s f8, f6");
COMPARE(ceil_l_d(f8, f6), "4620320a ceil.l.d f8, f6");
COMPARE(sub_s(f10, f8, f6), "46064281 sub.s f10, f8, f6");
COMPARE(sub_d(f10, f8, f6), "46264281 sub.d f10, f8, f6");
COMPARE(sqrt_s(f8, f6), "46003204 sqrt.s f8, f6");
COMPARE(sqrt_d(f8, f6), "46203204 sqrt.d f8, f6");
COMPARE(neg_s(f8, f6), "46003207 neg.s f8, f6");
COMPARE(neg_d(f8, f6), "46203207 neg.d f8, f6");
COMPARE(mul_s(f8, f6, f4), "46043202 mul.s f8, f6, f4");
COMPARE(mul_d(f8, f6, f4), "46243202 mul.d f8, f6, f4");
COMPARE(rsqrt_s(f8, f6), "46003216 rsqrt.s f8, f6");
COMPARE(rsqrt_d(f8, f6), "46203216 rsqrt.d f8, f6");
COMPARE(recip_s(f8, f6), "46003215 recip.s f8, f6");
COMPARE(recip_d(f8, f6), "46203215 recip.d f8, f6");
COMPARE(mov_s(f6, f4), "46002186 mov.s f6, f4");
COMPARE(mov_d(f6, f4), "46202186 mov.d f6, f4");
if (IsMipsArchVariant(kMips32r2)) {
COMPARE(trunc_l_d(f8, f6), "46203209 trunc.l.d f8, f6");
COMPARE(trunc_l_s(f8, f6), "46003209 trunc.l.s f8, f6");
COMPARE(movz_s(f6, f4, t0), "46082192 movz.s f6, f4, t0");
COMPARE(movz_d(f6, f4, t0), "46282192 movz.d f6, f4, t0");
COMPARE(movt_s(f6, f4, 4), "46112191 movt.s f6, f4, cc(1)");
COMPARE(movt_d(f6, f4, 4), "46312191 movt.d f6, f4, cc(1)");
COMPARE(movf_s(f6, f4, 4), "46102191 movf.s f6, f4, cc(1)");
COMPARE(movf_d(f6, f4, 4), "46302191 movf.d f6, f4, cc(1)");
COMPARE(movn_s(f6, f4, t0), "46082193 movn.s f6, f4, t0");
COMPARE(movn_d(f6, f4, t0), "46282193 movn.d f6, f4, t0");
}
VERIFY_RUN();
}
......@@ -674,18 +674,92 @@ TEST(Type0) {
TEST(Type1) {
SET_UP();
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(seleqz(S, f3, f4, f5), "460520d4 seleqz.s f3, f4, f5");
COMPARE(selnez(S, f3, f4, f5), "460520d7 selnez.s 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");
COMPARE(sel(S, f3, f4, f5), "460520d0 sel.s f3, f4, f5");
COMPARE(sel(D, f3, f4, f5), "462520d0 sel.d f3, f4, f5");
COMPARE(rint_d(f8, f6), "4620321a rint.d f8, f6");
VERIFY_RUN();
COMPARE(min_s(f3, f4, f5), "460520dc min.s f3, f4, f5");
COMPARE(max_s(f3, f4, f5), "460520de max.s f3, f4, f5");
COMPARE(rint(S, f8, f6), "4600321a rint.s f8, f6");
COMPARE(mina_d(f3, f4, f5), "462520dd mina.d f3, f4, f5");
COMPARE(mina_s(f3, f4, f5), "460520dd mina.s f3, f4, f5");
COMPARE(maxa_d(f3, f4, f5), "462520df maxa.d f3, f4, f5");
COMPARE(maxa_s(f3, f4, f5), "460520df maxa.s f3, f4, f5");
}
COMPARE(trunc_w_d(f8, f6), "4620320d trunc.w.d f8, f6");
COMPARE(trunc_w_s(f8, f6), "4600320d trunc.w.s f8, f6");
COMPARE(round_w_s(f8, f6), "4600320c round.w.s f8, f6");
COMPARE(round_w_d(f8, f6), "4620320c round.w.d f8, f6");
COMPARE(round_l_s(f8, f6), "46003208 round.l.s f8, f6");
COMPARE(round_l_d(f8, f6), "46203208 round.l.d f8, f6");
COMPARE(floor_w_s(f8, f6), "4600320f floor.w.s f8, f6");
COMPARE(floor_w_d(f8, f6), "4620320f floor.w.d f8, f6");
COMPARE(floor_l_s(f8, f6), "4600320b floor.l.s f8, f6");
COMPARE(floor_l_d(f8, f6), "4620320b floor.l.d f8, f6");
COMPARE(ceil_w_s(f8, f6), "4600320e ceil.w.s f8, f6");
COMPARE(ceil_w_d(f8, f6), "4620320e ceil.w.d f8, f6");
COMPARE(ceil_l_s(f8, f6), "4600320a ceil.l.s f8, f6");
COMPARE(ceil_l_d(f8, f6), "4620320a ceil.l.d f8, f6");
COMPARE(sub_s(f10, f8, f6), "46064281 sub.s f10, f8, f6");
COMPARE(sub_d(f10, f8, f6), "46264281 sub.d f10, f8, f6");
COMPARE(sqrt_s(f8, f6), "46003204 sqrt.s f8, f6");
COMPARE(sqrt_d(f8, f6), "46203204 sqrt.d f8, f6");
COMPARE(neg_s(f8, f6), "46003207 neg.s f8, f6");
COMPARE(neg_d(f8, f6), "46203207 neg.d f8, f6");
COMPARE(mul_s(f8, f6, f4), "46043202 mul.s f8, f6, f4");
COMPARE(mul_d(f8, f6, f4), "46243202 mul.d f8, f6, f4");
COMPARE(rsqrt_s(f8, f6), "46003216 rsqrt.s f8, f6");
COMPARE(rsqrt_d(f8, f6), "46203216 rsqrt.d f8, f6");
COMPARE(recip_s(f8, f6), "46003215 recip.s f8, f6");
COMPARE(recip_d(f8, f6), "46203215 recip.d f8, f6");
COMPARE(mov_s(f6, f4), "46002186 mov.s f6, f4");
COMPARE(mov_d(f6, f4), "46202186 mov.d f6, f4");
if (kArchVariant == kMips64r2) {
COMPARE(trunc_l_d(f8, f6), "46203209 trunc.l.d f8, f6");
COMPARE(trunc_l_s(f8, f6), "46003209 trunc.l.s f8, f6");
COMPARE(movz_s(f6, f4, t0), "460c2192 movz.s f6, f4, t0");
COMPARE(movz_d(f6, f4, t0), "462c2192 movz.d f6, f4, t0");
COMPARE(movt_s(f6, f4, 4), "46112191 movt.s f6, f4, cc(1)");
COMPARE(movt_d(f6, f4, 4), "46312191 movt.d f6, f4, cc(1)");
COMPARE(movf_s(f6, f4, 4), "46102191 movf.s f6, f4, cc(1)");
COMPARE(movf_d(f6, f4, 4), "46302191 movf.d f6, f4, cc(1)");
COMPARE(movn_s(f6, f4, t0), "460c2193 movn.s f6, f4, t0");
COMPARE(movn_d(f6, f4, t0), "462c2193 movn.d f6, f4, t0");
}
VERIFY_RUN();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment