x86_imul_reg_reg(inst, $1, $2);
}
+/* Spill before division to ensure that the arguments end up in
+ EAX and ECX, and that EDX is free */
+JIT_OP_IDIV: binary, spill_before, more_space
+ [reg, imm] -> {
+ switch($2)
+ {
+ case 0:
+ {
+ inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
+ }
+ break;
+
+ case 1: break;
+
+ case -1:
+ {
+ /* Dividing by -1 gives an exception if the argument
+ is minint, or simply negates for other values */
+ unsigned char *patch = inst;
+ x86_alu_reg_imm(inst, X86_CMP, $1, jit_min_int);
+ x86_branch8(inst, X86_CC_NE, 0, 0);
+ inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC);
+ x86_patch(patch, inst);
+ x86_neg_reg(inst, $1);
+ }
+ break;
+
+ case 2:
+ {
+ x86_shift_reg_imm(inst, X86_SAR, $1, 1);
+ }
+ break;
+
+ case 4:
+ {
+ x86_shift_reg_imm(inst, X86_SAR, $1, 2);
+ }
+ break;
+
+ case 8:
+ {
+ x86_shift_reg_imm(inst, X86_SAR, $1, 3);
+ }
+ break;
+
+ case 16:
+ {
+ x86_shift_reg_imm(inst, X86_SAR, $1, 4);
+ }
+ break;
+
+ case 32:
+ {
+ x86_shift_reg_imm(inst, X86_SAR, $1, 5);
+ }
+ break;
+
+ case 64:
+ {
+ x86_shift_reg_imm(inst, X86_SAR, $1, 6);
+ }
+ break;
+
+ case 128:
+ {
+ x86_shift_reg_imm(inst, X86_SAR, $1, 7);
+ }
+ break;
+
+ case 256:
+ {
+ x86_shift_reg_imm(inst, X86_SAR, $1, 8);
+ }
+ break;
+
+ case 512:
+ {
+ x86_shift_reg_imm(inst, X86_SAR, $1, 9);
+ }
+ break;
+
+ case 1024:
+ {
+ x86_shift_reg_imm(inst, X86_SAR, $1, 10);
+ }
+ break;
+
+ case 2048:
+ {
+ x86_shift_reg_imm(inst, X86_SAR, $1, 11);
+ }
+ break;
+
+ case 4096:
+ {
+ x86_shift_reg_imm(inst, X86_SAR, $1, 12);
+ }
+ break;
+
+ case 8192:
+ {
+ x86_shift_reg_imm(inst, X86_SAR, $1, 13);
+ }
+ break;
+
+ case 16384:
+ {
+ x86_shift_reg_imm(inst, X86_SAR, $1, 14);
+ }
+ break;
+
+ case 32768:
+ {
+ x86_shift_reg_imm(inst, X86_SAR, $1, 15);
+ }
+ break;
+
+ case 65536:
+ {
+ x86_shift_reg_imm(inst, X86_SAR, $1, 16);
+ }
+ break;
+
+ case 0x00020000:
+ {
+ x86_shift_reg_imm(inst, X86_SAR, $1, 17);
+ }
+ break;
+
+ case 0x00040000:
+ {
+ x86_shift_reg_imm(inst, X86_SAR, $1, 18);
+ }
+ break;
+
+ case 0x00080000:
+ {
+ x86_shift_reg_imm(inst, X86_SAR, $1, 19);
+ }
+ break;
+
+ case 0x00100000:
+ {
+ x86_shift_reg_imm(inst, X86_SAR, $1, 20);
+ }
+ break;
+
+ case 0x00200000:
+ {
+ x86_shift_reg_imm(inst, X86_SAR, $1, 21);
+ }
+ break;
+
+ case 0x00400000:
+ {
+ x86_shift_reg_imm(inst, X86_SAR, $1, 22);
+ }
+ break;
+
+ case 0x00800000:
+ {
+ x86_shift_reg_imm(inst, X86_SAR, $1, 23);
+ }
+ break;
+
+ case 0x01000000:
+ {
+ x86_shift_reg_imm(inst, X86_SAR, $1, 24);
+ }
+ break;
+
+ case 0x02000000:
+ {
+ x86_shift_reg_imm(inst, X86_SAR, $1, 25);
+ }
+ break;
+
+ case 0x04000000:
+ {
+ x86_shift_reg_imm(inst, X86_SAR, $1, 26);
+ }
+ break;
+
+ case 0x08000000:
+ {
+ x86_shift_reg_imm(inst, X86_SAR, $1, 27);
+ }
+ break;
+
+ case 0x10000000:
+ {
+ x86_shift_reg_imm(inst, X86_SAR, $1, 28);
+ }
+ break;
+
+ case 0x20000000:
+ {
+ x86_shift_reg_imm(inst, X86_SAR, $1, 29);
+ }
+ break;
+
+ case 0x40000000:
+ {
+ x86_shift_reg_imm(inst, X86_SAR, $1, 30);
+ }
+ break;
+
+ case (jit_nint)0x80000000:
+ {
+ x86_shift_reg_imm(inst, X86_SAR, $1, 31);
+ }
+ break;
+
+ default:
+ {
+ x86_mov_reg_imm(inst, X86_ECX, $2);
+ x86_cdq(inst);
+ x86_div_reg(inst, X86_ECX, 1);
+ }
+ break;
+ }
+ }
+ [reg, reg] -> {
+ unsigned char *patch, *patch2;
+ x86_alu_reg_reg(inst, X86_OR, $2, $2);
+ patch = inst;
+ x86_branch8(inst, X86_CC_NE, 0, 0);
+ inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
+ x86_patch(patch, inst);
+ x86_alu_reg_imm(inst, X86_CMP, $2, -1);
+ patch = inst;
+ x86_branch8(inst, X86_CC_NE, 0, 0);
+ x86_alu_reg_imm(inst, X86_CMP, $1, jit_min_int);
+ patch2 = inst;
+ x86_branch8(inst, X86_CC_NE, 0, 0);
+ inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC);
+ x86_patch(patch, inst);
+ x86_patch(patch2, inst);
+ x86_cdq(inst);
+ x86_div_reg(inst, $2, 1);
+ }
+
+JIT_OP_IDIV_UN: binary, spill_before, more_space
+ [reg, imm] -> {
+ switch($2)
+ {
+ case 0:
+ {
+ inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
+ }
+ break;
+
+ case 1: break;
+
+ case 2:
+ {
+ x86_shift_reg_imm(inst, X86_SHR, $1, 1);
+ }
+ break;
+
+ case 4:
+ {
+ x86_shift_reg_imm(inst, X86_SHR, $1, 2);
+ }
+ break;
+
+ case 8:
+ {
+ x86_shift_reg_imm(inst, X86_SHR, $1, 3);
+ }
+ break;
+
+ case 16:
+ {
+ x86_shift_reg_imm(inst, X86_SHR, $1, 4);
+ }
+ break;
+
+ case 32:
+ {
+ x86_shift_reg_imm(inst, X86_SHR, $1, 5);
+ }
+ break;
+
+ case 64:
+ {
+ x86_shift_reg_imm(inst, X86_SHR, $1, 6);
+ }
+ break;
+
+ case 128:
+ {
+ x86_shift_reg_imm(inst, X86_SHR, $1, 7);
+ }
+ break;
+
+ case 256:
+ {
+ x86_shift_reg_imm(inst, X86_SHR, $1, 8);
+ }
+ break;
+
+ case 512:
+ {
+ x86_shift_reg_imm(inst, X86_SHR, $1, 9);
+ }
+ break;
+
+ case 1024:
+ {
+ x86_shift_reg_imm(inst, X86_SHR, $1, 10);
+ }
+ break;
+
+ case 2048:
+ {
+ x86_shift_reg_imm(inst, X86_SHR, $1, 11);
+ }
+ break;
+
+ case 4096:
+ {
+ x86_shift_reg_imm(inst, X86_SHR, $1, 12);
+ }
+ break;
+
+ case 8192:
+ {
+ x86_shift_reg_imm(inst, X86_SHR, $1, 13);
+ }
+ break;
+
+ case 16384:
+ {
+ x86_shift_reg_imm(inst, X86_SHR, $1, 14);
+ }
+ break;
+
+ case 32768:
+ {
+ x86_shift_reg_imm(inst, X86_SHR, $1, 15);
+ }
+ break;
+
+ case 65536:
+ {
+ x86_shift_reg_imm(inst, X86_SHR, $1, 16);
+ }
+ break;
+
+ case 0x00020000:
+ {
+ x86_shift_reg_imm(inst, X86_SHR, $1, 17);
+ }
+ break;
+
+ case 0x00040000:
+ {
+ x86_shift_reg_imm(inst, X86_SHR, $1, 18);
+ }
+ break;
+
+ case 0x00080000:
+ {
+ x86_shift_reg_imm(inst, X86_SHR, $1, 19);
+ }
+ break;
+
+ case 0x00100000:
+ {
+ x86_shift_reg_imm(inst, X86_SHR, $1, 20);
+ }
+ break;
+
+ case 0x00200000:
+ {
+ x86_shift_reg_imm(inst, X86_SHR, $1, 21);
+ }
+ break;
+
+ case 0x00400000:
+ {
+ x86_shift_reg_imm(inst, X86_SHR, $1, 22);
+ }
+ break;
+
+ case 0x00800000:
+ {
+ x86_shift_reg_imm(inst, X86_SHR, $1, 23);
+ }
+ break;
+
+ case 0x01000000:
+ {
+ x86_shift_reg_imm(inst, X86_SHR, $1, 24);
+ }
+ break;
+
+ case 0x02000000:
+ {
+ x86_shift_reg_imm(inst, X86_SHR, $1, 25);
+ }
+ break;
+
+ case 0x04000000:
+ {
+ x86_shift_reg_imm(inst, X86_SHR, $1, 26);
+ }
+ break;
+
+ case 0x08000000:
+ {
+ x86_shift_reg_imm(inst, X86_SHR, $1, 27);
+ }
+ break;
+
+ case 0x10000000:
+ {
+ x86_shift_reg_imm(inst, X86_SHR, $1, 28);
+ }
+ break;
+
+ case 0x20000000:
+ {
+ x86_shift_reg_imm(inst, X86_SHR, $1, 29);
+ }
+ break;
+
+ case 0x40000000:
+ {
+ x86_shift_reg_imm(inst, X86_SHR, $1, 30);
+ }
+ break;
+
+ case (jit_nint)0x80000000:
+ {
+ x86_shift_reg_imm(inst, X86_SHR, $1, 31);
+ }
+ break;
+
+ default:
+ {
+ x86_mov_reg_imm(inst, X86_ECX, $2);
+ x86_clear_reg(inst, X86_EDX);
+ x86_div_reg(inst, X86_ECX, 0);
+ }
+ break;
+ }
+ }
+ [reg, reg] -> {
+ unsigned char *patch;
+ x86_alu_reg_reg(inst, X86_OR, $2, $2);
+ patch = inst;
+ x86_branch8(inst, X86_CC_NE, 0, 0);
+ inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
+ x86_patch(patch, inst);
+ x86_clear_reg(inst, X86_EDX);
+ x86_div_reg(inst, $2, 0);
+ }
+
+JIT_OP_IREM: binary, spill_before, more_space
+ [reg, imm] -> {
+ switch($2)
+ {
+ case 0:
+ {
+ inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
+ }
+ break;
+
+ case 1:
+ {
+ x86_clear_reg(inst, $1);
+ }
+ break;
+
+ case -1:
+ {
+ /* Dividing by -1 gives an exception if the argument
+ is minint, or simply gives a remainder of zero */
+ unsigned char *patch = inst;
+ x86_alu_reg_imm(inst, X86_CMP, $1, jit_min_int);
+ x86_branch8(inst, X86_CC_NE, 0, 0);
+ inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC);
+ x86_patch(patch, inst);
+ x86_clear_reg(inst, $1);
+ }
+ break;
+
+ default:
+ {
+ x86_mov_reg_imm(inst, X86_ECX, $2);
+ x86_cdq(inst);
+ x86_div_reg(inst, X86_ECX, 1);
+ /* TODO: rearrange register assignments to avoid the move */
+ x86_mov_reg_reg(inst, X86_EAX, X86_EDX, 4);
+ }
+ break;
+ }
+ }
+ [reg, reg] -> {
+ unsigned char *patch, *patch2;
+ x86_alu_reg_reg(inst, X86_OR, $2, $2);
+ patch = inst;
+ x86_branch8(inst, X86_CC_NE, 0, 0);
+ inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
+ x86_patch(patch, inst);
+ x86_alu_reg_imm(inst, X86_CMP, $2, -1);
+ patch = inst;
+ x86_branch8(inst, X86_CC_NE, 0, 0);
+ x86_alu_reg_imm(inst, X86_CMP, $1, jit_min_int);
+ patch2 = inst;
+ x86_branch8(inst, X86_CC_NE, 0, 0);
+ inst = throw_builtin(inst, func, JIT_RESULT_ARITHMETIC);
+ x86_patch(patch, inst);
+ x86_patch(patch2, inst);
+ x86_cdq(inst);
+ x86_div_reg(inst, $2, 1);
+ x86_mov_reg_reg(inst, X86_EAX, X86_EDX, 4);
+ }
+
+JIT_OP_IREM_UN: binary, spill_before, more_space
+ [reg, imm] -> {
+ switch($2)
+ {
+ case 0:
+ {
+ inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
+ }
+ break;
+
+ case 1:
+ {
+ x86_clear_reg(inst, $1);
+ }
+ break;
+
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ case 32:
+ case 64:
+ case 128:
+ case 256:
+ case 512:
+ case 1024:
+ case 2048:
+ case 4096:
+ case 8192:
+ case 16384:
+ case 32768:
+ case 65536:
+ case 0x00020000:
+ case 0x00040000:
+ case 0x00080000:
+ case 0x00100000:
+ case 0x00200000:
+ case 0x00400000:
+ case 0x00800000:
+ case 0x01000000:
+ case 0x02000000:
+ case 0x04000000:
+ case 0x08000000:
+ case 0x10000000:
+ case 0x20000000:
+ case 0x40000000:
+ case (jit_nint)0x80000000:
+ {
+ x86_alu_reg_imm(inst, X86_AND, $1, $2 - 1);
+ }
+ break;
+
+ default:
+ {
+ x86_mov_reg_imm(inst, X86_ECX, $2);
+ x86_clear_reg(inst, X86_EDX);
+ x86_div_reg(inst, X86_ECX, 0);
+ x86_mov_reg_reg(inst, X86_EAX, X86_EDX, 4);
+ }
+ break;
+ }
+ }
+ [reg, reg] -> {
+ unsigned char *patch;
+ x86_alu_reg_reg(inst, X86_OR, $2, $2);
+ patch = inst;
+ x86_branch8(inst, X86_CC_NE, 0, 0);
+ inst = throw_builtin(inst, func, JIT_RESULT_DIVISION_BY_ZERO);
+ x86_patch(patch, inst);
+ x86_clear_reg(inst, X86_EDX);
+ x86_div_reg(inst, $2, 0);
+ x86_mov_reg_reg(inst, X86_EAX, X86_EDX, 4);
+ }
+
JIT_OP_INEG: unary
[reg] -> {
x86_neg_reg(inst, $1);