Implemented SDIV and UDIV instructions
This commit is contained in:
parent
6033b05ca6
commit
ab84524806
6 changed files with 153 additions and 3 deletions
|
@ -878,6 +878,90 @@ void EmitX64::EmitMul64(EmitContext& ctx, IR::Inst* inst) {
|
||||||
ctx.reg_alloc.DefineValue(inst, result);
|
ctx.reg_alloc.DefineValue(inst, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmitX64::EmitUnsignedDiv32(EmitContext& ctx, IR::Inst* inst) {
|
||||||
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
|
||||||
|
ctx.reg_alloc.ScratchGpr({HostLoc::RAX});
|
||||||
|
ctx.reg_alloc.ScratchGpr({HostLoc::RDX});
|
||||||
|
Xbyak::Reg32 dividend = ctx.reg_alloc.UseGpr(args[0]).cvt32();
|
||||||
|
Xbyak::Reg32 divisor = ctx.reg_alloc.UseGpr(args[1]).cvt32();
|
||||||
|
|
||||||
|
Xbyak::Label end;
|
||||||
|
|
||||||
|
code->xor_(eax, eax);
|
||||||
|
code->test(divisor, divisor);
|
||||||
|
code->jz(end);
|
||||||
|
code->mov(eax, dividend);
|
||||||
|
code->xor_(edx, edx);
|
||||||
|
code->div(divisor);
|
||||||
|
code->L(end);
|
||||||
|
|
||||||
|
ctx.reg_alloc.DefineValue(inst, eax);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmitX64::EmitUnsignedDiv64(EmitContext& ctx, IR::Inst* inst) {
|
||||||
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
|
||||||
|
ctx.reg_alloc.ScratchGpr({HostLoc::RAX});
|
||||||
|
ctx.reg_alloc.ScratchGpr({HostLoc::RDX});
|
||||||
|
Xbyak::Reg64 dividend = ctx.reg_alloc.UseGpr(args[0]);
|
||||||
|
Xbyak::Reg64 divisor = ctx.reg_alloc.UseGpr(args[1]);
|
||||||
|
|
||||||
|
Xbyak::Label end;
|
||||||
|
|
||||||
|
code->xor_(eax, eax);
|
||||||
|
code->test(divisor, divisor);
|
||||||
|
code->jz(end);
|
||||||
|
code->mov(rax, dividend);
|
||||||
|
code->xor_(edx, edx);
|
||||||
|
code->div(divisor);
|
||||||
|
code->L(end);
|
||||||
|
|
||||||
|
ctx.reg_alloc.DefineValue(inst, rax);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmitX64::EmitSignedDiv32(EmitContext& ctx, IR::Inst* inst) {
|
||||||
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
|
||||||
|
ctx.reg_alloc.ScratchGpr({HostLoc::RAX});
|
||||||
|
ctx.reg_alloc.ScratchGpr({HostLoc::RDX});
|
||||||
|
Xbyak::Reg32 dividend = ctx.reg_alloc.UseGpr(args[0]).cvt32();
|
||||||
|
Xbyak::Reg32 divisor = ctx.reg_alloc.UseGpr(args[1]).cvt32();
|
||||||
|
|
||||||
|
Xbyak::Label end;
|
||||||
|
|
||||||
|
code->xor_(eax, eax);
|
||||||
|
code->test(divisor, divisor);
|
||||||
|
code->jz(end);
|
||||||
|
code->mov(eax, dividend);
|
||||||
|
code->cdq();
|
||||||
|
code->idiv(divisor);
|
||||||
|
code->L(end);
|
||||||
|
|
||||||
|
ctx.reg_alloc.DefineValue(inst, eax);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmitX64::EmitSignedDiv64(EmitContext& ctx, IR::Inst* inst) {
|
||||||
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
|
||||||
|
ctx.reg_alloc.ScratchGpr({HostLoc::RAX});
|
||||||
|
ctx.reg_alloc.ScratchGpr({HostLoc::RDX});
|
||||||
|
Xbyak::Reg64 dividend = ctx.reg_alloc.UseGpr(args[0]);
|
||||||
|
Xbyak::Reg64 divisor = ctx.reg_alloc.UseGpr(args[1]);
|
||||||
|
|
||||||
|
Xbyak::Label end;
|
||||||
|
|
||||||
|
code->xor_(eax, eax);
|
||||||
|
code->test(divisor, divisor);
|
||||||
|
code->jz(end);
|
||||||
|
code->mov(rax, dividend);
|
||||||
|
code->cqo();
|
||||||
|
code->idiv(divisor);
|
||||||
|
code->L(end);
|
||||||
|
|
||||||
|
ctx.reg_alloc.DefineValue(inst, rax);
|
||||||
|
}
|
||||||
|
|
||||||
void EmitX64::EmitAnd32(EmitContext& ctx, IR::Inst* inst) {
|
void EmitX64::EmitAnd32(EmitContext& ctx, IR::Inst* inst) {
|
||||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||||
|
|
||||||
|
|
|
@ -274,8 +274,8 @@ INST(LDR_imm_fpsimd_2, "LDR (immediate, SIMD&FP)", "zz111
|
||||||
//INST(LDRA, "LDRAA, LDRAB", "11111000MS1iiiiiiiiiW1nnnnnttttt")
|
//INST(LDRA, "LDRAA, LDRAB", "11111000MS1iiiiiiiiiW1nnnnnttttt")
|
||||||
|
|
||||||
// Data Processing - Register - 2 source
|
// Data Processing - Register - 2 source
|
||||||
//INST(UDIV, "UDIV", "z0011010110mmmmm000010nnnnnddddd")
|
INST(UDIV, "UDIV", "z0011010110mmmmm000010nnnnnddddd")
|
||||||
//INST(SDIV, "SDIV", "z0011010110mmmmm000011nnnnnddddd")
|
INST(SDIV, "SDIV", "z0011010110mmmmm000011nnnnnddddd")
|
||||||
INST(LSLV, "LSLV", "z0011010110mmmmm001000nnnnnddddd")
|
INST(LSLV, "LSLV", "z0011010110mmmmm001000nnnnnddddd")
|
||||||
INST(LSRV, "LSRV", "z0011010110mmmmm001001nnnnnddddd")
|
INST(LSRV, "LSRV", "z0011010110mmmmm001001nnnnnddddd")
|
||||||
INST(ASRV, "ASRV", "z0011010110mmmmm001010nnnnnddddd")
|
INST(ASRV, "ASRV", "z0011010110mmmmm001010nnnnnddddd")
|
||||||
|
@ -975,4 +975,4 @@ INST(AND_asimd, "AND (vector)", "0Q001
|
||||||
//INST(FMADD_float, "FMADD", "00011111yy0mmmmm0aaaaannnnnddddd")
|
//INST(FMADD_float, "FMADD", "00011111yy0mmmmm0aaaaannnnnddddd")
|
||||||
//INST(FMSUB_float, "FMSUB", "00011111yy0mmmmm1aaaaannnnnddddd")
|
//INST(FMSUB_float, "FMSUB", "00011111yy0mmmmm1aaaaannnnnddddd")
|
||||||
//INST(FNMADD_float, "FNMADD", "00011111yy1mmmmm0aaaaannnnnddddd")
|
//INST(FNMADD_float, "FNMADD", "00011111yy1mmmmm0aaaaannnnnddddd")
|
||||||
//INST(FNMSUB_float, "FNMSUB", "00011111yy1mmmmm1aaaaannnnnddddd")
|
//INST(FNMSUB_float, "FNMSUB", "00011111yy1mmmmm1aaaaannnnnddddd")
|
||||||
|
|
|
@ -79,5 +79,29 @@ bool TranslatorVisitor::UMSUBL(Reg Rm, Reg Ra, Reg Rn, Reg Rd) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TranslatorVisitor::UDIV(bool sf, Reg Rm, Reg Rn, Reg Rd) {
|
||||||
|
const size_t datasize = sf ? 64 : 32;
|
||||||
|
|
||||||
|
const IR::U32U64 m = X(datasize, Rm);
|
||||||
|
const IR::U32U64 n = X(datasize, Rn);
|
||||||
|
|
||||||
|
const IR::U32U64 result = ir.UnsignedDiv(n,m);
|
||||||
|
|
||||||
|
X(datasize, Rd, result);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TranslatorVisitor::SDIV(bool sf, Reg Rm, Reg Rn, Reg Rd) {
|
||||||
|
const size_t datasize = sf ? 64 : 32;
|
||||||
|
|
||||||
|
const IR::U32U64 m = X(datasize, Rm);
|
||||||
|
const IR::U32U64 n = X(datasize, Rn);
|
||||||
|
|
||||||
|
const IR::U32U64 result = ir.SignedDiv(n,m);
|
||||||
|
|
||||||
|
X(datasize, Rd, result);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace A64
|
} // namespace A64
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
||||||
|
|
|
@ -269,6 +269,38 @@ U32U64 IREmitter::Mul(const U32U64& a, const U32U64& b) {
|
||||||
return Inst<U64>(Opcode::Mul64, a, b);
|
return Inst<U64>(Opcode::Mul64, a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
U32 IREmitter::UnsignedDiv(const U32& a, const U32& b) {
|
||||||
|
return Inst<U32>(Opcode::UnsignedDiv32, a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
U64 IREmitter::UnsignedDiv(const U64& a, const U64& b) {
|
||||||
|
return Inst<U64>(Opcode::UnsignedDiv64, a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
U32U64 IREmitter::UnsignedDiv(const U32U64& a, const U32U64& b) {
|
||||||
|
if (a.GetType() == Type::U32) {
|
||||||
|
return Inst<U32>(Opcode::UnsignedDiv32, a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Inst<U64>(Opcode::UnsignedDiv64, a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
U32 IREmitter::SignedDiv(const U32& a, const U32& b) {
|
||||||
|
return Inst<U32>(Opcode::SignedDiv32, a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
U64 IREmitter::SignedDiv(const U64& a, const U64& b) {
|
||||||
|
return Inst<U64>(Opcode::SignedDiv64, a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
U32U64 IREmitter::SignedDiv(const U32U64& a, const U32U64& b) {
|
||||||
|
if (a.GetType() == Type::U32) {
|
||||||
|
return Inst<U32>(Opcode::SignedDiv32, a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Inst<U64>(Opcode::SignedDiv64, a, b);
|
||||||
|
}
|
||||||
|
|
||||||
U32 IREmitter::And(const U32& a, const U32& b) {
|
U32 IREmitter::And(const U32& a, const U32& b) {
|
||||||
return Inst<U32>(Opcode::And32, a, b);
|
return Inst<U32>(Opcode::And32, a, b);
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,6 +110,12 @@ public:
|
||||||
U32 Mul(const U32& a, const U32& b);
|
U32 Mul(const U32& a, const U32& b);
|
||||||
U64 Mul(const U64& a, const U64& b);
|
U64 Mul(const U64& a, const U64& b);
|
||||||
U32U64 Mul(const U32U64& a, const U32U64& b);
|
U32U64 Mul(const U32U64& a, const U32U64& b);
|
||||||
|
U32 UnsignedDiv(const U32& a, const U32& b);
|
||||||
|
U64 UnsignedDiv(const U64& a, const U64& b);
|
||||||
|
U32U64 UnsignedDiv(const U32U64& a, const U32U64& b);
|
||||||
|
U32 SignedDiv(const U32& a, const U32& b);
|
||||||
|
U64 SignedDiv(const U64& a, const U64& b);
|
||||||
|
U32U64 SignedDiv(const U32U64& a, const U32U64& b);
|
||||||
U32 And(const U32& a, const U32& b);
|
U32 And(const U32& a, const U32& b);
|
||||||
U32U64 And(const U32U64& a, const U32U64& b);
|
U32U64 And(const U32U64& a, const U32U64& b);
|
||||||
U32 Eor(const U32& a, const U32& b);
|
U32 Eor(const U32& a, const U32& b);
|
||||||
|
|
|
@ -94,6 +94,10 @@ OPCODE(Sub32, T::U32, T::U32, T::U32,
|
||||||
OPCODE(Sub64, T::U64, T::U64, T::U64, T::U1 )
|
OPCODE(Sub64, T::U64, T::U64, T::U64, T::U1 )
|
||||||
OPCODE(Mul32, T::U32, T::U32, T::U32 )
|
OPCODE(Mul32, T::U32, T::U32, T::U32 )
|
||||||
OPCODE(Mul64, T::U64, T::U64, T::U64 )
|
OPCODE(Mul64, T::U64, T::U64, T::U64 )
|
||||||
|
OPCODE(UnsignedDiv32, T::U32, T::U32, T::U32 )
|
||||||
|
OPCODE(UnsignedDiv64, T::U64, T::U64, T::U64 )
|
||||||
|
OPCODE(SignedDiv32, T::U32, T::U32, T::U32 )
|
||||||
|
OPCODE(SignedDiv64, T::U64, T::U64, T::U64 )
|
||||||
OPCODE(And32, T::U32, T::U32, T::U32 )
|
OPCODE(And32, T::U32, T::U32, T::U32 )
|
||||||
OPCODE(And64, T::U64, T::U64, T::U64 )
|
OPCODE(And64, T::U64, T::U64, T::U64 )
|
||||||
OPCODE(Eor32, T::U32, T::U32, T::U32 )
|
OPCODE(Eor32, T::U32, T::U32, T::U32 )
|
||||||
|
|
Loading…
Reference in a new issue