A64: Implement FMINNM (scalar)
This commit is contained in:
parent
1c9804ea07
commit
0575e7421b
6 changed files with 98 additions and 1 deletions
|
@ -551,6 +551,75 @@ void EmitX64::EmitFPMin64(EmitContext& ctx, IR::Inst* inst) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void EmitX64::EmitFPMinNumeric32(EmitContext& ctx, IR::Inst* inst) {
|
||||||
|
FPThreeOp32(code, ctx, inst, [&](Xbyak::Xmm result, Xbyak::Xmm operand, Xbyak::Reg32 scratch, Xbyak::Label& end){
|
||||||
|
Xbyak::Label normal, normal_or_equal, result_is_result;
|
||||||
|
|
||||||
|
code.ucomiss(result, operand);
|
||||||
|
code.jnp(normal_or_equal);
|
||||||
|
// If operand == QNaN, result = result.
|
||||||
|
code.movd(scratch, operand);
|
||||||
|
code.shl(scratch, 1);
|
||||||
|
code.cmp(scratch, 0xff800000u);
|
||||||
|
code.jae(result_is_result);
|
||||||
|
// If operand == SNaN, let usual NaN code handle it.
|
||||||
|
code.cmp(scratch, 0xff000000u);
|
||||||
|
code.ja(normal);
|
||||||
|
// If result == SNaN, && operand != NaN, result = result.
|
||||||
|
code.movd(scratch, result);
|
||||||
|
code.shl(scratch, 1);
|
||||||
|
code.cmp(scratch, 0xff800000u);
|
||||||
|
code.jnae(result_is_result);
|
||||||
|
// If result == QNaN && operand != NaN, result = operand.
|
||||||
|
code.movaps(result, operand);
|
||||||
|
code.jmp(end);
|
||||||
|
|
||||||
|
code.L(result_is_result);
|
||||||
|
code.movaps(operand, result);
|
||||||
|
code.jmp(normal);
|
||||||
|
|
||||||
|
code.L(normal_or_equal);
|
||||||
|
code.jnz(normal);
|
||||||
|
code.orps(operand, result);
|
||||||
|
code.L(normal);
|
||||||
|
}, &Xbyak::CodeGenerator::minss);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmitX64::EmitFPMinNumeric64(EmitContext& ctx, IR::Inst* inst) {
|
||||||
|
FPThreeOp64(code, ctx, inst, [&](Xbyak::Xmm result, Xbyak::Xmm operand, Xbyak::Reg64 scratch, Xbyak::Label& end){
|
||||||
|
Xbyak::Label normal, normal_or_equal, result_is_result;
|
||||||
|
|
||||||
|
code.ucomisd(result, operand);
|
||||||
|
code.jnp(normal_or_equal);
|
||||||
|
// If operand == QNaN, result = result.
|
||||||
|
code.movq(scratch, operand);
|
||||||
|
code.shl(scratch, 1);
|
||||||
|
code.cmp(scratch, code.MConst(qword, 0xfff0'0000'0000'0000u));
|
||||||
|
code.jae(result_is_result);
|
||||||
|
// If operand == SNaN, let usual NaN code handle it.
|
||||||
|
code.cmp(scratch, code.MConst(qword, 0xffe0'0000'0000'0000u));
|
||||||
|
code.ja(normal);
|
||||||
|
// If result == SNaN, && operand != NaN, result = result.
|
||||||
|
code.movq(scratch, result);
|
||||||
|
code.shl(scratch, 1);
|
||||||
|
code.cmp(scratch, code.MConst(qword, 0xfff0'0000'0000'0000u));
|
||||||
|
code.jnae(result_is_result);
|
||||||
|
// If result == QNaN && operand != NaN, result = operand.
|
||||||
|
code.movaps(result, operand);
|
||||||
|
code.jmp(end);
|
||||||
|
|
||||||
|
code.L(result_is_result);
|
||||||
|
code.movaps(operand, result);
|
||||||
|
code.jmp(normal);
|
||||||
|
|
||||||
|
code.L(normal_or_equal);
|
||||||
|
code.jnz(normal);
|
||||||
|
code.orps(operand, result);
|
||||||
|
code.L(normal);
|
||||||
|
}, &Xbyak::CodeGenerator::minsd);
|
||||||
|
}
|
||||||
|
|
||||||
void EmitX64::EmitFPMul32(EmitContext& ctx, IR::Inst* inst) {
|
void EmitX64::EmitFPMul32(EmitContext& ctx, IR::Inst* inst) {
|
||||||
FPThreeOp32(code, ctx, inst, &Xbyak::CodeGenerator::mulss);
|
FPThreeOp32(code, ctx, inst, &Xbyak::CodeGenerator::mulss);
|
||||||
}
|
}
|
||||||
|
|
|
@ -928,7 +928,7 @@ INST(FSUB_float, "FSUB (scalar)", "00011
|
||||||
INST(FMAX_float, "FMAX (scalar)", "00011110yy1mmmmm010010nnnnnddddd")
|
INST(FMAX_float, "FMAX (scalar)", "00011110yy1mmmmm010010nnnnnddddd")
|
||||||
INST(FMIN_float, "FMIN (scalar)", "00011110yy1mmmmm010110nnnnnddddd")
|
INST(FMIN_float, "FMIN (scalar)", "00011110yy1mmmmm010110nnnnnddddd")
|
||||||
INST(FMAXNM_float, "FMAXNM (scalar)", "00011110yy1mmmmm011010nnnnnddddd")
|
INST(FMAXNM_float, "FMAXNM (scalar)", "00011110yy1mmmmm011010nnnnnddddd")
|
||||||
//INST(FMINNM_float, "FMINNM (scalar)", "00011110yy1mmmmm011110nnnnnddddd")
|
INST(FMINNM_float, "FMINNM (scalar)", "00011110yy1mmmmm011110nnnnnddddd")
|
||||||
INST(FNMUL_float, "FNMUL (scalar)", "00011110yy1mmmmm100010nnnnnddddd")
|
INST(FNMUL_float, "FNMUL (scalar)", "00011110yy1mmmmm100010nnnnnddddd")
|
||||||
|
|
||||||
// Data Processing - FP and SIMD - Floating point conditional select
|
// Data Processing - FP and SIMD - Floating point conditional select
|
||||||
|
|
|
@ -128,6 +128,21 @@ bool TranslatorVisitor::FMAXNM_float(Imm<2> type, Vec Vm, Vec Vn, Vec Vd) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TranslatorVisitor::FMINNM_float(Imm<2> type, Vec Vm, Vec Vn, Vec Vd) {
|
||||||
|
auto datasize = GetDataSize(type);
|
||||||
|
if (!datasize) {
|
||||||
|
return UnallocatedEncoding();
|
||||||
|
}
|
||||||
|
|
||||||
|
const IR::U32U64 operand1 = V_scalar(*datasize, Vn);
|
||||||
|
const IR::U32U64 operand2 = V_scalar(*datasize, Vm);
|
||||||
|
|
||||||
|
const IR::U32U64 result = ir.FPMinNumeric(operand1, operand2, true);
|
||||||
|
|
||||||
|
V_scalar(*datasize, Vd, result);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool TranslatorVisitor::FNMUL_float(Imm<2> type, Vec Vm, Vec Vn, Vec Vd) {
|
bool TranslatorVisitor::FNMUL_float(Imm<2> type, Vec Vm, Vec Vn, Vec Vd) {
|
||||||
auto datasize = GetDataSize(type);
|
auto datasize = GetDataSize(type);
|
||||||
if (!datasize) {
|
if (!datasize) {
|
||||||
|
|
|
@ -1205,6 +1205,16 @@ U32U64 IREmitter::FPMin(const U32U64& a, const U32U64& b, bool fpscr_controlled)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
U32U64 IREmitter::FPMinNumeric(const U32U64& a, const U32U64& b, bool fpscr_controlled) {
|
||||||
|
ASSERT(fpscr_controlled);
|
||||||
|
ASSERT(a.GetType() == b.GetType());
|
||||||
|
if (a.GetType() == Type::U32) {
|
||||||
|
return Inst<U32>(Opcode::FPMinNumeric32, a, b);
|
||||||
|
} else {
|
||||||
|
return Inst<U64>(Opcode::FPMinNumeric64, a, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
U32U64 IREmitter::FPMul(const U32U64& a, const U32U64& b, bool fpscr_controlled) {
|
U32U64 IREmitter::FPMul(const U32U64& a, const U32U64& b, bool fpscr_controlled) {
|
||||||
ASSERT(fpscr_controlled);
|
ASSERT(fpscr_controlled);
|
||||||
ASSERT(a.GetType() == b.GetType());
|
ASSERT(a.GetType() == b.GetType());
|
||||||
|
|
|
@ -249,6 +249,7 @@ public:
|
||||||
U32U64 FPMax(const U32U64& a, const U32U64& b, bool fpscr_controlled);
|
U32U64 FPMax(const U32U64& a, const U32U64& b, bool fpscr_controlled);
|
||||||
U32U64 FPMaxNumeric(const U32U64& a, const U32U64& b, bool fpscr_controlled);
|
U32U64 FPMaxNumeric(const U32U64& a, const U32U64& b, bool fpscr_controlled);
|
||||||
U32U64 FPMin(const U32U64& a, const U32U64& b, bool fpscr_controlled);
|
U32U64 FPMin(const U32U64& a, const U32U64& b, bool fpscr_controlled);
|
||||||
|
U32U64 FPMinNumeric(const U32U64& a, const U32U64& b, bool fpscr_controlled);
|
||||||
U32U64 FPMul(const U32U64& a, const U32U64& b, bool fpscr_controlled);
|
U32U64 FPMul(const U32U64& a, const U32U64& b, bool fpscr_controlled);
|
||||||
U32U64 FPNeg(const U32U64& a);
|
U32U64 FPNeg(const U32U64& a);
|
||||||
U32U64 FPSqrt(const U32U64& a);
|
U32U64 FPSqrt(const U32U64& a);
|
||||||
|
|
|
@ -304,6 +304,8 @@ OPCODE(FPMaxNumeric32, T::U32, T::U32, T::U32
|
||||||
OPCODE(FPMaxNumeric64, T::U64, T::U64, T::U64 )
|
OPCODE(FPMaxNumeric64, T::U64, T::U64, T::U64 )
|
||||||
OPCODE(FPMin32, T::U32, T::U32, T::U32 )
|
OPCODE(FPMin32, T::U32, T::U32, T::U32 )
|
||||||
OPCODE(FPMin64, T::U64, T::U64, T::U64 )
|
OPCODE(FPMin64, T::U64, T::U64, T::U64 )
|
||||||
|
OPCODE(FPMinNumeric32, T::U32, T::U32, T::U32 )
|
||||||
|
OPCODE(FPMinNumeric64, T::U64, T::U64, T::U64 )
|
||||||
OPCODE(FPMul32, T::U32, T::U32, T::U32 )
|
OPCODE(FPMul32, T::U32, T::U32, T::U32 )
|
||||||
OPCODE(FPMul64, T::U64, T::U64, T::U64 )
|
OPCODE(FPMul64, T::U64, T::U64, T::U64 )
|
||||||
OPCODE(FPNeg32, T::U32, T::U32 )
|
OPCODE(FPNeg32, T::U32, T::U32 )
|
||||||
|
|
Loading…
Reference in a new issue