Nasty, but jump over div/0. Value remains undefined, as on 360.

Fixes issue #135.
This commit is contained in:
Ben Vanik 2015-02-10 17:27:48 -08:00
parent e3a4273ef3
commit 3573840c5f
1 changed files with 40 additions and 0 deletions

View File

@ -3289,6 +3289,9 @@ EMITTER_OPCODE_TABLE(
// TODO(benvanik): simplify code! // TODO(benvanik): simplify code!
EMITTER(DIV_I8, MATCH(I<OPCODE_DIV, I8<>, I8<>, I8<>>)) { EMITTER(DIV_I8, MATCH(I<OPCODE_DIV, I8<>, I8<>, I8<>>)) {
static void Emit(X64Emitter& e, const EmitArgType& i) { static void Emit(X64Emitter& e, const EmitArgType& i) {
Xbyak::Label skip;
e.inLocalLabel();
// NOTE: RDX clobbered. // NOTE: RDX clobbered.
bool clobbered_rcx = false; bool clobbered_rcx = false;
if (i.src2.is_constant) { if (i.src2.is_constant) {
@ -3303,6 +3306,10 @@ EMITTER(DIV_I8, MATCH(I<OPCODE_DIV, I8<>, I8<>, I8<>>)) {
e.idiv(e.cl); e.idiv(e.cl);
} }
} else { } else {
// Skip if src2 is zero.
e.test(i.src2, i.src2);
e.jz(skip, CodeGenerator::T_SHORT);
if (i.instr->flags & ARITHMETIC_UNSIGNED) { if (i.instr->flags & ARITHMETIC_UNSIGNED) {
if (i.src1.is_constant) { if (i.src1.is_constant) {
e.mov(e.ax, static_cast<int16_t>(i.src1.constant())); e.mov(e.ax, static_cast<int16_t>(i.src1.constant()));
@ -3319,6 +3326,9 @@ EMITTER(DIV_I8, MATCH(I<OPCODE_DIV, I8<>, I8<>, I8<>>)) {
e.idiv(i.src2); e.idiv(i.src2);
} }
} }
e.L(skip);
e.outLocalLabel();
e.mov(i.dest, e.al); e.mov(i.dest, e.al);
if (clobbered_rcx) { if (clobbered_rcx) {
e.ReloadECX(); e.ReloadECX();
@ -3328,6 +3338,9 @@ EMITTER(DIV_I8, MATCH(I<OPCODE_DIV, I8<>, I8<>, I8<>>)) {
}; };
EMITTER(DIV_I16, MATCH(I<OPCODE_DIV, I16<>, I16<>, I16<>>)) { EMITTER(DIV_I16, MATCH(I<OPCODE_DIV, I16<>, I16<>, I16<>>)) {
static void Emit(X64Emitter& e, const EmitArgType& i) { static void Emit(X64Emitter& e, const EmitArgType& i) {
Xbyak::Label skip;
e.inLocalLabel();
// NOTE: RDX clobbered. // NOTE: RDX clobbered.
bool clobbered_rcx = false; bool clobbered_rcx = false;
if (i.src2.is_constant) { if (i.src2.is_constant) {
@ -3347,6 +3360,10 @@ EMITTER(DIV_I16, MATCH(I<OPCODE_DIV, I16<>, I16<>, I16<>>)) {
e.idiv(e.cx); e.idiv(e.cx);
} }
} else { } else {
// Skip if src2 is zero.
e.test(i.src2, i.src2);
e.jz(skip, CodeGenerator::T_SHORT);
if (i.instr->flags & ARITHMETIC_UNSIGNED) { if (i.instr->flags & ARITHMETIC_UNSIGNED) {
if (i.src1.is_constant) { if (i.src1.is_constant) {
e.mov(e.ax, i.src1.constant()); e.mov(e.ax, i.src1.constant());
@ -3368,6 +3385,9 @@ EMITTER(DIV_I16, MATCH(I<OPCODE_DIV, I16<>, I16<>, I16<>>)) {
e.idiv(i.src2); e.idiv(i.src2);
} }
} }
e.L(skip);
e.outLocalLabel();
e.mov(i.dest, e.ax); e.mov(i.dest, e.ax);
if (clobbered_rcx) { if (clobbered_rcx) {
e.ReloadECX(); e.ReloadECX();
@ -3377,6 +3397,9 @@ EMITTER(DIV_I16, MATCH(I<OPCODE_DIV, I16<>, I16<>, I16<>>)) {
}; };
EMITTER(DIV_I32, MATCH(I<OPCODE_DIV, I32<>, I32<>, I32<>>)) { EMITTER(DIV_I32, MATCH(I<OPCODE_DIV, I32<>, I32<>, I32<>>)) {
static void Emit(X64Emitter& e, const EmitArgType& i) { static void Emit(X64Emitter& e, const EmitArgType& i) {
Xbyak::Label skip;
e.inLocalLabel();
// NOTE: RDX clobbered. // NOTE: RDX clobbered.
bool clobbered_rcx = false; bool clobbered_rcx = false;
if (i.src2.is_constant) { if (i.src2.is_constant) {
@ -3396,6 +3419,10 @@ EMITTER(DIV_I32, MATCH(I<OPCODE_DIV, I32<>, I32<>, I32<>>)) {
e.idiv(e.ecx); e.idiv(e.ecx);
} }
} else { } else {
// Skip if src2 is zero.
e.test(i.src2, i.src2);
e.jz(skip, CodeGenerator::T_SHORT);
if (i.instr->flags & ARITHMETIC_UNSIGNED) { if (i.instr->flags & ARITHMETIC_UNSIGNED) {
if (i.src1.is_constant) { if (i.src1.is_constant) {
e.mov(e.eax, i.src1.constant()); e.mov(e.eax, i.src1.constant());
@ -3417,6 +3444,9 @@ EMITTER(DIV_I32, MATCH(I<OPCODE_DIV, I32<>, I32<>, I32<>>)) {
e.idiv(i.src2); e.idiv(i.src2);
} }
} }
e.L(skip);
e.outLocalLabel();
e.mov(i.dest, e.eax); e.mov(i.dest, e.eax);
if (clobbered_rcx) { if (clobbered_rcx) {
e.ReloadECX(); e.ReloadECX();
@ -3426,6 +3456,9 @@ EMITTER(DIV_I32, MATCH(I<OPCODE_DIV, I32<>, I32<>, I32<>>)) {
}; };
EMITTER(DIV_I64, MATCH(I<OPCODE_DIV, I64<>, I64<>, I64<>>)) { EMITTER(DIV_I64, MATCH(I<OPCODE_DIV, I64<>, I64<>, I64<>>)) {
static void Emit(X64Emitter& e, const EmitArgType& i) { static void Emit(X64Emitter& e, const EmitArgType& i) {
Xbyak::Label skip;
e.inLocalLabel();
// NOTE: RDX clobbered. // NOTE: RDX clobbered.
bool clobbered_rcx = false; bool clobbered_rcx = false;
if (i.src2.is_constant) { if (i.src2.is_constant) {
@ -3445,6 +3478,10 @@ EMITTER(DIV_I64, MATCH(I<OPCODE_DIV, I64<>, I64<>, I64<>>)) {
e.idiv(e.rcx); e.idiv(e.rcx);
} }
} else { } else {
// Skip if src2 is zero.
e.test(i.src2, i.src2);
e.jz(skip, CodeGenerator::T_SHORT);
if (i.instr->flags & ARITHMETIC_UNSIGNED) { if (i.instr->flags & ARITHMETIC_UNSIGNED) {
if (i.src1.is_constant) { if (i.src1.is_constant) {
e.mov(e.rax, i.src1.constant()); e.mov(e.rax, i.src1.constant());
@ -3466,6 +3503,9 @@ EMITTER(DIV_I64, MATCH(I<OPCODE_DIV, I64<>, I64<>, I64<>>)) {
e.idiv(i.src2); e.idiv(i.src2);
} }
} }
e.L(skip);
e.outLocalLabel();
e.mov(i.dest, e.rax); e.mov(i.dest, e.rax);
if (clobbered_rcx) { if (clobbered_rcx) {
e.ReloadECX(); e.ReloadECX();