diff --git a/src/dynarmic/backend/x64/emit_x64_data_processing.cpp b/src/dynarmic/backend/x64/emit_x64_data_processing.cpp index feabe5e5..5e44e6eb 100644 --- a/src/dynarmic/backend/x64/emit_x64_data_processing.cpp +++ b/src/dynarmic/backend/x64/emit_x64_data_processing.cpp @@ -1189,16 +1189,17 @@ void EmitX64::EmitSignedDiv32(EmitContext& ctx, IR::Inst* inst) { ctx.reg_alloc.ScratchGpr(HostLoc::RAX); ctx.reg_alloc.ScratchGpr(HostLoc::RDX); const Xbyak::Reg32 dividend = ctx.reg_alloc.UseGpr(args[0]).cvt32(); - const Xbyak::Reg32 divisor = ctx.reg_alloc.UseGpr(args[1]).cvt32(); + const Xbyak::Reg32 divisor = ctx.reg_alloc.UseScratchGpr(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.movsxd(rax, dividend); + code.movsxd(divisor.cvt64(), divisor); + code.cqo(); + code.idiv(divisor.cvt64()); code.L(end); ctx.reg_alloc.DefineValue(inst, eax); @@ -1212,11 +1213,17 @@ void EmitX64::EmitSignedDiv64(EmitContext& ctx, IR::Inst* inst) { const Xbyak::Reg64 dividend = ctx.reg_alloc.UseGpr(args[0]); const Xbyak::Reg64 divisor = ctx.reg_alloc.UseGpr(args[1]); - Xbyak::Label end; + Xbyak::Label end, ok; code.xor_(eax, eax); code.test(divisor, divisor); code.jz(end); + code.cmp(divisor, -1); + code.jne(ok); + code.mov(rax, 0x8000000000000000); + code.cmp(dividend, rax); + code.je(end); + code.L(ok); code.mov(rax, dividend); code.cqo(); code.idiv(divisor); diff --git a/tests/A32/test_arm_instructions.cpp b/tests/A32/test_arm_instructions.cpp index e1459264..1878f961 100644 --- a/tests/A32/test_arm_instructions.cpp +++ b/tests/A32/test_arm_instructions.cpp @@ -582,3 +582,22 @@ TEST_CASE("arm: vmsr, vcmp, vmrs", "[arm][A32]") { test_env.ticks_left = 4; jit.Run(); } + +TEST_CASE("arm: sdiv maximally", "[arm][A32]") { + ArmTestEnv test_env; + A32::Jit jit{GetUserConfig(&test_env)}; + test_env.code_mem = { + 0xe712f011, // sdiv r2, r1, r0 + 0xeafffffe, // b +#0 + }; + + jit.Regs()[1] = 0x80000000; + jit.Regs()[0] = 0xffffffff; + + jit.SetCpsr(0x000001d0); // User-mode + + test_env.ticks_left = 2; + jit.Run(); + + REQUIRE(jit.Regs()[2] == 0x80000000); +} diff --git a/tests/A64/a64.cpp b/tests/A64/a64.cpp index d6ac341b..067da6bb 100644 --- a/tests/A64/a64.cpp +++ b/tests/A64/a64.cpp @@ -1199,3 +1199,24 @@ TEST_CASE("A64: SQRDMULH QC flag when output invalidated", "[a64]") { REQUIRE(jit.GetFpsr() == 0x08000000); REQUIRE(jit.GetVector(11) == Vector{0xb4cb'4fec'8563'1032, 0x0000'0000'0000'0000}); } + +TEST_CASE("A64: SDIV maximally", "[a64]") { + A64TestEnv env; + A64::Jit jit{A64::UserConfig{&env}}; + + env.code_mem.emplace_back(0x9ac00c22); // SDIV X2, X1, X0 + env.code_mem.emplace_back(0x14000000); // B . + + jit.SetRegister(0, 0xffffffffffffffff); + jit.SetRegister(1, 0x8000000000000000); + jit.SetRegister(2, 0xffffffffffffffff); + jit.SetPC(0); + + env.ticks_left = 2; + jit.Run(); + + REQUIRE(jit.GetRegister(0) == 0xffffffffffffffff); + REQUIRE(jit.GetRegister(1) == 0x8000000000000000); + REQUIRE(jit.GetRegister(2) == 0x8000000000000000); + REQUIRE(jit.GetPC() == 4); +}