emit_x64_data_processing: Detect overflow on division
This commit is contained in:
parent
905d822810
commit
038b728797
3 changed files with 52 additions and 5 deletions
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue