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::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);
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue