From ab845248063ea91617822da60750816944942813 Mon Sep 17 00:00:00 2001 From: FernandoS27 Date: Wed, 24 Jan 2018 08:36:39 -0400 Subject: [PATCH] Implemented SDIV and UDIV instructions --- src/backend_x64/emit_x64_data_processing.cpp | 84 +++++++++++++++++++ src/frontend/A64/decoder/a64.inc | 6 +- .../impl/data_processing_multiply.cpp | 24 ++++++ src/frontend/ir/ir_emitter.cpp | 32 +++++++ src/frontend/ir/ir_emitter.h | 6 ++ src/frontend/ir/opcodes.inc | 4 + 6 files changed, 153 insertions(+), 3 deletions(-) diff --git a/src/backend_x64/emit_x64_data_processing.cpp b/src/backend_x64/emit_x64_data_processing.cpp index 4011816e..a372535d 100644 --- a/src/backend_x64/emit_x64_data_processing.cpp +++ b/src/backend_x64/emit_x64_data_processing.cpp @@ -878,6 +878,90 @@ void EmitX64::EmitMul64(EmitContext& ctx, IR::Inst* inst) { 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) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); diff --git a/src/frontend/A64/decoder/a64.inc b/src/frontend/A64/decoder/a64.inc index 0aa92957..6c7dd821 100644 --- a/src/frontend/A64/decoder/a64.inc +++ b/src/frontend/A64/decoder/a64.inc @@ -274,8 +274,8 @@ INST(LDR_imm_fpsimd_2, "LDR (immediate, SIMD&FP)", "zz111 //INST(LDRA, "LDRAA, LDRAB", "11111000MS1iiiiiiiiiW1nnnnnttttt") // Data Processing - Register - 2 source -//INST(UDIV, "UDIV", "z0011010110mmmmm000010nnnnnddddd") -//INST(SDIV, "SDIV", "z0011010110mmmmm000011nnnnnddddd") +INST(UDIV, "UDIV", "z0011010110mmmmm000010nnnnnddddd") +INST(SDIV, "SDIV", "z0011010110mmmmm000011nnnnnddddd") INST(LSLV, "LSLV", "z0011010110mmmmm001000nnnnnddddd") INST(LSRV, "LSRV", "z0011010110mmmmm001001nnnnnddddd") INST(ASRV, "ASRV", "z0011010110mmmmm001010nnnnnddddd") @@ -975,4 +975,4 @@ INST(AND_asimd, "AND (vector)", "0Q001 //INST(FMADD_float, "FMADD", "00011111yy0mmmmm0aaaaannnnnddddd") //INST(FMSUB_float, "FMSUB", "00011111yy0mmmmm1aaaaannnnnddddd") //INST(FNMADD_float, "FNMADD", "00011111yy1mmmmm0aaaaannnnnddddd") -//INST(FNMSUB_float, "FNMSUB", "00011111yy1mmmmm1aaaaannnnnddddd") \ No newline at end of file +//INST(FNMSUB_float, "FNMSUB", "00011111yy1mmmmm1aaaaannnnnddddd") diff --git a/src/frontend/A64/translate/impl/data_processing_multiply.cpp b/src/frontend/A64/translate/impl/data_processing_multiply.cpp index b7d26516..af0f42bb 100644 --- a/src/frontend/A64/translate/impl/data_processing_multiply.cpp +++ b/src/frontend/A64/translate/impl/data_processing_multiply.cpp @@ -79,5 +79,29 @@ bool TranslatorVisitor::UMSUBL(Reg Rm, Reg Ra, Reg Rn, Reg Rd) { 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 Dynarmic diff --git a/src/frontend/ir/ir_emitter.cpp b/src/frontend/ir/ir_emitter.cpp index 155cbfef..d29926d5 100644 --- a/src/frontend/ir/ir_emitter.cpp +++ b/src/frontend/ir/ir_emitter.cpp @@ -269,6 +269,38 @@ U32U64 IREmitter::Mul(const U32U64& a, const U32U64& b) { return Inst(Opcode::Mul64, a, b); } +U32 IREmitter::UnsignedDiv(const U32& a, const U32& b) { + return Inst(Opcode::UnsignedDiv32, a, b); +} + +U64 IREmitter::UnsignedDiv(const U64& a, const U64& b) { + return Inst(Opcode::UnsignedDiv64, a, b); +} + +U32U64 IREmitter::UnsignedDiv(const U32U64& a, const U32U64& b) { + if (a.GetType() == Type::U32) { + return Inst(Opcode::UnsignedDiv32, a, b); + } + + return Inst(Opcode::UnsignedDiv64, a, b); +} + +U32 IREmitter::SignedDiv(const U32& a, const U32& b) { + return Inst(Opcode::SignedDiv32, a, b); +} + +U64 IREmitter::SignedDiv(const U64& a, const U64& b) { + return Inst(Opcode::SignedDiv64, a, b); +} + +U32U64 IREmitter::SignedDiv(const U32U64& a, const U32U64& b) { + if (a.GetType() == Type::U32) { + return Inst(Opcode::SignedDiv32, a, b); + } + + return Inst(Opcode::SignedDiv64, a, b); +} + U32 IREmitter::And(const U32& a, const U32& b) { return Inst(Opcode::And32, a, b); } diff --git a/src/frontend/ir/ir_emitter.h b/src/frontend/ir/ir_emitter.h index 102a67d5..39e0bda6 100644 --- a/src/frontend/ir/ir_emitter.h +++ b/src/frontend/ir/ir_emitter.h @@ -110,6 +110,12 @@ public: U32 Mul(const U32& a, const U32& b); U64 Mul(const U64& a, const U64& 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); U32U64 And(const U32U64& a, const U32U64& b); U32 Eor(const U32& a, const U32& b); diff --git a/src/frontend/ir/opcodes.inc b/src/frontend/ir/opcodes.inc index da922bfc..20c40040 100644 --- a/src/frontend/ir/opcodes.inc +++ b/src/frontend/ir/opcodes.inc @@ -94,6 +94,10 @@ OPCODE(Sub32, T::U32, T::U32, T::U32, OPCODE(Sub64, T::U64, T::U64, T::U64, T::U1 ) OPCODE(Mul32, T::U32, T::U32, T::U32 ) 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(And64, T::U64, T::U64, T::U64 ) OPCODE(Eor32, T::U32, T::U32, T::U32 )