/* This should eventually end up in machdep/, but for now, x86 is the only target, and it's easier this way... */ /************************************************************************* * Some basic information about the the target CPU * *************************************************************************/ #define EAX 0 #define ECX 1 #define EDX 2 #define EBX 3 /* The register in which subroutines return an integer return value */ #define REG_RESULT 0 /* The registers subroutines take their first and second argument in */ #define REG_PAR1 0 #define REG_PAR2 2 /* Three registers that are not used for any of the above */ #define REG_NOPAR1 6 #define REG_NOPAR2 5 #define REG_NOPAR3 3 #define REG_PC_PRE 0 /* The register we use for preloading regs.pc_p */ #define REG_PC_TMP 1 /* Another register that is not the above */ #define SHIFTCOUNT_NREG 1 /* Register that can be used for shiftcount. -1 if any reg will do */ #define MUL_NREG1 0 /* %eax will hold the low 32 bits after a 32x32 mul */ #define MUL_NREG2 2 /* %edx will hold the high 32 bits */ uae_s8 always_used[]={4,-1}; uae_s8 can_byte[]={0,1,2,3,-1}; uae_s8 can_word[]={0,1,2,3,5,6,7,-1}; uae_u8 call_saved[]={0,0,0,0,1,0,0,0}; /* This *should* be the same as call_saved. But: - We might not really know which registers are saved, and which aren't, so we need to preserve some, but don't want to rely on everyone else also saving those registers - Special registers (such like the stack pointer) should not be "preserved" by pushing, even though they are "saved" across function calls */ uae_u8 need_to_preserve[]={1,1,1,1,0,1,1,1}; /* Whether classes of instructions do or don't clobber the native flags */ #define CLOBBER_MOV #define CLOBBER_LEA #define CLOBBER_CMOV #define CLOBBER_POP #define CLOBBER_PUSH #define CLOBBER_SUB clobber_flags() #define CLOBBER_SBB clobber_flags() #define CLOBBER_CMP clobber_flags() #define CLOBBER_ADD clobber_flags() #define CLOBBER_ADC clobber_flags() #define CLOBBER_AND clobber_flags() #define CLOBBER_OR clobber_flags() #define CLOBBER_XOR clobber_flags() #define CLOBBER_ROL clobber_flags() #define CLOBBER_ROR clobber_flags() #define CLOBBER_SHLL clobber_flags() #define CLOBBER_SHRL clobber_flags() #define CLOBBER_SHRA clobber_flags() #define CLOBBER_TEST clobber_flags() #define CLOBBER_CL16 #define CLOBBER_CL8 #define CLOBBER_SE16 #define CLOBBER_SE8 #define CLOBBER_ZE16 #define CLOBBER_ZE8 #define CLOBBER_SW16 clobber_flags() #define CLOBBER_SW32 #define CLOBBER_SETCC #define CLOBBER_MUL clobber_flags() #define CLOBBER_BT clobber_flags() #define CLOBBER_BSF clobber_flags() /************************************************************************* * Actual encoding of the instructions on the target CPU * *************************************************************************/ static int have_rat_stall; /* Partial registers stalls? */ static int have_cmov; /* We need to generate different code if we don't have cmov */ STATIC_INLINE uae_u16 swap16 (uae_u16 x) { return ((x&0xff00)>>8)|((x&0x00ff)<<8); } STATIC_INLINE uae_u32 swap32(uae_u32 x) { return ((x&0xff00)<<8)|((x&0x00ff)<<24)|((x&0xff0000)>>8)|((x&0xff000000)>>24); } STATIC_INLINE int isbyte(uae_s32 x) { return (x>=-128 && x<=127); } LOWFUNC(NONE,WRITE,1,raw_push_l_r,(R4 r)) { emit_byte(0x50+r); } LENDFUNC(NONE,WRITE,1,raw_push_l_r,(R4 r)) LOWFUNC(NONE,READ,1,raw_pop_l_r,(R4 r)) { emit_byte(0x58+r); } LENDFUNC(NONE,READ,1,raw_pop_l_r,(R4 r)) LOWFUNC(WRITE,NONE,2,raw_bt_l_ri,(R4 r, IMM i)) { emit_byte(0x0f); emit_byte(0xba); emit_byte(0xe0+r); emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_bt_l_ri,(R4 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_bt_l_rr,(R4 r, R4 b)) { emit_byte(0x0f); emit_byte(0xa3); emit_byte(0xc0+8*b+r); } LENDFUNC(WRITE,NONE,2,raw_bt_l_rr,(R4 r, R4 b)) LOWFUNC(WRITE,NONE,2,raw_btc_l_ri,(RW4 r, IMM i)) { emit_byte(0x0f); emit_byte(0xba); emit_byte(0xf8+r); emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_btc_l_ri,(RW4 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_btc_l_rr,(RW4 r, R4 b)) { emit_byte(0x0f); emit_byte(0xbb); emit_byte(0xc0+8*b+r); } LENDFUNC(WRITE,NONE,2,raw_btc_l_rr,(RW4 r, R4 b)) LOWFUNC(WRITE,NONE,2,raw_btr_l_ri,(RW4 r, IMM i)) { emit_byte(0x0f); emit_byte(0xba); emit_byte(0xf0+r); emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_btr_l_ri,(RW4 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_btr_l_rr,(RW4 r, R4 b)) { emit_byte(0x0f); emit_byte(0xb3); emit_byte(0xc0+8*b+r); } LENDFUNC(WRITE,NONE,2,raw_btr_l_rr,(RW4 r, R4 b)) LOWFUNC(WRITE,NONE,2,raw_bts_l_ri,(RW4 r, IMM i)) { emit_byte(0x0f); emit_byte(0xba); emit_byte(0xe8+r); emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_bts_l_ri,(RW4 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_bts_l_rr,(RW4 r, R4 b)) { emit_byte(0x0f); emit_byte(0xab); emit_byte(0xc0+8*b+r); } LENDFUNC(WRITE,NONE,2,raw_bts_l_rr,(RW4 r, R4 b)) LOWFUNC(WRITE,NONE,2,raw_sub_w_ri,(RW2 d, IMM i)) { emit_byte(0x66); if (isbyte(i)) { emit_byte(0x83); emit_byte(0xe8+d); emit_byte(i); } else { emit_byte(0x81); emit_byte(0xe8+d); emit_word(i); } } LENDFUNC(WRITE,NONE,2,raw_sub_w_ri,(RW2 d, IMM i)) LOWFUNC(NONE,WRITE,2,raw_mov_l_mi,(MEMW d, IMM s)) { emit_byte(0xc7); emit_byte(0x05); emit_long(d); emit_long(s); } LENDFUNC(NONE,WRITE,2,raw_mov_l_mi,(MEMW d, IMM s)) LOWFUNC(NONE,WRITE,2,raw_mov_w_mi,(MEMW d, IMM s)) { emit_byte(0x66); emit_byte(0xc7); emit_byte(0x05); emit_long(d); emit_word(s); } LENDFUNC(NONE,WRITE,2,raw_mov_w_mi,(MEMW d, IMM s)) LOWFUNC(NONE,WRITE,2,raw_mov_b_mi,(MEMW d, IMM s)) { emit_byte(0xc6); emit_byte(0x05); emit_long(d); emit_byte(s); } LENDFUNC(NONE,WRITE,2,raw_mov_b_mi,(MEMW d, IMM s)) LOWFUNC(WRITE,RMW,2,raw_rol_b_mi,(MEMRW d, IMM i)) { emit_byte(0xc0); emit_byte(0x05); emit_long(d); emit_byte(i); } LENDFUNC(WRITE,RMW,2,raw_rol_b_mi,(MEMRW d, IMM i)) LOWFUNC(WRITE,NONE,2,raw_rol_b_ri,(RW1 r, IMM i)) { emit_byte(0xc0); emit_byte(0xc0+r); emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_rol_b_ri,(RW1 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_rol_w_ri,(RW2 r, IMM i)) { emit_byte(0x66); emit_byte(0xc1); emit_byte(0xc0+r); emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_rol_w_ri,(RW2 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_rol_l_ri,(RW4 r, IMM i)) { emit_byte(0xc1); emit_byte(0xc0+r); emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_rol_l_ri,(RW4 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_rol_l_rr,(RW4 d, R1 r)) { emit_byte(0xd3); emit_byte(0xc0+d); } LENDFUNC(WRITE,NONE,2,raw_rol_l_rr,(RW4 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_rol_w_rr,(RW2 d, R1 r)) { emit_byte(0x66); emit_byte(0xd3); emit_byte(0xc0+d); } LENDFUNC(WRITE,NONE,2,raw_rol_w_rr,(RW2 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_rol_b_rr,(RW1 d, R1 r)) { emit_byte(0xd2); emit_byte(0xc0+d); } LENDFUNC(WRITE,NONE,2,raw_rol_b_rr,(RW1 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_shll_l_rr,(RW4 d, R1 r)) { emit_byte(0xd3); emit_byte(0xe0+d); } LENDFUNC(WRITE,NONE,2,raw_shll_l_rr,(RW4 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_shll_w_rr,(RW2 d, R1 r)) { emit_byte(0x66); emit_byte(0xd3); emit_byte(0xe0+d); } LENDFUNC(WRITE,NONE,2,raw_shll_w_rr,(RW2 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_shll_b_rr,(RW1 d, R1 r)) { emit_byte(0xd2); emit_byte(0xe0+d); } LENDFUNC(WRITE,NONE,2,raw_shll_b_rr,(RW1 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_ror_b_ri,(RW1 r, IMM i)) { emit_byte(0xc0); emit_byte(0xc8+r); emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_ror_b_ri,(RW1 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_ror_w_ri,(RW2 r, IMM i)) { emit_byte(0x66); emit_byte(0xc1); emit_byte(0xc8+r); emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_ror_w_ri,(RW2 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_ror_l_ri,(RW4 r, IMM i)) { emit_byte(0xc1); emit_byte(0xc8+r); emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_ror_l_ri,(RW4 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_ror_l_rr,(RW4 d, R1 r)) { emit_byte(0xd3); emit_byte(0xc8+d); } LENDFUNC(WRITE,NONE,2,raw_ror_l_rr,(RW4 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_ror_w_rr,(RW2 d, R1 r)) { emit_byte(0x66); emit_byte(0xd3); emit_byte(0xc8+d); } LENDFUNC(WRITE,NONE,2,raw_ror_w_rr,(RW2 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_ror_b_rr,(RW1 d, R1 r)) { emit_byte(0xd2); emit_byte(0xc8+d); } LENDFUNC(WRITE,NONE,2,raw_ror_b_rr,(RW1 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_shrl_l_rr,(RW4 d, R1 r)) { emit_byte(0xd3); emit_byte(0xe8+d); } LENDFUNC(WRITE,NONE,2,raw_shrl_l_rr,(RW4 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_shrl_w_rr,(RW2 d, R1 r)) { emit_byte(0x66); emit_byte(0xd3); emit_byte(0xe8+d); } LENDFUNC(WRITE,NONE,2,raw_shrl_w_rr,(RW2 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_shrl_b_rr,(RW1 d, R1 r)) { emit_byte(0xd2); emit_byte(0xe8+d); } LENDFUNC(WRITE,NONE,2,raw_shrl_b_rr,(RW1 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_shra_l_rr,(RW4 d, R1 r)) { emit_byte(0xd3); emit_byte(0xf8+d); } LENDFUNC(WRITE,NONE,2,raw_shra_l_rr,(RW4 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_shra_w_rr,(RW2 d, R1 r)) { emit_byte(0x66); emit_byte(0xd3); emit_byte(0xf8+d); } LENDFUNC(WRITE,NONE,2,raw_shra_w_rr,(RW2 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_shra_b_rr,(RW1 d, R1 r)) { emit_byte(0xd2); emit_byte(0xf8+d); } LENDFUNC(WRITE,NONE,2,raw_shra_b_rr,(RW1 d, R1 r)) LOWFUNC(WRITE,NONE,2,raw_shll_l_ri,(RW4 r, IMM i)) { emit_byte(0xc1); emit_byte(0xe0+r); emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_shll_l_ri,(RW4 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_shll_w_ri,(RW2 r, IMM i)) { emit_byte(0x66); emit_byte(0xc1); emit_byte(0xe0+r); emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_shll_w_ri,(RW2 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_shll_b_ri,(RW1 r, IMM i)) { emit_byte(0xc0); emit_byte(0xe0+r); emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_shll_b_ri,(RW1 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_shrl_l_ri,(RW4 r, IMM i)) { emit_byte(0xc1); emit_byte(0xe8+r); emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_shrl_l_ri,(RW4 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_shrl_w_ri,(RW2 r, IMM i)) { emit_byte(0x66); emit_byte(0xc1); emit_byte(0xe8+r); emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_shrl_w_ri,(RW2 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_shrl_b_ri,(RW1 r, IMM i)) { emit_byte(0xc0); emit_byte(0xe8+r); emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_shrl_b_ri,(RW1 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_shra_l_ri,(RW4 r, IMM i)) { emit_byte(0xc1); emit_byte(0xf8+r); emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_shra_l_ri,(RW4 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_shra_w_ri,(RW2 r, IMM i)) { emit_byte(0x66); emit_byte(0xc1); emit_byte(0xf8+r); emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_shra_w_ri,(RW2 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_shra_b_ri,(RW1 r, IMM i)) { emit_byte(0xc0); emit_byte(0xf8+r); emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_shra_b_ri,(RW1 r, IMM i)) LOWFUNC(WRITE,NONE,1,raw_sahf,(R2 dummy_ah)) { emit_byte(0x9e); } LENDFUNC(WRITE,NONE,1,raw_sahf,(R2 dummy_ah)) LOWFUNC(NONE,NONE,1,raw_cpuid,(R4 dummy_eax)) { emit_byte(0x0f); emit_byte(0xa2); } LENDFUNC(NONE,NONE,1,raw_cpuid,(R4 dummy_eax)) LOWFUNC(READ,NONE,1,raw_lahf,(W2 dummy_ah)) { emit_byte(0x9f); } LENDFUNC(READ,NONE,1,raw_lahf,(W2 dummy_ah)) LOWFUNC(READ,NONE,2,raw_setcc,(W1 d, IMM cc)) { emit_byte(0x0f); emit_byte(0x90+cc); emit_byte(0xc0+d); } LENDFUNC(READ,NONE,2,raw_setcc,(W1 d, IMM cc)) LOWFUNC(READ,WRITE,2,raw_setcc_m,(MEMW d, IMM cc)) { emit_byte(0x0f); emit_byte(0x90+cc); emit_byte(0x05); emit_long(d); } LENDFUNC(READ,WRITE,2,raw_setcc_m,(MEMW d, IMM cc)) LOWFUNC(READ,NONE,3,raw_cmov_l_rr,(RW4 d, R4 s, IMM cc)) { if (have_cmov) { emit_byte(0x0f); emit_byte(0x40+cc); emit_byte(0xc0+8*d+s); } else { /* replacement using branch and mov */ int uncc=(cc^1); emit_byte(0x70+uncc); emit_byte(2); /* skip next 2 bytes if not cc=true */ emit_byte(0x89); emit_byte(0xc0+8*s+d); } } LENDFUNC(READ,NONE,3,raw_cmov_l_rr,(RW4 d, R4 s, IMM cc)) LOWFUNC(WRITE,NONE,2,raw_bsf_l_rr,(W4 d, R4 s)) { emit_byte(0x0f); emit_byte(0xbc); emit_byte(0xc0+8*d+s); } LENDFUNC(WRITE,NONE,2,raw_bsf_l_rr,(W4 d, R4 s)) LOWFUNC(NONE,NONE,2,raw_sign_extend_16_rr,(W4 d, R2 s)) { emit_byte(0x0f); emit_byte(0xbf); emit_byte(0xc0+8*d+s); } LENDFUNC(NONE,NONE,2,raw_sign_extend_16_rr,(W4 d, R2 s)) LOWFUNC(NONE,NONE,2,raw_sign_extend_8_rr,(W4 d, R1 s)) { emit_byte(0x0f); emit_byte(0xbe); emit_byte(0xc0+8*d+s); } LENDFUNC(NONE,NONE,2,raw_sign_extend_8_rr,(W4 d, R1 s)) LOWFUNC(NONE,NONE,2,raw_zero_extend_16_rr,(W4 d, R2 s)) { emit_byte(0x0f); emit_byte(0xb7); emit_byte(0xc0+8*d+s); } LENDFUNC(NONE,NONE,2,raw_zero_extend_16_rr,(W4 d, R2 s)) LOWFUNC(NONE,NONE,2,raw_zero_extend_8_rr,(W4 d, R1 s)) { emit_byte(0x0f); emit_byte(0xb6); emit_byte(0xc0+8*d+s); } LENDFUNC(NONE,NONE,2,raw_zero_extend_8_rr,(W4 d, R1 s)) LOWFUNC(NONE,NONE,2,raw_imul_32_32,(RW4 d, R4 s)) { emit_byte(0x0f); emit_byte(0xaf); emit_byte(0xc0+8*d+s); } LENDFUNC(NONE,NONE,2,raw_imul_32_32,(RW4 d, R4 s)) LOWFUNC(NONE,NONE,2,raw_imul_64_32,(RW4 d, RW4 s)) { if (d!=MUL_NREG1 || s!=MUL_NREG2) abort(); emit_byte(0xf7); emit_byte(0xea); } LENDFUNC(NONE,NONE,2,raw_imul_64_32,(RW4 d, RW4 s)) LOWFUNC(NONE,NONE,2,raw_mul_64_32,(RW4 d, RW4 s)) { if (d!=MUL_NREG1 || s!=MUL_NREG2) { write_log ("JIT: Bad register in MUL: d=%d, s=%d\n", d, s); abort(); } emit_byte(0xf7); emit_byte(0xe2); } LENDFUNC(NONE,NONE,2,raw_mul_64_32,(RW4 d, RW4 s)) LOWFUNC(NONE,NONE,2,raw_mul_32_32,(RW4 d, R4 s)) { abort(); /* %^$&%^$%#^ x86! */ emit_byte(0x0f); emit_byte(0xaf); emit_byte(0xc0+8*d+s); } LENDFUNC(NONE,NONE,2,raw_mul_32_32,(RW4 d, R4 s)) LOWFUNC(NONE,NONE,2,raw_mov_b_rr,(W1 d, R1 s)) { emit_byte(0x88); emit_byte(0xc0+8*s+d); } LENDFUNC(NONE,NONE,2,raw_mov_b_rr,(W1 d, R1 s)) LOWFUNC(NONE,NONE,2,raw_mov_w_rr,(W2 d, R2 s)) { emit_byte(0x66); emit_byte(0x89); emit_byte(0xc0+8*s+d); } LENDFUNC(NONE,NONE,2,raw_mov_w_rr,(W2 d, R2 s)) LOWFUNC(NONE,READ,4,raw_mov_l_rrm_indexed,(W4 d,R4 baser, R4 index, IMM factor)) { int isebp=(baser==5)?0x40:0; int fi; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: abort(); } emit_byte(0x8b); emit_byte(0x04+8*d+isebp); emit_byte(baser+8*index+0x40*fi); if (isebp) emit_byte(0x00); } LENDFUNC(NONE,READ,4,raw_mov_l_rrm_indexed,(W4 d,R4 baser, R4 index, IMM factor)) LOWFUNC(NONE,READ,4,raw_mov_w_rrm_indexed,(W2 d, R4 baser, R4 index, IMM factor)) { int fi; int isebp; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: abort(); } isebp=(baser==5)?0x40:0; emit_byte(0x66); emit_byte(0x8b); emit_byte(0x04+8*d+isebp); emit_byte(baser+8*index+0x40*fi); if (isebp) emit_byte(0x00); } LENDFUNC(NONE,READ,4,raw_mov_w_rrm_indexed,(W2 d, R4 baser, R4 index, IMM factor)) LOWFUNC(NONE,READ,4,raw_mov_b_rrm_indexed,(W1 d, R4 baser, R4 index, IMM factor)) { int fi; int isebp; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: abort(); } isebp=(baser==5)?0x40:0; emit_byte(0x8a); emit_byte(0x04+8*d+isebp); emit_byte(baser+8*index+0x40*fi); if (isebp) emit_byte(0x00); } LENDFUNC(NONE,READ,4,raw_mov_b_rrm_indexed,(W1 d, R4 baser, R4 index, IMM factor)) LOWFUNC(NONE,WRITE,4,raw_mov_l_mrr_indexed,(R4 baser, R4 index, IMM factor, R4 s)) { int fi; int isebp; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: abort(); } isebp=(baser==5)?0x40:0; emit_byte(0x89); emit_byte(0x04+8*s+isebp); emit_byte(baser+8*index+0x40*fi); if (isebp) emit_byte(0x00); } LENDFUNC(NONE,WRITE,4,raw_mov_l_mrr_indexed,(R4 baser, R4 index, IMM factor, R4 s)) LOWFUNC(NONE,WRITE,4,raw_mov_w_mrr_indexed,(R4 baser, R4 index, IMM factor, R2 s)) { int fi; int isebp; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: abort(); } isebp=(baser==5)?0x40:0; emit_byte(0x66); emit_byte(0x89); emit_byte(0x04+8*s+isebp); emit_byte(baser+8*index+0x40*fi); if (isebp) emit_byte(0x00); } LENDFUNC(NONE,WRITE,4,raw_mov_w_mrr_indexed,(R4 baser, R4 index, IMM factor, R2 s)) LOWFUNC(NONE,WRITE,4,raw_mov_b_mrr_indexed,(R4 baser, R4 index, IMM factor, R1 s)) { int fi; int isebp; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: abort(); } isebp=(baser==5)?0x40:0; emit_byte(0x88); emit_byte(0x04+8*s+isebp); emit_byte(baser+8*index+0x40*fi); if (isebp) emit_byte(0x00); } LENDFUNC(NONE,WRITE,4,raw_mov_b_mrr_indexed,(R4 baser, R4 index, IMM factor, R1 s)) LOWFUNC(NONE,WRITE,5,raw_mov_l_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R4 s)) { int fi; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: abort(); } emit_byte(0x89); emit_byte(0x84+8*s); emit_byte(baser+8*index+0x40*fi); emit_long(base); } LENDFUNC(NONE,WRITE,5,raw_mov_l_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R4 s)) LOWFUNC(NONE,WRITE,5,raw_mov_w_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R2 s)) { int fi; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: abort(); } emit_byte(0x66); emit_byte(0x89); emit_byte(0x84+8*s); emit_byte(baser+8*index+0x40*fi); emit_long(base); } LENDFUNC(NONE,WRITE,5,raw_mov_w_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R2 s)) LOWFUNC(NONE,WRITE,5,raw_mov_b_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R1 s)) { int fi; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: abort(); } emit_byte(0x88); emit_byte(0x84+8*s); emit_byte(baser+8*index+0x40*fi); emit_long(base); } LENDFUNC(NONE,WRITE,5,raw_mov_b_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R1 s)) LOWFUNC(NONE,READ,5,raw_mov_l_brrm_indexed,(W4 d, IMM base, R4 baser, R4 index, IMM factor)) { int fi; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: abort(); } emit_byte(0x8b); emit_byte(0x84+8*d); emit_byte(baser+8*index+0x40*fi); emit_long(base); } LENDFUNC(NONE,READ,5,raw_mov_l_brrm_indexed,(W4 d, IMM base, R4 baser, R4 index, IMM factor)) LOWFUNC(NONE,READ,5,raw_mov_w_brrm_indexed,(W2 d, IMM base, R4 baser, R4 index, IMM factor)) { int fi; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: abort(); } emit_byte(0x66); emit_byte(0x8b); emit_byte(0x84+8*d); emit_byte(baser+8*index+0x40*fi); emit_long(base); } LENDFUNC(NONE,READ,5,raw_mov_w_brrm_indexed,(W2 d, IMM base, R4 baser, R4 index, IMM factor)) LOWFUNC(NONE,READ,5,raw_mov_b_brrm_indexed,(W1 d, IMM base, R4 baser, R4 index, IMM factor)) { int fi; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: abort(); } emit_byte(0x8a); emit_byte(0x84+8*d); emit_byte(baser+8*index+0x40*fi); emit_long(base); } LENDFUNC(NONE,READ,5,raw_mov_b_brrm_indexed,(W1 d, IMM base, R4 baser, R4 index, IMM factor)) LOWFUNC(NONE,READ,4,raw_mov_l_rm_indexed,(W4 d, IMM base, R4 index, IMM factor)) { int fi; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: write_log ("JIT: Bad factor %d in mov_l_rm_indexed!\n", factor); abort(); } emit_byte(0x8b); emit_byte(0x04+8*d); emit_byte(0x05+8*index+64*fi); emit_long(base); } LENDFUNC(NONE,READ,4,raw_mov_l_rm_indexed,(W4 d, IMM base, R4 index, IMM factor)) LOWFUNC(NONE,READ,5,raw_cmov_l_rm_indexed,(W4 d, IMM base, R4 index, IMM factor, IMM cond)) { int fi; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: write_log ("JIT: Bad factor %d in mov_l_rm_indexed!\n", factor); abort(); } if (have_cmov) { emit_byte(0x0f); emit_byte(0x40+cond); emit_byte(0x04+8*d); emit_byte(0x05+8*index+64*fi); emit_long(base); } else { /* replacement using branch and mov */ int uncc=(cond^1); emit_byte(0x70+uncc); emit_byte(7); /* skip next 7 bytes if not cc=true */ emit_byte(0x8b); emit_byte(0x04+8*d); emit_byte(0x05+8*index+64*fi); emit_long(base); } } LENDFUNC(NONE,READ,5,raw_cmov_l_rm_indexed,(W4 d, IMM base, R4 index, IMM factor, IMM cond)) LOWFUNC(NONE,READ,3,raw_cmov_l_rm,(W4 d, IMM mem, IMM cond)) { if (have_cmov) { emit_byte(0x0f); emit_byte(0x40+cond); emit_byte(0x05+8*d); emit_long(mem); } else { /* replacement using branch and mov */ int uncc=(cond^1); emit_byte(0x70+uncc); emit_byte(6); /* skip next 6 bytes if not cc=true */ emit_byte(0x8b); emit_byte(0x05+8*d); emit_long(mem); } } LENDFUNC(NONE,READ,3,raw_cmov_l_rm,(W4 d, IMM mem, IMM cond)) LOWFUNC(NONE,READ,3,raw_mov_l_rR,(W4 d, R4 s, IMM offset)) { emit_byte(0x8b); emit_byte(0x40+8*d+s); emit_byte(offset); } LENDFUNC(NONE,READ,3,raw_mov_l_rR,(W4 d, R4 s, IMM offset)) LOWFUNC(NONE,READ,3,raw_mov_w_rR,(W2 d, R4 s, IMM offset)) { emit_byte(0x66); emit_byte(0x8b); emit_byte(0x40+8*d+s); emit_byte(offset); } LENDFUNC(NONE,READ,3,raw_mov_w_rR,(W2 d, R4 s, IMM offset)) LOWFUNC(NONE,READ,3,raw_mov_b_rR,(W1 d, R4 s, IMM offset)) { emit_byte(0x8a); emit_byte(0x40+8*d+s); emit_byte(offset); } LENDFUNC(NONE,READ,3,raw_mov_b_rR,(W1 d, R4 s, IMM offset)) LOWFUNC(NONE,READ,3,raw_mov_l_brR,(W4 d, R4 s, IMM offset)) { emit_byte(0x8b); emit_byte(0x80+8*d+s); emit_long(offset); } LENDFUNC(NONE,READ,3,raw_mov_l_brR,(W4 d, R4 s, IMM offset)) LOWFUNC(NONE,READ,3,raw_mov_w_brR,(W2 d, R4 s, IMM offset)) { emit_byte(0x66); emit_byte(0x8b); emit_byte(0x80+8*d+s); emit_long(offset); } LENDFUNC(NONE,READ,3,raw_mov_w_brR,(W2 d, R4 s, IMM offset)) LOWFUNC(NONE,READ,3,raw_mov_b_brR,(W1 d, R4 s, IMM offset)) { emit_byte(0x8a); emit_byte(0x80+8*d+s); emit_long(offset); } LENDFUNC(NONE,READ,3,raw_mov_b_brR,(W1 d, R4 s, IMM offset)) LOWFUNC(NONE,WRITE,3,raw_mov_l_Ri,(R4 d, IMM i, IMM offset)) { emit_byte(0xc7); emit_byte(0x40+d); emit_byte(offset); emit_long(i); } LENDFUNC(NONE,WRITE,3,raw_mov_l_Ri,(R4 d, IMM i, IMM offset)) LOWFUNC(NONE,WRITE,3,raw_mov_w_Ri,(R4 d, IMM i, IMM offset)) { emit_byte(0x66); emit_byte(0xc7); emit_byte(0x40+d); emit_byte(offset); emit_word(i); } LENDFUNC(NONE,WRITE,3,raw_mov_w_Ri,(R4 d, IMM i, IMM offset)) LOWFUNC(NONE,WRITE,3,raw_mov_b_Ri,(R4 d, IMM i, IMM offset)) { emit_byte(0xc6); emit_byte(0x40+d); emit_byte(offset); emit_byte(i); } LENDFUNC(NONE,WRITE,3,raw_mov_b_Ri,(R4 d, IMM i, IMM offset)) LOWFUNC(NONE,WRITE,3,raw_mov_l_Rr,(R4 d, R4 s, IMM offset)) { emit_byte(0x89); emit_byte(0x40+8*s+d); emit_byte(offset); } LENDFUNC(NONE,WRITE,3,raw_mov_l_Rr,(R4 d, R4 s, IMM offset)) LOWFUNC(NONE,WRITE,3,raw_mov_w_Rr,(R4 d, R2 s, IMM offset)) { emit_byte(0x66); emit_byte(0x89); emit_byte(0x40+8*s+d); emit_byte(offset); } LENDFUNC(NONE,WRITE,3,raw_mov_w_Rr,(R4 d, R2 s, IMM offset)) LOWFUNC(NONE,WRITE,3,raw_mov_b_Rr,(R4 d, R1 s, IMM offset)) { emit_byte(0x88); emit_byte(0x40+8*s+d); emit_byte(offset); } LENDFUNC(NONE,WRITE,3,raw_mov_b_Rr,(R4 d, R1 s, IMM offset)) LOWFUNC(NONE,NONE,3,raw_lea_l_brr,(W4 d, R4 s, IMM offset)) { emit_byte(0x8d); emit_byte(0x80+8*d+s); emit_long(offset); } LENDFUNC(NONE,NONE,3,raw_lea_l_brr,(W4 d, R4 s, IMM offset)) LOWFUNC(NONE,NONE,5,raw_lea_l_brr_indexed,(W4 d, R4 s, R4 index, IMM factor, IMM offset)) { int fi; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: abort(); } emit_byte(0x8d); emit_byte(0x84+8*d); emit_byte(0x40*fi+8*index+s); emit_long(offset); } LENDFUNC(NONE,NONE,5,raw_lea_l_brr_indexed,(W4 d, R4 s, R4 index, IMM factor, IMM offset)) LOWFUNC(NONE,NONE,4,raw_lea_l_rr_indexed,(W4 d, R4 s, R4 index, IMM factor)) { int isebp=(s==5)?0x40:0; int fi; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: abort(); } emit_byte(0x8d); emit_byte(0x04+8*d+isebp); emit_byte(0x40*fi+8*index+s); if (isebp) emit_byte(0); } LENDFUNC(NONE,NONE,4,raw_lea_l_rr_indexed,(W4 d, R4 s, R4 index, IMM factor)) LOWFUNC(NONE,WRITE,3,raw_mov_l_bRr,(R4 d, R4 s, IMM offset)) { emit_byte(0x89); emit_byte(0x80+8*s+d); emit_long(offset); } LENDFUNC(NONE,WRITE,3,raw_mov_l_bRr,(R4 d, R4 s, IMM offset)) LOWFUNC(NONE,WRITE,3,raw_mov_w_bRr,(R4 d, R2 s, IMM offset)) { emit_byte(0x66); emit_byte(0x89); emit_byte(0x80+8*s+d); emit_long(offset); } LENDFUNC(NONE,WRITE,3,raw_mov_w_bRr,(R4 d, R2 s, IMM offset)) LOWFUNC(NONE,WRITE,3,raw_mov_b_bRr,(R4 d, R1 s, IMM offset)) { emit_byte(0x88); emit_byte(0x80+8*s+d); emit_long(offset); } LENDFUNC(NONE,WRITE,3,raw_mov_b_bRr,(R4 d, R1 s, IMM offset)) LOWFUNC(NONE,NONE,1,raw_bswap_32,(RW4 r)) { emit_byte(0x0f); emit_byte(0xc8+r); } LENDFUNC(NONE,NONE,1,raw_bswap_32,(RW4 r)) LOWFUNC(WRITE,NONE,1,raw_bswap_16,(RW2 r)) { emit_byte(0x66); emit_byte(0xc1); emit_byte(0xc0+r); emit_byte(0x08); } LENDFUNC(WRITE,NONE,1,raw_bswap_16,(RW2 r)) LOWFUNC(NONE,NONE,2,raw_mov_l_rr,(W4 d, R4 s)) { emit_byte(0x89); emit_byte(0xc0+8*s+d); } LENDFUNC(NONE,NONE,2,raw_mov_l_rr,(W4 d, R4 s)) LOWFUNC(NONE,WRITE,2,raw_mov_l_mr,(IMM d, R4 s)) { emit_byte(0x89); emit_byte(0x05+8*s); emit_long(d); } LENDFUNC(NONE,WRITE,2,raw_mov_l_mr,(IMM d, R4 s)) LOWFUNC(NONE,READ,2,raw_mov_l_rm,(W4 d, MEMR s)) { emit_byte(0x8b); emit_byte(0x05+8*d); emit_long(s); } LENDFUNC(NONE,READ,2,raw_mov_l_rm,(W4 d, MEMR s)) LOWFUNC(NONE,WRITE,2,raw_mov_w_mr,(IMM d, R2 s)) { emit_byte(0x66); emit_byte(0x89); emit_byte(0x05+8*s); emit_long(d); } LENDFUNC(NONE,WRITE,2,raw_mov_w_mr,(IMM d, R2 s)) LOWFUNC(NONE,READ,2,raw_mov_w_rm,(W2 d, IMM s)) { emit_byte(0x66); emit_byte(0x8b); emit_byte(0x05+8*d); emit_long(s); } LENDFUNC(NONE,READ,2,raw_mov_w_rm,(W2 d, IMM s)) LOWFUNC(NONE,WRITE,2,raw_mov_b_mr,(IMM d, R1 s)) { emit_byte(0x88); emit_byte(0x05+8*s); emit_long(d); } LENDFUNC(NONE,WRITE,2,raw_mov_b_mr,(IMM d, R1 s)) LOWFUNC(NONE,READ,2,raw_mov_b_rm,(W1 d, IMM s)) { emit_byte(0x8a); emit_byte(0x05+8*d); emit_long(s); } LENDFUNC(NONE,READ,2,raw_mov_b_rm,(W1 d, IMM s)) LOWFUNC(NONE,NONE,2,raw_mov_l_ri,(W4 d, IMM s)) { emit_byte(0xb8+d); emit_long(s); } LENDFUNC(NONE,NONE,2,raw_mov_l_ri,(W4 d, IMM s)) LOWFUNC(NONE,NONE,2,raw_mov_w_ri,(W2 d, IMM s)) { emit_byte(0x66); emit_byte(0xb8+d); emit_word(s); } LENDFUNC(NONE,NONE,2,raw_mov_w_ri,(W2 d, IMM s)) LOWFUNC(NONE,NONE,2,raw_mov_b_ri,(W1 d, IMM s)) { emit_byte(0xb0+d); emit_byte(s); } LENDFUNC(NONE,NONE,2,raw_mov_b_ri,(W1 d, IMM s)) LOWFUNC(RMW,RMW,2,raw_adc_l_mi,(MEMRW d, IMM s)) { emit_byte(0x81); emit_byte(0x15); emit_long(d); emit_long(s); } LENDFUNC(RMW,RMW,2,raw_adc_l_mi,(MEMRW d, IMM s)) LOWFUNC(WRITE,RMW,2,raw_add_l_mi,(IMM d, IMM s)) { emit_byte(0x81); emit_byte(0x05); emit_long(d); emit_long(s); } LENDFUNC(WRITE,RMW,2,raw_add_l_mi,(IMM d, IMM s)) LOWFUNC(WRITE,RMW,2,raw_add_w_mi,(IMM d, IMM s)) { emit_byte(0x66); emit_byte(0x81); emit_byte(0x05); emit_long(d); emit_word(s); } LENDFUNC(WRITE,RMW,2,raw_add_w_mi,(IMM d, IMM s)) LOWFUNC(WRITE,RMW,2,raw_add_b_mi,(IMM d, IMM s)) { emit_byte(0x80); emit_byte(0x05); emit_long(d); emit_byte(s); } LENDFUNC(WRITE,RMW,2,raw_add_b_mi,(IMM d, IMM s)) LOWFUNC(WRITE,NONE,2,raw_test_l_ri,(R4 d, IMM i)) { emit_byte(0xf7); emit_byte(0xc0+d); emit_long(i); } LENDFUNC(WRITE,NONE,2,raw_test_l_ri,(R4 d, IMM i)) LOWFUNC(WRITE,NONE,2,raw_test_l_rr,(R4 d, R4 s)) { emit_byte(0x85); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_test_l_rr,(R4 d, R4 s)) LOWFUNC(WRITE,NONE,2,raw_test_w_rr,(R2 d, R2 s)) { emit_byte(0x66); emit_byte(0x85); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_test_w_rr,(R2 d, R2 s)) LOWFUNC(WRITE,NONE,2,raw_test_b_rr,(R1 d, R1 s)) { emit_byte(0x84); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_test_b_rr,(R1 d, R1 s)) LOWFUNC(WRITE,NONE,2,raw_and_l_ri,(RW4 d, IMM i)) { emit_byte(0x81); emit_byte(0xe0+d); emit_long(i); } LENDFUNC(WRITE,NONE,2,raw_and_l_ri,(RW4 d, IMM i)) LOWFUNC(WRITE,NONE,2,raw_and_w_ri,(RW2 d, IMM i)) { emit_byte(0x66); emit_byte(0x81); emit_byte(0xe0+d); emit_word(i); } LENDFUNC(WRITE,NONE,2,raw_and_w_ri,(RW2 d, IMM i)) LOWFUNC(WRITE,NONE,2,raw_and_l,(RW4 d, R4 s)) { emit_byte(0x21); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_and_l,(RW4 d, R4 s)) LOWFUNC(WRITE,NONE,2,raw_and_w,(RW2 d, R2 s)) { emit_byte(0x66); emit_byte(0x21); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_and_w,(RW2 d, R2 s)) LOWFUNC(WRITE,NONE,2,raw_and_b,(RW1 d, R1 s)) { emit_byte(0x20); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_and_b,(RW1 d, R1 s)) LOWFUNC(WRITE,NONE,2,raw_or_l_ri,(RW4 d, IMM i)) { emit_byte(0x81); emit_byte(0xc8+d); emit_long(i); } LENDFUNC(WRITE,NONE,2,raw_or_l_ri,(RW4 d, IMM i)) LOWFUNC(WRITE,NONE,2,raw_or_l,(RW4 d, R4 s)) { emit_byte(0x09); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_or_l,(RW4 d, R4 s)) LOWFUNC(WRITE,NONE,2,raw_or_w,(RW2 d, R2 s)) { emit_byte(0x66); emit_byte(0x09); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_or_w,(RW2 d, R2 s)) LOWFUNC(WRITE,NONE,2,raw_or_b,(RW1 d, R1 s)) { emit_byte(0x08); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_or_b,(RW1 d, R1 s)) LOWFUNC(RMW,NONE,2,raw_adc_l,(RW4 d, R4 s)) { emit_byte(0x11); emit_byte(0xc0+8*s+d); } LENDFUNC(RMW,NONE,2,raw_adc_l,(RW4 d, R4 s)) LOWFUNC(RMW,NONE,2,raw_adc_w,(RW2 d, R2 s)) { emit_byte(0x66); emit_byte(0x11); emit_byte(0xc0+8*s+d); } LENDFUNC(RMW,NONE,2,raw_adc_w,(RW2 d, R2 s)) LOWFUNC(RMW,NONE,2,raw_adc_b,(RW1 d, R1 s)) { emit_byte(0x10); emit_byte(0xc0+8*s+d); } LENDFUNC(RMW,NONE,2,raw_adc_b,(RW1 d, R1 s)) LOWFUNC(WRITE,NONE,2,raw_add_l,(RW4 d, R4 s)) { emit_byte(0x01); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_add_l,(RW4 d, R4 s)) LOWFUNC(WRITE,NONE,2,raw_add_w,(RW2 d, R2 s)) { emit_byte(0x66); emit_byte(0x01); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_add_w,(RW2 d, R2 s)) LOWFUNC(WRITE,NONE,2,raw_add_b,(RW1 d, R1 s)) { emit_byte(0x00); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_add_b,(RW1 d, R1 s)) LOWFUNC(WRITE,NONE,2,raw_sub_l_ri,(RW4 d, IMM i)) { if (isbyte(i)) { emit_byte(0x83); emit_byte(0xe8+d); emit_byte(i); } else { emit_byte(0x81); emit_byte(0xe8+d); emit_long(i); } } LENDFUNC(WRITE,NONE,2,raw_sub_l_ri,(RW4 d, IMM i)) LOWFUNC(WRITE,NONE,2,raw_sub_b_ri,(RW1 d, IMM i)) { emit_byte(0x80); emit_byte(0xe8+d); emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_sub_b_ri,(RW1 d, IMM i)) LOWFUNC(WRITE,NONE,2,raw_add_l_ri,(RW4 d, IMM i)) { if (isbyte(i)) { emit_byte(0x83); emit_byte(0xc0+d); emit_byte(i); } else { emit_byte(0x81); emit_byte(0xc0+d); emit_long(i); } } LENDFUNC(WRITE,NONE,2,raw_add_l_ri,(RW4 d, IMM i)) LOWFUNC(WRITE,NONE,2,raw_add_w_ri,(RW2 d, IMM i)) { if (isbyte(i)) { emit_byte(0x66); emit_byte(0x83); emit_byte(0xc0+d); emit_byte(i); } else { emit_byte(0x66); emit_byte(0x81); emit_byte(0xc0+d); emit_word(i); } } LENDFUNC(WRITE,NONE,2,raw_add_w_ri,(RW2 d, IMM i)) LOWFUNC(WRITE,NONE,2,raw_add_b_ri,(RW1 d, IMM i)) { emit_byte(0x80); emit_byte(0xc0+d); emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_add_b_ri,(RW1 d, IMM i)) LOWFUNC(RMW,NONE,2,raw_sbb_l,(RW4 d, R4 s)) { emit_byte(0x19); emit_byte(0xc0+8*s+d); } LENDFUNC(RMW,NONE,2,raw_sbb_l,(RW4 d, R4 s)) LOWFUNC(RMW,NONE,2,raw_sbb_w,(RW2 d, R2 s)) { emit_byte(0x66); emit_byte(0x19); emit_byte(0xc0+8*s+d); } LENDFUNC(RMW,NONE,2,raw_sbb_w,(RW2 d, R2 s)) LOWFUNC(RMW,NONE,2,raw_sbb_b,(RW1 d, R1 s)) { emit_byte(0x18); emit_byte(0xc0+8*s+d); } LENDFUNC(RMW,NONE,2,raw_sbb_b,(RW1 d, R1 s)) LOWFUNC(WRITE,NONE,2,raw_sub_l,(RW4 d, R4 s)) { emit_byte(0x29); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_sub_l,(RW4 d, R4 s)) LOWFUNC(WRITE,NONE,2,raw_sub_w,(RW2 d, R2 s)) { emit_byte(0x66); emit_byte(0x29); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_sub_w,(RW2 d, R2 s)) LOWFUNC(WRITE,NONE,2,raw_sub_b,(RW1 d, R1 s)) { emit_byte(0x28); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_sub_b,(RW1 d, R1 s)) LOWFUNC(WRITE,NONE,2,raw_cmp_l,(R4 d, R4 s)) { emit_byte(0x39); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_cmp_l,(R4 d, R4 s)) LOWFUNC(WRITE,NONE,2,raw_cmp_l_ri,(R4 r, IMM i)) { emit_byte(0x81); emit_byte(0xf8+r); emit_long(i); } LENDFUNC(WRITE,NONE,2,raw_cmp_l_ri,(R4 r, IMM i)) LOWFUNC(WRITE,NONE,2,raw_cmp_w,(R2 d, R2 s)) { emit_byte(0x66); emit_byte(0x39); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_cmp_w,(R2 d, R2 s)) LOWFUNC(WRITE,NONE,2,raw_cmp_b_ri,(R1 d, IMM i)) { emit_byte(0x80); emit_byte(0xf8+d); emit_byte(i); } LENDFUNC(WRITE,NONE,2,raw_cmp_b_ri,(R1 d, IMM i)) LOWFUNC(WRITE,NONE,2,raw_cmp_b,(R1 d, R1 s)) { emit_byte(0x38); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_cmp_b,(R1 d, R1 s)) LOWFUNC(WRITE,READ,4,raw_cmp_l_rm_indexed,(R4 d, IMM offset, R4 index, IMM factor)) { int fi; switch(factor) { case 1: fi=0; break; case 2: fi=1; break; case 4: fi=2; break; case 8: fi=3; break; default: abort(); } emit_byte(0x39); emit_byte(0x04+8*d); emit_byte(5+8*index+0x40*fi); emit_long(offset); } LENDFUNC(WRITE,READ,4,raw_cmp_l_rm_indexed,(R4 d, IMM offset, R4 index, IMM factor)) LOWFUNC(WRITE,NONE,2,raw_xor_l,(RW4 d, R4 s)) { emit_byte(0x31); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_xor_l,(RW4 d, R4 s)) LOWFUNC(WRITE,NONE,2,raw_xor_w,(RW2 d, R2 s)) { emit_byte(0x66); emit_byte(0x31); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_xor_w,(RW2 d, R2 s)) LOWFUNC(WRITE,NONE,2,raw_xor_b,(RW1 d, R1 s)) { emit_byte(0x30); emit_byte(0xc0+8*s+d); } LENDFUNC(WRITE,NONE,2,raw_xor_b,(RW1 d, R1 s)) LOWFUNC(WRITE,RMW,2,raw_sub_l_mi,(MEMRW d, IMM s)) { emit_byte(0x81); emit_byte(0x2d); emit_long(d); emit_long(s); } LENDFUNC(WRITE,RMW,2,raw_sub_l_mi,(MEMRW d, IMM s)) LOWFUNC(WRITE,READ,2,raw_cmp_l_mi,(MEMR d, IMM s)) { emit_byte(0x81); emit_byte(0x3d); emit_long(d); emit_long(s); } LENDFUNC(WRITE,READ,2,raw_cmp_l_mi,(MEMR d, IMM s)) LOWFUNC(NONE,NONE,2,raw_xchg_l_rr,(RW4 r1, RW4 r2)) { emit_byte(0x87); emit_byte(0xc0+8*r1+r2); } LENDFUNC(NONE,NONE,2,raw_xchg_l_rr,(RW4 r1, RW4 r2)) LOWFUNC(READ,WRITE,0,raw_pushfl,(void)) { emit_byte(0x9c); } LENDFUNC(READ,WRITE,0,raw_pushfl,(void)) LOWFUNC(WRITE,READ,0,raw_popfl,(void)) { emit_byte(0x9d); } LENDFUNC(WRITE,READ,0,raw_popfl,(void)) /************************************************************************* * Unoptimizable stuff --- jump * *************************************************************************/ STATIC_INLINE void raw_call_r(R4 r) { emit_byte(0xff); emit_byte(0xd0+r); } STATIC_INLINE void raw_jmp_r(R4 r) { emit_byte(0xff); emit_byte(0xe0+r); } STATIC_INLINE void raw_jmp_m_indexed(uae_u32 base, uae_u32 r, uae_u32 m) { int mu; switch(m) { case 1: mu=0; break; case 2: mu=1; break; case 4: mu=2; break; case 8: mu=3; break; default: abort(); } emit_byte(0xff); emit_byte(0x24); emit_byte(0x05+8*r+0x40*mu); emit_long(base); } STATIC_INLINE void raw_jmp_m(uae_u32 base) { emit_byte(0xff); emit_byte(0x25); emit_long(base); } STATIC_INLINE void raw_call(uae_u32 t) { emit_byte(0xe8); emit_long(t-(uae_u32)target-4); } STATIC_INLINE void raw_jmp(uae_u32 t) { emit_byte(0xe9); emit_long(t-(uae_u32)target-4); } STATIC_INLINE void raw_jl(uae_u32 t) { emit_byte(0x0f); emit_byte(0x8c); emit_long(t-(uae_u32)target-4); } STATIC_INLINE void raw_jz(uae_u32 t) { emit_byte(0x0f); emit_byte(0x84); emit_long(t-(uae_u32)target-4); } STATIC_INLINE void raw_jnz(uae_u32 t) { emit_byte(0x0f); emit_byte(0x85); emit_long(t-(uae_u32)target-4); } STATIC_INLINE void raw_jnz_l_oponly(void) { emit_byte(0x0f); emit_byte(0x85); } STATIC_INLINE void raw_jcc_l_oponly(int cc) { emit_byte(0x0f); emit_byte(0x80+cc); } STATIC_INLINE void raw_jnz_b_oponly(void) { emit_byte(0x75); } STATIC_INLINE void raw_jz_b_oponly(void) { emit_byte(0x74); } STATIC_INLINE void raw_jmp_l_oponly(void) { emit_byte(0xe9); } STATIC_INLINE void raw_jmp_b_oponly(void) { emit_byte(0xeb); } STATIC_INLINE void raw_ret(void) { emit_byte(0xc3); } STATIC_INLINE void raw_nop(void) { emit_byte(0x90); } STATIC_INLINE void raw_emit_nop_filler (int nbytes) { /* Source: GNU Binutils 2.12.90.0.15 */ /* Various efficient no-op patterns for aligning code labels. Note: Don't try to assemble the instructions in the comments. 0L and 0w are not legal. */ static const uae_u8 f32_1[] = {0x90}; /* nop */ static const uae_u8 f32_2[] = {0x89,0xf6}; /* movl %esi,%esi */ static const uae_u8 f32_3[] = {0x8d,0x76,0x00}; /* leal 0(%esi),%esi */ static const uae_u8 f32_4[] = {0x8d,0x74,0x26,0x00}; /* leal 0(%esi,1),%esi */ static const uae_u8 f32_5[] = {0x90, /* nop */ 0x8d,0x74,0x26,0x00}; /* leal 0(%esi,1),%esi */ static const uae_u8 f32_6[] = {0x8d,0xb6,0x00,0x00,0x00,0x00}; /* leal 0L(%esi),%esi */ static const uae_u8 f32_7[] = {0x8d,0xb4,0x26,0x00,0x00,0x00,0x00}; /* leal 0L(%esi,1),%esi */ static const uae_u8 f32_8[] = {0x90, /* nop */ 0x8d,0xb4,0x26,0x00,0x00,0x00,0x00}; /* leal 0L(%esi,1),%esi */ static const uae_u8 f32_9[] = {0x89,0xf6, /* movl %esi,%esi */ 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ static const uae_u8 f32_10[] = {0x8d,0x76,0x00, /* leal 0(%esi),%esi */ 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ static const uae_u8 f32_11[] = {0x8d,0x74,0x26,0x00, /* leal 0(%esi,1),%esi */ 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ static const uae_u8 f32_12[] = {0x8d,0xb6,0x00,0x00,0x00,0x00, /* leal 0L(%esi),%esi */ 0x8d,0xbf,0x00,0x00,0x00,0x00}; /* leal 0L(%edi),%edi */ static const uae_u8 f32_13[] = {0x8d,0xb6,0x00,0x00,0x00,0x00, /* leal 0L(%esi),%esi */ 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ static const uae_u8 f32_14[] = {0x8d,0xb4,0x26,0x00,0x00,0x00,0x00, /* leal 0L(%esi,1),%esi */ 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ static const uae_u8 f32_15[] = {0xeb,0x0d,0x90,0x90,0x90,0x90,0x90, /* jmp .+15; lotsa nops */ 0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90}; static const uae_u8 f32_16[] = {0xeb,0x0d,0x90,0x90,0x90,0x90,0x90, /* jmp .+15; lotsa nops */ 0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90}; static const uae_u8 *const f32_patt[] = { f32_1, f32_2, f32_3, f32_4, f32_5, f32_6, f32_7, f32_8, f32_9, f32_10, f32_11, f32_12, f32_13, f32_14, f32_15 }; static const uae_u8 prefixes[4] = { 0x66, 0x66, 0x66, 0x66 }; #if defined(__x86_64__) /* The recommended way to pad 64bit code is to use NOPs preceded by maximally four 0x66 prefixes. Balance the size of nops. */ if (nbytes > 0) { int i; int nnops = (nbytes + 3) / 4; int len = nbytes / nnops; int remains = nbytes - nnops * len; for (i = 0; i < remains; i++) { emit_block (prefixes, len); raw_nop (); } for (; i < nnops; i++) { emit_block (prefixes, len - 1); raw_nop (); } } #else int nloops = nbytes / 16; while (nloops-- > 0) emit_block (f32_16, sizeof (f32_16)); nbytes %= 16; if (nbytes) emit_block (f32_patt[nbytes - 1], nbytes); #endif } /************************************************************************* * Flag handling, to and fro UAE flag register * *************************************************************************/ #define FLAG_NREG1 0 /* Set to -1 if any register will do */ STATIC_INLINE void raw_flags_to_reg(int r) { raw_lahf(0); /* Most flags in AH */ //raw_setcc(r,0); /* V flag in AL */ raw_setcc_m((uae_u32)live.state[FLAGTMP].mem,0); #if 1 /* Let's avoid those nasty partial register stalls */ //raw_mov_b_mr((uae_u32)live.state[FLAGTMP].mem,r); raw_mov_b_mr(((uae_u32)live.state[FLAGTMP].mem)+1,r+4); //live.state[FLAGTMP].status=CLEAN; live.state[FLAGTMP].status=INMEM; live.state[FLAGTMP].realreg=-1; /* We just "evicted" FLAGTMP. */ if (live.nat[r].nholds!=1) { /* Huh? */ abort(); } live.nat[r].nholds=0; #endif } #define FLAG_NREG2 0 /* Set to -1 if any register will do */ STATIC_INLINE void raw_reg_to_flags(int r) { raw_cmp_b_ri(r,-127); /* set V */ raw_sahf(0); } /* Apparently, there are enough instructions between flag store and flag reload to avoid the partial memory stall */ STATIC_INLINE void raw_load_flagreg(uae_u32 target, uae_u32 r) { #if 1 raw_mov_l_rm(target,(uae_u32)live.state[r].mem); #else raw_mov_b_rm(target,(uae_u32)live.state[r].mem); raw_mov_b_rm(target+4,((uae_u32)live.state[r].mem)+1); #endif } /* FLAGX is word-sized */ STATIC_INLINE void raw_load_flagx(uae_u32 target, uae_u32 r) { if (live.nat[target].canword) raw_mov_w_rm(target,(uae_u32)live.state[r].mem); else raw_mov_l_rm(target,(uae_u32)live.state[r].mem); } #define NATIVE_FLAG_Z 0x40 #define NATIVE_CC_EQ 4 STATIC_INLINE void raw_flags_set_zero(int f, int r, int t) { // FIXME: this is really suboptimal raw_pushfl(); raw_pop_l_r(f); raw_and_l_ri(f,~NATIVE_FLAG_Z); raw_test_l_rr(r,r); raw_mov_l_ri(r,0); raw_mov_l_ri(t,NATIVE_FLAG_Z); raw_cmov_l_rr(r,t,NATIVE_CC_EQ); raw_or_l(f,r); raw_push_l_r(f); raw_popfl(); } STATIC_INLINE void raw_inc_sp(int off) { raw_add_l_ri(4,off); } /************************************************************************* * Handling mistaken direct memory access * *************************************************************************/ #ifdef NATMEM_OFFSET # ifdef _WIN32 // %%% BRIAN KING WAS HERE %%% # include # else # ifndef __USE_GNU # define __USE_GNU # endif # include # endif # include #define SIG_READ 1 #define SIG_WRITE 2 static int in_handler=0; static uae_u8 *veccode; # ifdef _WIN32 int EvalException ( LPEXCEPTION_POINTERS blah, int n_except ) { PEXCEPTION_RECORD pExceptRecord = NULL; PCONTEXT pContext = NULL; uae_u8* i = NULL; uae_u32 addr = 0; int r=-1; int size=4; int dir=-1; int len=0; int j; if( n_except != STATUS_ACCESS_VIOLATION || !canbang) return EXCEPTION_CONTINUE_SEARCH; pExceptRecord = blah->ExceptionRecord; pContext = blah->ContextRecord; if( pContext ) { i = (uae_u8 *)(pContext->Eip); } if( pExceptRecord ) { addr = (uae_u32)(pExceptRecord->ExceptionInformation[1]); } #ifdef JIT_DEBUG write_log ("JIT: fault address is 0x%x at 0x%x\n", addr, i); #endif if (!canbang || !currprefs.cachesize) { #ifdef JIT_DEBUG write_log ("JIT: Not happy! Canbang or cachesize is 0 in SIGSEGV handler!\n"); #endif return EXCEPTION_CONTINUE_SEARCH; } if (in_handler) write_log ("JIT: Argh --- Am already in a handler. Shouldn't happen!\n"); if (canbang && i>=compiled_code && i<=current_compile_p) { if (*i==0x66) { i++; size=2; len++; } switch(i[0]) { case 0x8a: if ((i[1]&0xc0)==0x80) { r=(i[1]>>3)&7; dir=SIG_READ; size=1; len+=6; break; } break; case 0x88: if ((i[1]&0xc0)==0x80) { r=(i[1]>>3)&7; dir=SIG_WRITE; size=1; len+=6; break; } break; case 0x8b: switch(i[1]&0xc0) { case 0x80: r=(i[1]>>3)&7; dir=SIG_READ; len+=6; break; case 0x40: r=(i[1]>>3)&7; dir=SIG_READ; len+=3; break; case 0x00: r=(i[1]>>3)&7; dir=SIG_READ; len+=2; break; default: break; } break; case 0x89: switch(i[1]&0xc0) { case 0x80: r=(i[1]>>3)&7; dir=SIG_WRITE; len+=6; break; case 0x40: r=(i[1]>>3)&7; dir=SIG_WRITE; len+=3; break; case 0x00: r=(i[1]>>3)&7; dir=SIG_WRITE; len+=2; break; } break; } } if (r!=-1) { void* pr=NULL; #ifdef JIT_DEBUG write_log ("JIT: register was %d, direction was %d, size was %d\n", r, dir, size); #endif switch(r) { case 0: pr=&(pContext->Eax); break; case 1: pr=&(pContext->Ecx); break; case 2: pr=&(pContext->Edx); break; case 3: pr=&(pContext->Ebx); break; case 4: pr=(size>1)?NULL:(((uae_u8*)&(pContext->Eax))+1); break; case 5: pr=(size>1)? (void*)(&(pContext->Ebp)): (void*)(((uae_u8*)&(pContext->Ecx))+1); break; case 6: pr=(size>1)? (void*)(&(pContext->Esi)): (void*)(((uae_u8*)&(pContext->Edx))+1); break; case 7: pr=(size>1)? (void*)(&(pContext->Edi)): (void*)(((uae_u8*)&(pContext->Ebx))+1); break; default: abort(); } if (pr) { blockinfo* bi; if (currprefs.comp_oldsegv) { addr-=NATMEM_OFFSET; if ((addr>=0x10000000 && addr<0x40000000) || (addr>=0x50000000)) { #ifdef JIT_DEBUG write_log ("JIT: Suspicious address 0x%x in SEGV handler.\n", addr); #endif } if (dir==SIG_READ) { switch(size) { case 1: *((uae_u8*)pr)=get_byte(addr); break; case 2: *((uae_u16*)pr)=swap16(get_word(addr)); break; case 4: *((uae_u32*)pr)=swap32(get_long(addr)); break; default: abort(); } } else { /* write */ switch(size) { case 1: put_byte(addr,*((uae_u8*)pr)); break; case 2: put_word(addr,swap16(*((uae_u16*)pr))); break; case 4: put_long(addr,swap32(*((uae_u32*)pr))); break; default: abort(); } } #ifdef JIT_DEBUG write_log ("JIT: Handled one access!\n"); flush_log (); #endif segvcount++; pContext->Eip+=len; } else { void* tmp=target; int i; uae_u8 vecbuf[5]; addr-=NATMEM_OFFSET; if ((addr>=0x10000000 && addr<0x40000000) || (addr>=0x50000000)) { #ifdef JIT_DEBUG write_log ("JIT: Suspicious address 0x%x in SEGV handler.\n", addr); #endif } target=(uae_u8*)pContext->Eip; for (i=0;i<5;i++) vecbuf[i]=target[i]; emit_byte(0xe9); emit_long((uae_u32)veccode-(uae_u32)target-4); #ifdef JIT_DEBUG write_log ("JIT: Create jump to %p\n", veccode); write_log ("JIT: Handled one access!\n"); #endif segvcount++; target=veccode; if (dir==SIG_READ) { switch(size) { case 1: raw_mov_b_ri(r,get_byte(addr)); break; case 2: raw_mov_w_ri(r,swap16(get_word(addr))); break; case 4: raw_mov_l_ri(r,swap32(get_long(addr))); break; default: abort(); } } else { /* write */ switch(size) { case 1: put_byte(addr,*((uae_u8*)pr)); break; case 2: put_word(addr,swap16(*((uae_u16*)pr))); break; case 4: put_long(addr,swap32(*((uae_u32*)pr))); break; default: abort(); } } for (i=0;i<5;i++) raw_mov_b_mi(pContext->Eip+i,vecbuf[i]); raw_mov_l_mi((uae_u32)&in_handler,0); emit_byte(0xe9); emit_long(pContext->Eip+len-(uae_u32)target-4); in_handler=1; target=tmp; } bi=active; while (bi) { if (bi->handler && (uae_u8*)bi->direct_handler<=i && (uae_u8*)bi->nexthandler>i) { #ifdef JIT_DEBUG write_log ("JIT: deleted trigger (%p<%p<%p) %p\n", bi->handler, i, bi->nexthandler, bi->pc_p); #endif invalidate_block(bi); raise_in_cl_list(bi); set_special (®s,0); return EXCEPTION_CONTINUE_EXECUTION; } bi=bi->next; } /* Not found in the active list. Might be a rom routine that is in the dormant list */ bi=dormant; while (bi) { if (bi->handler && (uae_u8*)bi->direct_handler<=i && (uae_u8*)bi->nexthandler>i) { #ifdef JIT_DEBUG write_log ("JIT: deleted trigger (%p<%p<%p) %p\n", bi->handler, i, bi->nexthandler, bi->pc_p); #endif invalidate_block(bi); raise_in_cl_list(bi); set_special (®s,0); return EXCEPTION_CONTINUE_EXECUTION; } bi=bi->next; } #ifdef JIT_DEBUG write_log ("JIT: Huh? Could not find trigger!\n"); #endif return EXCEPTION_CONTINUE_EXECUTION; } } write_log ("JIT: Can't handle access!\n"); if( i ) { for (j=0;j<10;j++) { write_log ("JIT: instruction byte %2d is 0x%02x\n", j, i[j]); } } #if 0 write_log("Please send the above info (starting at \"fault address\") to\n" "bmeyer@csse.monash.edu.au\n" "This shouldn't happen ;-)\n"); #endif return EXCEPTION_CONTINUE_SEARCH; } # else typedef void *CONTEXT_T; #define CONTEXT_EIP(context) (((struct ucontext *)context)->uc_mcontext.gregs[REG_EIP]) #define CONTEXT_EAX(context) (((struct ucontext *)context)->uc_mcontext.gregs[REG_EAX]) #define CONTEXT_ECX(context) (((struct ucontext *)context)->uc_mcontext.gregs[REG_ECX]) #define CONTEXT_EDX(context) (((struct ucontext *)context)->uc_mcontext.gregs[REG_EDX]) #define CONTEXT_EBX(context) (((struct ucontext *)context)->uc_mcontext.gregs[REG_EBX]) #define CONTEXT_ESP(context) (((struct ucontext *)context)->uc_mcontext.gregs[REG_ESP]) #define CONTEXT_EBP(context) (((struct ucontext *)context)->uc_mcontext.gregs[REG_EBP]) #define CONTEXT_ESI(context) (((struct ucontext *)context)->uc_mcontext.gregs[REG_ESI]) #define CONTEXT_EDI(context) (((struct ucontext *)context)->uc_mcontext.gregs[REG_EDI]) #define CONTEXT_CR2(context) (((struct ucontext *)context)->uc_mcontext.cr2) /* * Try to handle faulted memory access in compiled code * * Returns 1 if handled, 0 otherwise */ static int handle_access (CONTEXT_T context) { uae_u8 *i = (uae_u8 *) CONTEXT_EIP (context); uae_u32 addr = CONTEXT_CR2 (context); int reg = -1; int size = 4; int dir = -1; int len = 0; #ifdef JIT_DEBUG write_log ("JIT: fault address is %08x at %08x\n", addr, i); if (!canbang) write_log ("JIT: Not happy! Canbang is 0 in SIGSEGV handler!\n"); #endif if (in_handler) write_log ("JIT: Argh --- Am already in a handler. Shouldn't happen!\n"); /* * Decode access opcode */ if (canbang && i >= compiled_code && i <= current_compile_p) { if (*i == 0x66) { i++; size = 2; len++; } switch (i[0]) { case 0x8a: if ((i[1] & 0xc0) == 0x80) { reg = (i[1] >> 3) & 7; dir = SIG_READ; size = 1; len += 6; break; } break; case 0x88: if ((i[1] & 0xc0) == 0x80) { reg = (i[1] >> 3) & 7; dir = SIG_WRITE; size = 1; len += 6; break; } break; case 0x8b: switch (i[1] & 0xc0) { case 0x80: reg = (i[1] >> 3) & 7; dir = SIG_READ; len += 6; break; case 0x40: reg = (i[1] >> 3) & 7; dir = SIG_READ; len += 3; break; case 0x00: reg = (i[1] >> 3) & 7; dir = SIG_READ; len += 2; break; default: break; } break; case 0x89: switch (i[1] & 0xc0) { case 0x80: reg = (i[1] >> 3) & 7; dir = SIG_WRITE; len += 6; break; case 0x40: reg = (i[1] >> 3) & 7; dir = SIG_WRITE; len += 3; break; case 0x00: reg = (i[1] >> 3) & 7; dir = SIG_WRITE; len += 2; break; } break; } } if (reg !=-1) { void *pr = NULL; #ifdef JIT_DEBUG write_log ("JIT: register was %d, direction was %d, size was %d\n", reg, dir, size); #endif switch (reg) { case 0: pr = &(CONTEXT_EAX (context)); break; case 1: pr = &(CONTEXT_ECX (context)); break; case 2: pr = &(CONTEXT_EDX (context)); break; case 3: pr = &(CONTEXT_EBX (context)); break; case 4: pr = (size > 1) ? NULL : (((uae_u8*)&(CONTEXT_EAX (context)))+1); break; case 5: pr = (size > 1) ? (void*) (&(CONTEXT_EBP (context))) : (void*)(((uae_u8*)&(CONTEXT_ECX (context))) + 1); break; case 6: pr = (size > 1) ? (void*) (&(CONTEXT_ESI (context))) : (void*)(((uae_u8*)&(CONTEXT_EDX (context))) + 1); break; case 7: pr = (size > 1) ? (void*) (&(CONTEXT_EDI (context))) : (void*)(((uae_u8*)&(CONTEXT_EBX (context))) + 1); break; default: abort (); } if (pr) { blockinfo *bi; if (currprefs.comp_oldsegv) { addr -= NATMEM_OFFSET; #ifdef JIT_DEBUG if ((addr >= 0x10000000 && addr < 0x40000000) || (addr >= 0x50000000)) { write_log ("JIT: Suspicious address in %x SEGV handler.\n", addr); } #endif if (dir == SIG_READ) { switch (size) { case 1: *((uae_u8*) pr) = get_byte (addr); break; case 2: *((uae_u16*)pr) = get_word (addr); break; case 4: *((uae_u32*)pr) = get_long (addr); break; default: abort (); } } else { /* write */ switch (size) { case 1: put_byte (addr, *((uae_u8*) pr)); break; case 2: put_word (addr, *((uae_u16*)pr)); break; case 4: put_long (addr, *((uae_u32*)pr)); break; default: abort (); } } #ifdef JIT_DEBUG write_log ("JIT: Handled one access!\n"); flush_log (); #endif segvcount++; CONTEXT_EIP (context) += len; } else { void *tmp = target; int i; uae_u8 vecbuf[5]; addr -= NATMEM_OFFSET; #ifdef JIT_DEBUG if ((addr >= 0x10000000 && addr < 0x40000000) || (addr >= 0x50000000)) { write_log ("JIT: Suspicious address 0x%x in SEGV handler.\n", addr); } #endif target = (uae_u8*) CONTEXT_EIP (context); for (i = 0; i < 5; i++) vecbuf[i] = target[i]; emit_byte (0xe9); emit_long ((uae_u32)veccode - (uae_u32)target - 4); #ifdef JIT_DEBUG write_log ("JIT: Create jump to %p\n", veccode); write_log ("JIT: Handled one access!\n"); flush_log (); #endif segvcount++; target = veccode; if (dir == SIG_READ) { switch (size) { case 1: raw_mov_b_ri (reg ,get_byte (addr)); break; case 2: raw_mov_w_ri (reg, get_word (addr)); break; case 4: raw_mov_l_ri (reg, get_long (addr)); break; default: abort (); } } else { /* write */ switch(size) { case 1: put_byte (addr, *((uae_u8*) pr)); break; case 2: put_word (addr, *((uae_u16*)pr)); break; case 4: put_long (addr, *((uae_u32*)pr)); break; default: abort (); } } for (i = 0; i < 5; i++) raw_mov_b_mi (CONTEXT_EIP (context) + i, vecbuf[i]); raw_mov_l_mi ((uae_u32)&in_handler, 0); emit_byte (0xe9); emit_long (CONTEXT_EIP (context) + len - (uae_u32)target - 4); in_handler = 1; target = tmp; } bi = active; while (bi) { if (bi->handler && (uae_u8*)bi->direct_handler <= i && (uae_u8*)bi->nexthandler > i) { #ifdef JIT_DEBUG write_log ("JIT: deleted trigger (%p < %p < %p) %p\n", bi->handler, i, bi->nexthandler, bi->pc_p); #endif invalidate_block (bi); raise_in_cl_list (bi); set_special (®s, 0); return 1; } bi = bi->next; } /* Not found in the active list. Might be a rom routine that is in the dormant list */ bi = dormant; while (bi) { if (bi->handler && (uae_u8*)bi->direct_handler <= i && (uae_u8*)bi->nexthandler > i) { #ifdef JIT_DEBUG write_log ("JIT: deleted trigger (%p < %p <%p) %p\n", bi->handler, i, bi->nexthandler, bi->pc_p); #endif invalidate_block (bi); raise_in_cl_list (bi); set_special (®s, 0); return 1; } bi = bi->next; } #ifdef JIT_DEBUG write_log ("JIT: Huh? Could not find trigger!\n"); #endif return 1; } } return 0; } /* * SIGSEGV handler */ static void vec (int signum, struct siginfo *info, void *context) { uae_u8 *i = (uae_u8 *) CONTEXT_EIP (context); uae_u32 addr = CONTEXT_CR2 (context); if (i >= compiled_code) { if (handle_access (context)) return; else { int j; write_log ("JIT: can't handle access!\n"); for (j = 0 ; j < 10; j++) write_log ("JIT: instruction byte %2d is %02x\n", i, j[i]); } } else { write_log ("Caught illegal access to %08x at eip=%08x\n", addr, i); } exit (EXIT_FAILURE); } # endif #endif /************************************************************************* * Checking for CPU features * *************************************************************************/ struct cpuinfo_x86 { uae_u8 x86; // CPU family uae_u8 x86_vendor; // CPU vendor uae_u8 x86_processor; // CPU canonical processor type uae_u8 x86_brand_id; // CPU BrandID if supported, yield 0 otherwise uae_u32 x86_hwcap; uae_u8 x86_model; uae_u8 x86_mask; int cpuid_level; // Maximum supported CPUID level, -1=no CPUID char x86_vendor_id[16]; }; struct cpuinfo_x86 cpuinfo; enum { X86_VENDOR_INTEL = 0, X86_VENDOR_CYRIX = 1, X86_VENDOR_AMD = 2, X86_VENDOR_UMC = 3, X86_VENDOR_NEXGEN = 4, X86_VENDOR_CENTAUR = 5, X86_VENDOR_RISE = 6, X86_VENDOR_TRANSMETA = 7, X86_VENDOR_NSC = 8, X86_VENDOR_UNKNOWN = 0xff }; enum { X86_PROCESSOR_I386, /* 80386 */ X86_PROCESSOR_I486, /* 80486DX, 80486SX, 80486DX[24] */ X86_PROCESSOR_PENTIUM, X86_PROCESSOR_PENTIUMPRO, X86_PROCESSOR_K6, X86_PROCESSOR_ATHLON, X86_PROCESSOR_PENTIUM4, X86_PROCESSOR_X86_64, X86_PROCESSOR_max }; static const char * x86_processor_string_table[X86_PROCESSOR_max] = { "80386", "80486", "Pentium", "PentiumPro", "K6", "Athlon", "Pentium4", "x86-64" }; static const struct ptt { const int align_loop; const int align_loop_max_skip; const int align_jump; const int align_jump_max_skip; const int align_func; } x86_alignments[X86_PROCESSOR_max] = { { 4, 3, 4, 3, 4 }, { 16, 15, 16, 15, 16 }, { 16, 7, 16, 7, 16 }, { 16, 15, 16, 7, 16 }, { 32, 7, 32, 7, 32 }, { 16, 7, 16, 7, 16 }, { 0, 0, 0, 0, 0 }, { 16, 7, 16, 7, 16 } }; static void x86_get_cpu_vendor (struct cpuinfo_x86 *c) { char *v = c->x86_vendor_id; if (!strcmp(v, "GenuineIntel")) c->x86_vendor = X86_VENDOR_INTEL; else if (!strcmp(v, "AuthenticAMD")) c->x86_vendor = X86_VENDOR_AMD; else if (!strcmp(v, "CyrixInstead")) c->x86_vendor = X86_VENDOR_CYRIX; else if (!strcmp(v, "Geode by NSC")) c->x86_vendor = X86_VENDOR_NSC; else if (!strcmp(v, "UMC UMC UMC ")) c->x86_vendor = X86_VENDOR_UMC; else if (!strcmp(v, "CentaurHauls")) c->x86_vendor = X86_VENDOR_CENTAUR; else if (!strcmp(v, "NexGenDriven")) c->x86_vendor = X86_VENDOR_NEXGEN; else if (!strcmp(v, "RiseRiseRise")) c->x86_vendor = X86_VENDOR_RISE; else if (!strcmp(v, "GenuineTMx86") || !strcmp (v, "TransmetaCPU")) c->x86_vendor = X86_VENDOR_TRANSMETA; else c->x86_vendor = X86_VENDOR_UNKNOWN; } static void cpuid (uae_u32 op, uae_u32 *eax, uae_u32 *ebx, uae_u32 *ecx, uae_u32 *edx) { const int CPUID_SPACE = 4096; uae_u8 *cpuid_space; uae_u8 *tmp; static uae_u32 s_op, s_eax, s_ebx, s_ecx, s_edx; cpuid_space = (uae_u8 *) cache_alloc (CPUID_SPACE); if (cpuid_space == 0) abort (); tmp = get_target (); s_op = op; set_target (cpuid_space); raw_push_l_r (0); /* eax */ raw_push_l_r (1); /* ecx */ raw_push_l_r (2); /* edx */ raw_push_l_r (3); /* ebx */ raw_mov_l_rm (0, (uae_uintptr) &s_op); raw_cpuid (0); raw_mov_l_mr ((uae_uintptr) &s_eax, 0); raw_mov_l_mr ((uae_uintptr) &s_ebx, 3); raw_mov_l_mr ((uae_uintptr) &s_ecx, 1); raw_mov_l_mr ((uae_uintptr) &s_edx, 2); raw_pop_l_r (3); raw_pop_l_r (2); raw_pop_l_r (1); raw_pop_l_r (0); raw_ret (); set_target (tmp); ((compop_func *) cpuid_space) (0); if (eax != NULL) *eax = s_eax; if (ebx != NULL) *ebx = s_ebx; if (ecx != NULL) *ecx = s_ecx; if (edx != NULL) *edx = s_edx; cache_free (cpuid_space); } static void raw_init_cpu (void) { struct cpuinfo_x86 *c = &cpuinfo; uae_u32 xlvl; /* Defaults */ c->x86_processor = X86_PROCESSOR_max; c->x86_vendor = X86_VENDOR_UNKNOWN; c->cpuid_level = -1; /* CPUID not detected */ c->x86_model = 0; c->x86_mask = 0; /* So far unknown... */ c->x86_vendor_id[0] = '\0'; /* Unset */ c->x86_hwcap = 0; /* Get vendor name */ c->x86_vendor_id[12] = '\0'; cpuid (0x00000000, (uae_u32 *) &c->cpuid_level, (uae_u32 *) &c->x86_vendor_id[0], (uae_u32 *) &c->x86_vendor_id[8], (uae_u32 *) &c->x86_vendor_id[4]); x86_get_cpu_vendor (c); /* Intel-defined flags: level 0x00000001 */ c->x86_brand_id = 0; if (c->cpuid_level >= 0x00000001) { uae_u32 tfms, brand_id; cpuid (0x00000001, &tfms, &brand_id, NULL, &c->x86_hwcap); c->x86 = (tfms >> 8) & 15; if (c->x86 == 0xf) c->x86 += (tfms >> 20) & 0xff; /* extended family */ c->x86_model = (tfms >> 4) & 15; if (c->x86_model == 0xf) c->x86_model |= (tfms >> 12) & 0xf0; /* extended model */ c->x86_brand_id = brand_id & 0xff; c->x86_mask = tfms & 15; } else { /* Have CPUID level 0 only - unheard of */ c->x86 = 4; } /* AMD-defined flags: level 0x80000001 */ cpuid (0x80000000, &xlvl, NULL, NULL, NULL); if ((xlvl & 0xffff0000) == 0x80000000) { if (xlvl >= 0x80000001) { uae_u32 features, extra_features; cpuid (0x80000001, NULL, NULL, &extra_features, &features); if (features & (1 << 29)) { /* Assume x86-64 if long mode is supported */ c->x86_processor = X86_PROCESSOR_X86_64; } #if 0 if (extra_features & (1 << 0)) have_lahf_lm = 1; #endif } } /* Canonicalize processor ID */ switch (c->x86) { case 3: c->x86_processor = X86_PROCESSOR_I386; break; case 4: c->x86_processor = X86_PROCESSOR_I486; break; case 5: if (c->x86_vendor == X86_VENDOR_AMD) c->x86_processor = X86_PROCESSOR_K6; else c->x86_processor = X86_PROCESSOR_PENTIUM; break; case 6: if (c->x86_vendor == X86_VENDOR_AMD) c->x86_processor = X86_PROCESSOR_ATHLON; else c->x86_processor = X86_PROCESSOR_PENTIUMPRO; break; case 15: if (c->x86_processor == X86_PROCESSOR_max) { switch (c->x86_vendor) { case X86_VENDOR_INTEL: c->x86_processor = X86_PROCESSOR_PENTIUM4; break; case X86_VENDOR_AMD: /* Assume a 32-bit Athlon processor if not in long mode */ c->x86_processor = X86_PROCESSOR_ATHLON; break; } } break; } if (c->x86_processor == X86_PROCESSOR_max) { c->x86_processor = X86_PROCESSOR_I386; write_log ("Error: unknown processor type, assuming i386\n"); write_log (" Family : %d\n", c->x86); write_log (" Model : %d\n", c->x86_model); write_log (" Mask : %d\n", c->x86_mask); write_log (" Vendor : %s [%d]\n", c->x86_vendor_id, c->x86_vendor); if (c->x86_brand_id) write_log(" BrandID : %02x\n", c->x86_brand_id); } /* Have CMOV support? */ have_cmov = c->x86_hwcap & (1 << 15); #if defined(__x86_64__) if (!have_cmov) { write_log ("x86-64 implementations are bound to have CMOV!\n"); abort (); } #endif /* Can the host CPU suffer from partial register stalls? */ have_rat_stall = (c->x86_vendor == X86_VENDOR_INTEL); #if 1 /* It appears that partial register writes are a bad idea even on * AMD K7 cores, even though they are not supposed to have the * dreaded rat stall. Why? Anyway, that's why we lie about it ;-) */ if (c->x86_processor == X86_PROCESSOR_ATHLON) have_rat_stall = 1; #endif /* Alignments */ if (1) /*(tune_alignment)*/ { align_loops = x86_alignments[c->x86_processor].align_loop; align_jumps = x86_alignments[c->x86_processor].align_jump; } write_log ("Max CPUID level=%d Processor is %s [%s]\n", c->cpuid_level, c->x86_vendor_id, x86_processor_string_table[c->x86_processor]); } /************************************************************************* * FPU stuff * *************************************************************************/ STATIC_INLINE void raw_fp_init(void) { int i; for (i=0;i1) { emit_byte(0x9b); emit_byte(0xdb); emit_byte(0xe3); live.tos=-1; } #endif while (live.tos>=1) { emit_byte(0xde); emit_byte(0xd9); live.tos-=2; } while (live.tos>=0) { emit_byte(0xdd); emit_byte(0xd8); live.tos--; } raw_fp_init(); } STATIC_INLINE void make_tos(int r) { int p,q; if (live.spos[r]<0) { /* Register not yet on stack */ emit_byte(0xd9); emit_byte(0xe8); /* Push '1' on the stack, just to grow it */ live.tos++; live.spos[r]=live.tos; live.onstack[live.tos]=r; return; } /* Register is on stack */ if (live.tos==live.spos[r]) return; p=live.spos[r]; q=live.onstack[live.tos]; emit_byte(0xd9); emit_byte(0xc8+live.tos-live.spos[r]); /* exchange it with top of stack */ live.onstack[live.tos]=r; live.spos[r]=live.tos; live.onstack[p]=q; live.spos[q]=p; } STATIC_INLINE void make_tos2(int r, int r2) { int q; make_tos(r2); /* Put the reg that's supposed to end up in position2 on top */ if (live.spos[r]<0) { /* Register not yet on stack */ make_tos(r); /* This will extend the stack */ return; } /* Register is on stack */ emit_byte(0xd9); emit_byte(0xc9); /* Move r2 into position 2 */ q=live.onstack[live.tos-1]; live.onstack[live.tos]=q; live.spos[q]=live.tos; live.onstack[live.tos-1]=r2; live.spos[r2]=live.tos-1; make_tos(r); /* And r into 1 */ } STATIC_INLINE int stackpos(int r) { if (live.spos[r]<0) abort(); if (live.tos=0) { /* source is on top of stack, and we already have the dest */ int dd=stackpos(d); emit_byte(0xdd); emit_byte(0xd0+dd); } else { emit_byte(0xd9); emit_byte(0xc0+ds); /* duplicate source on tos */ tos_make(d); /* store to destination, pop if necessary */ } } LENDFUNC(NONE,NONE,2,raw_fmov_rr,(FW d, FR s)) LOWFUNC(NONE,READ,4,raw_fldcw_m_indexed,(R4 index, IMM base)) { emit_byte(0xd9); emit_byte(0xa8+index); emit_long(base); } LENDFUNC(NONE,READ,4,raw_fldcw_m_indexed,(R4 index, IMM base)) LOWFUNC(NONE,NONE,2,raw_fsqrt_rr,(FW d, FR s)) { int ds; if (d!=s) { usereg(s); ds=stackpos(s); emit_byte(0xd9); emit_byte(0xc0+ds); /* duplicate source */ emit_byte(0xd9); emit_byte(0xfa); /* take square root */ tos_make(d); /* store to destination */ } else { make_tos(d); emit_byte(0xd9); emit_byte(0xfa); /* take square root */ } } LENDFUNC(NONE,NONE,2,raw_fsqrt_rr,(FW d, FR s)) LOWFUNC(NONE,NONE,2,raw_fabs_rr,(FW d, FR s)) { int ds; if (d!=s) { usereg(s); ds=stackpos(s); emit_byte(0xd9); emit_byte(0xc0+ds); /* duplicate source */ emit_byte(0xd9); emit_byte(0xe1); /* take fabs */ tos_make(d); /* store to destination */ } else { make_tos(d); emit_byte(0xd9); emit_byte(0xe1); /* take fabs */ } } LENDFUNC(NONE,NONE,2,raw_fabs_rr,(FW d, FR s)) LOWFUNC(NONE,NONE,2,raw_frndint_rr,(FW d, FR s)) { int ds; if (d!=s) { usereg(s); ds=stackpos(s); emit_byte(0xd9); emit_byte(0xc0+ds); /* duplicate source */ emit_byte(0xd9); emit_byte(0xfc); /* take frndint */ tos_make(d); /* store to destination */ } else { make_tos(d); emit_byte(0xd9); emit_byte(0xfc); /* take frndint */ } } LENDFUNC(NONE,NONE,2,raw_frndint_rr,(FW d, FR s)) LOWFUNC(NONE,NONE,2,raw_fcos_rr,(FW d, FR s)) { int ds; if (d!=s) { usereg(s); ds=stackpos(s); emit_byte(0xd9); emit_byte(0xc0+ds); /* duplicate source */ emit_byte(0xd9); emit_byte(0xff); /* take cos */ tos_make(d); /* store to destination */ } else { make_tos(d); emit_byte(0xd9); emit_byte(0xff); /* take cos */ } } LENDFUNC(NONE,NONE,2,raw_fcos_rr,(FW d, FR s)) LOWFUNC(NONE,NONE,2,raw_fsin_rr,(FW d, FR s)) { int ds; if (d!=s) { usereg(s); ds=stackpos(s); emit_byte(0xd9); emit_byte(0xc0+ds); /* duplicate source */ emit_byte(0xd9); emit_byte(0xfe); /* take sin */ tos_make(d); /* store to destination */ } else { make_tos(d); emit_byte(0xd9); emit_byte(0xfe); /* take sin */ } } LENDFUNC(NONE,NONE,2,raw_fsin_rr,(FW d, FR s)) double one=1; LOWFUNC(NONE,NONE,2,raw_ftwotox_rr,(FW d, FR s)) { int ds; usereg(s); ds=stackpos(s); emit_byte(0xd9); emit_byte(0xc0+ds); /* duplicate source */ emit_byte(0xd9); emit_byte(0xc0); /* duplicate top of stack. Now up to 8 high */ emit_byte(0xd9); emit_byte(0xfc); /* rndint */ emit_byte(0xd9); emit_byte(0xc9); /* swap top two elements */ emit_byte(0xd8); emit_byte(0xe1); /* subtract rounded from original */ emit_byte(0xd9); emit_byte(0xf0); /* f2xm1 */ emit_byte(0xdc); emit_byte(0x05); emit_long((uae_u32)&one); /* Add '1' without using extra stack space */ emit_byte(0xd9); emit_byte(0xfd); /* and scale it */ emit_byte(0xdd); emit_byte(0xd9); /* take he rounded value off */ tos_make(d); /* store to destination */ } LENDFUNC(NONE,NONE,2,raw_ftwotox_rr,(FW d, FR s)) LOWFUNC(NONE,NONE,2,raw_fetox_rr,(FW d, FR s)) { int ds; usereg(s); ds=stackpos(s); emit_byte(0xd9); emit_byte(0xc0+ds); /* duplicate source */ emit_byte(0xd9); emit_byte(0xea); /* fldl2e */ emit_byte(0xde); emit_byte(0xc9); /* fmulp --- multiply source by log2(e) */ emit_byte(0xd9); emit_byte(0xc0); /* duplicate top of stack. Now up to 8 high */ emit_byte(0xd9); emit_byte(0xfc); /* rndint */ emit_byte(0xd9); emit_byte(0xc9); /* swap top two elements */ emit_byte(0xd8); emit_byte(0xe1); /* subtract rounded from original */ emit_byte(0xd9); emit_byte(0xf0); /* f2xm1 */ emit_byte(0xdc); emit_byte(0x05); emit_long((uae_u32)&one); /* Add '1' without using extra stack space */ emit_byte(0xd9); emit_byte(0xfd); /* and scale it */ emit_byte(0xdd); emit_byte(0xd9); /* take he rounded value off */ tos_make(d); /* store to destination */ } LENDFUNC(NONE,NONE,2,raw_fetox_rr,(FW d, FR s)) LOWFUNC(NONE,NONE,2,raw_flog2_rr,(FW d, FR s)) { int ds; usereg(s); ds=stackpos(s); emit_byte(0xd9); emit_byte(0xc0+ds); /* duplicate source */ emit_byte(0xd9); emit_byte(0xe8); /* push '1' */ emit_byte(0xd9); emit_byte(0xc9); /* swap top two */ emit_byte(0xd9); emit_byte(0xf1); /* take 1*log2(x) */ tos_make(d); /* store to destination */ } LENDFUNC(NONE,NONE,2,raw_flog2_rr,(FW d, FR s)) LOWFUNC(NONE,NONE,2,raw_fneg_rr,(FW d, FR s)) { int ds; if (d!=s) { usereg(s); ds=stackpos(s); emit_byte(0xd9); emit_byte(0xc0+ds); /* duplicate source */ emit_byte(0xd9); emit_byte(0xe0); /* take fchs */ tos_make(d); /* store to destination */ } else { make_tos(d); emit_byte(0xd9); emit_byte(0xe0); /* take fchs */ } } LENDFUNC(NONE,NONE,2,raw_fneg_rr,(FW d, FR s)) LOWFUNC(NONE,NONE,2,raw_fadd_rr,(FRW d, FR s)) { int ds; usereg(s); usereg(d); if (live.spos[s]==live.tos) { /* Source is on top of stack */ ds=stackpos(d); emit_byte(0xdc); emit_byte(0xc0+ds); /* add source to dest*/ } else { make_tos(d); ds=stackpos(s); emit_byte(0xd8); emit_byte(0xc0+ds); /* add source to dest*/ } } LENDFUNC(NONE,NONE,2,raw_fadd_rr,(FRW d, FR s)) LOWFUNC(NONE,NONE,2,raw_fsub_rr,(FRW d, FR s)) { int ds; usereg(s); usereg(d); if (live.spos[s]==live.tos) { /* Source is on top of stack */ ds=stackpos(d); emit_byte(0xdc); emit_byte(0xe8+ds); /* sub source from dest*/ } else { make_tos(d); ds=stackpos(s); emit_byte(0xd8); emit_byte(0xe0+ds); /* sub src from dest */ } } LENDFUNC(NONE,NONE,2,raw_fsub_rr,(FRW d, FR s)) LOWFUNC(NONE,NONE,2,raw_fcmp_rr,(FR d, FR s)) { int ds; usereg(s); usereg(d); make_tos(d); ds=stackpos(s); emit_byte(0xdd); emit_byte(0xe0+ds); /* cmp dest with source*/ } LENDFUNC(NONE,NONE,2,raw_fcmp_rr,(FR d, FR s)) LOWFUNC(NONE,NONE,2,raw_fmul_rr,(FRW d, FR s)) { int ds; usereg(s); usereg(d); if (live.spos[s]==live.tos) { /* Source is on top of stack */ ds=stackpos(d); emit_byte(0xdc); emit_byte(0xc8+ds); /* mul dest by source*/ } else { make_tos(d); ds=stackpos(s); emit_byte(0xd8); emit_byte(0xc8+ds); /* mul dest by source*/ } } LENDFUNC(NONE,NONE,2,raw_fmul_rr,(FRW d, FR s)) LOWFUNC(NONE,NONE,2,raw_fdiv_rr,(FRW d, FR s)) { int ds; usereg(s); usereg(d); if (live.spos[s]==live.tos) { /* Source is on top of stack */ ds=stackpos(d); emit_byte(0xdc); emit_byte(0xf8+ds); /* div dest by source */ } else { make_tos(d); ds=stackpos(s); emit_byte(0xd8); emit_byte(0xf0+ds); /* div dest by source*/ } } LENDFUNC(NONE,NONE,2,raw_fdiv_rr,(FRW d, FR s)) LOWFUNC(NONE,NONE,2,raw_frem_rr,(FRW d, FR s)) { int ds; usereg(s); usereg(d); make_tos2(d,s); ds=stackpos(s); if (ds!=1) { write_log ("JIT: Failed horribly in raw_frem_rr! ds is %d\n", ds); abort(); } emit_byte(0xd9); emit_byte(0xf8); /* take rem from dest by source */ } LENDFUNC(NONE,NONE,2,raw_frem_rr,(FRW d, FR s)) LOWFUNC(NONE,NONE,2,raw_frem1_rr,(FRW d, FR s)) { int ds; usereg(s); usereg(d); make_tos2(d,s); ds=stackpos(s); if (ds!=1) { write_log ("JIT: Failed horribly in raw_frem1_rr! ds is %d\n", ds); abort(); } emit_byte(0xd9); emit_byte(0xf5); /* take rem1 from dest by source */ } LENDFUNC(NONE,NONE,2,raw_frem1_rr,(FRW d, FR s)) LOWFUNC(NONE,NONE,1,raw_ftst_r,(FR r)) { make_tos(r); emit_byte(0xd9); /* ftst */ emit_byte(0xe4); } LENDFUNC(NONE,NONE,1,raw_ftst_r,(FR r)) STATIC_INLINE void raw_fflags_into_flags(int r) { int p; usereg(r); p=stackpos(r); emit_byte(0xd9); emit_byte(0xee); /* Push 0 */ emit_byte(0xd9); emit_byte(0xc9+p); /* swap top two around */ if (have_cmov) { // gb-- fucomi is for P6 cores only, not K6-2 then... emit_byte(0xdb); emit_byte(0xe9+p); /* fucomi them */ } else { emit_byte(0xdd); emit_byte(0xe1+p); /* fucom them */ emit_byte(0x9b); emit_byte(0xdf); emit_byte(0xe0); /* fstsw ax */ raw_sahf(0); /* sahf */ } emit_byte(0xdd); emit_byte(0xd9+p); /* store value back, and get rid of 0 */ }