emit_x64_data_processing: Detect overflow on division

This commit is contained in:
Merry 2022-11-29 14:15:03 +00:00
parent 905d822810
commit 038b728797
3 changed files with 52 additions and 5 deletions

View file

@ -1189,16 +1189,17 @@ void EmitX64::EmitSignedDiv32(EmitContext& ctx, IR::Inst* inst) {
ctx.reg_alloc.ScratchGpr(HostLoc::RAX); ctx.reg_alloc.ScratchGpr(HostLoc::RAX);
ctx.reg_alloc.ScratchGpr(HostLoc::RDX); ctx.reg_alloc.ScratchGpr(HostLoc::RDX);
const Xbyak::Reg32 dividend = ctx.reg_alloc.UseGpr(args[0]).cvt32(); 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; Xbyak::Label end;
code.xor_(eax, eax); code.xor_(eax, eax);
code.test(divisor, divisor); code.test(divisor, divisor);
code.jz(end); code.jz(end);
code.mov(eax, dividend); code.movsxd(rax, dividend);
code.cdq(); code.movsxd(divisor.cvt64(), divisor);
code.idiv(divisor); code.cqo();
code.idiv(divisor.cvt64());
code.L(end); code.L(end);
ctx.reg_alloc.DefineValue(inst, eax); 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 dividend = ctx.reg_alloc.UseGpr(args[0]);
const Xbyak::Reg64 divisor = ctx.reg_alloc.UseGpr(args[1]); const Xbyak::Reg64 divisor = ctx.reg_alloc.UseGpr(args[1]);
Xbyak::Label end; Xbyak::Label end, ok;
code.xor_(eax, eax); code.xor_(eax, eax);
code.test(divisor, divisor); code.test(divisor, divisor);
code.jz(end); 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.mov(rax, dividend);
code.cqo(); code.cqo();
code.idiv(divisor); code.idiv(divisor);

View file

@ -582,3 +582,22 @@ TEST_CASE("arm: vmsr, vcmp, vmrs", "[arm][A32]") {
test_env.ticks_left = 4; test_env.ticks_left = 4;
jit.Run(); 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);
}

View file

@ -1199,3 +1199,24 @@ TEST_CASE("A64: SQRDMULH QC flag when output invalidated", "[a64]") {
REQUIRE(jit.GetFpsr() == 0x08000000); REQUIRE(jit.GetFpsr() == 0x08000000);
REQUIRE(jit.GetVector(11) == Vector{0xb4cb'4fec'8563'1032, 0x0000'0000'0000'0000}); 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);
}