|
|
@ -350,6 +350,601 @@ JIT_OP_IMUL: binary |
|
|
|
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); |
|
|
|