Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions linux-user/i386/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,9 @@ restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc)
unlock_user_struct(fpstate, fpstate_addr, 0);
#ifdef CONFIG_LATX
load_xmm_from_env(env);
if (option_softfpu) {
cpu_x86_set_host_rounding_from_mxcsr(env);
}
#endif
} else {
err = 0;
Expand Down
3 changes: 3 additions & 0 deletions target/i386/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -1934,6 +1934,9 @@ void cpu_x86_fxsave(CPUX86State *s, target_ulong ptr);
void cpu_x86_fxrstor(CPUX86State *s, target_ulong ptr);
void cpu_x86_xsave(CPUX86State *s, target_ulong ptr);
void cpu_x86_xrstor(CPUX86State *s, target_ulong ptr);
#ifdef CONFIG_LATX
void cpu_x86_set_host_rounding_from_mxcsr(CPUX86State *s);
#endif

/* you can call this signal handler from your SIGBUS and SIGSEGV
signal handlers to inform the virtual CPU of exceptions. non zero
Expand Down
2 changes: 2 additions & 0 deletions target/i386/latx/include/translate.h
Original file line number Diff line number Diff line change
Expand Up @@ -1728,6 +1728,8 @@ void tr_lat_spin_unlock(IR2_OPND lat_lock_addr);

void gen_softfpu_helper_prologue(IR1_INST *pir1);
void gen_softfpu_helper_epilogue(IR1_INST *pir1);
void gen_softfpu_x87_fcsr_enter(void);
void gen_softfpu_x87_fcsr_exit(void);
void update_fcsr_rm(IR2_OPND control_word, IR2_OPND fcsr);

bool ir1_need_reserve_h128(IR1_INST *ir1);
Expand Down
21 changes: 21 additions & 0 deletions target/i386/latx/translator/tr-fctrl.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,24 @@ void update_fcsr_rm(IR2_OPND control_word, IR2_OPND fcsr)
ra_free_temp(temp_cw);
}

void gen_softfpu_x87_fcsr_exit(void)
{
IR2_OPND mxcsr_opnd = ra_alloc_itemp();
IR2_OPND cw_opnd = ra_alloc_itemp();
IR2_OPND fcsr_opnd = ra_alloc_itemp();

la_ld_wu(mxcsr_opnd, env_ir2_opnd, lsenv_offset_of_mxcsr(lsenv));
la_bstrpick_d(cw_opnd, mxcsr_opnd, 14, 13);
la_slli_d(cw_opnd, cw_opnd, 10);
la_movfcsr2gr(fcsr_opnd, fcsr_ir2_opnd);
update_fcsr_rm(cw_opnd, fcsr_opnd);
la_movgr2fcsr(fcsr_ir2_opnd, fcsr_opnd);

ra_free_temp(mxcsr_opnd);
ra_free_temp(cw_opnd);
ra_free_temp(fcsr_opnd);
}

void update_fcsr_by_sw(IR2_OPND sw)
{
IR2_OPND old_fcsr = ra_alloc_itemp();
Expand Down Expand Up @@ -234,6 +252,9 @@ bool translate_ldmxcsr(IR1_INST *pir1)

tr_gen_call_to_helper1((ADDR)update_mxcsr_status, 1,
LOAD_HELPER_UPDATE_MXCSR_STATUS);
if (option_softfpu) {
gen_softfpu_x87_fcsr_exit();
}

return true;
}
Expand Down
72 changes: 55 additions & 17 deletions target/i386/latx/translator/tr-softfpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,9 @@ static void la_update_fp_status(IR2_OPND cw_opnd)
IR2_OPND itemp = ra_alloc_itemp();
IR2_OPND tmp_fcsr = ra_alloc_itemp();

IR2_OPND label_float64_float80 = ra_alloc_label();
IR2_OPND label_float32 = ra_alloc_label();
IR2_OPND label_float64 = ra_alloc_label();
IR2_OPND label_precision_done = ra_alloc_label();

int fp_status_offset = lsenv_offset_of_fp_status(lsenv);
int round_mode_offset = fp_status_offset +
Expand All @@ -359,24 +361,59 @@ static void la_update_fp_status(IR2_OPND cw_opnd)
* x86 env
*
* 32 00 10
* reserved 01 00
* 64 10 01
* 80 11 10
* 80 11 00
*
*/

/* Precision Control (9, 8)*/
la_bstrpick_d(itemp, cw_opnd, 9, 8);
la_bne(itemp, zero_ir2_opnd, label_float64_float80);
li_wu(itemp, 1);
la_beq(itemp, zero_ir2_opnd, label_float32);
li_wu(tmp_fcsr, 2);
la_beq(itemp, tmp_fcsr, label_float64);
li_wu(itemp, floatx80_precision_x);
la_b(label_precision_done);

la_label(label_float64_float80);
la_xori(itemp, itemp, 3);
la_label(label_float32);
li_wu(itemp, floatx80_precision_s);
la_b(label_precision_done);

la_label(label_float64);
li_wu(itemp, floatx80_precision_d);

la_label(label_precision_done);
la_st_b(itemp, env_ir2_opnd, round_precision_offset);

ra_free_temp(itemp);
ra_free_temp(tmp_fcsr);
}

static void la_update_fp_status_from_env(void)
{
IR2_OPND cw_opnd = ra_alloc_itemp();

la_ld_hu(cw_opnd, env_ir2_opnd,
lsenv_offset_of_control_word(lsenv));
la_update_fp_status(cw_opnd);
ra_free_temp(cw_opnd);
}

void gen_softfpu_x87_fcsr_enter(void)
{
IR2_OPND cw_opnd = ra_alloc_itemp();
IR2_OPND fcsr_opnd = ra_alloc_itemp();

la_ld_hu(cw_opnd, env_ir2_opnd,
lsenv_offset_of_control_word(lsenv));
la_movfcsr2gr(fcsr_opnd, fcsr_ir2_opnd);
update_fcsr_rm(cw_opnd, fcsr_opnd);
la_movgr2fcsr(fcsr_ir2_opnd, fcsr_opnd);

ra_free_temp(cw_opnd);
ra_free_temp(fcsr_opnd);
}

__attribute__((unused))
void gen_softfpu_helper_prologue(IR1_INST *pir1)
{
Expand Down Expand Up @@ -1924,17 +1961,12 @@ static bool translate_fldcw_softfpu(IR1_INST *pir1)
{
IR1_OPND *opnd0 = ir1_get_opnd(pir1, 0);
IR2_OPND mem_opnd = convert_mem_no_offset(opnd0);
IR2_OPND new_cw = ra_alloc_itemp();

if (option_softfpu == 2) {
IR2_OPND new_cw = ra_alloc_itemp();
la_ld_hu(new_cw, mem_opnd, 0);
la_st_h(new_cw, env_ir2_opnd, lsenv_offset_of_control_word(lsenv));
la_update_fp_status(new_cw);
ra_free_temp(new_cw);

} else {
gen_softfpu_helper2m_16u((ADDR)helper_fldcw, mem_opnd);
}
la_ld_hu(new_cw, mem_opnd, 0);
la_st_h(new_cw, env_ir2_opnd, lsenv_offset_of_control_word(lsenv));
la_update_fp_status(new_cw);
ra_free_temp(new_cw);
return true;
}

Expand Down Expand Up @@ -2020,6 +2052,7 @@ static bool translate_fldenv_softfpu(IR1_INST *pir1)

} else {
gen_softfpu_helper3i((ADDR)helper_fldenv, mem_opnd, data32);
la_update_fp_status_from_env();
}
return true;
}
Expand Down Expand Up @@ -2325,6 +2358,7 @@ static bool translate_fninit_softfpu(IR1_INST *pir1)
ra_free_temp(temp);
} else {
gen_softfpu_helper1((ADDR)helper_fninit);
la_update_fp_status_from_env();
}
return true;
}
Expand Down Expand Up @@ -2474,6 +2508,7 @@ static bool translate_fnsave_softfpu(IR1_INST *pir1)
} else {
IR2_OPND mem_opnd = convert_mem_no_offset(opnd0);
gen_softfpu_helper3i((ADDR)helper_fsave, mem_opnd, data32);
la_update_fp_status_from_env();
}
return true;
}
Expand Down Expand Up @@ -2618,6 +2653,7 @@ static bool translate_frstor_softfpu(IR1_INST *pir1)
} else {
IR2_OPND mem_opnd = convert_mem_no_offset(opnd0);
gen_softfpu_helper3i((ADDR)helper_frstor, mem_opnd, data32);
la_update_fp_status_from_env();

}
return true;
Expand Down Expand Up @@ -3131,6 +3167,7 @@ static bool translate_fxrstor_softfpu(IR1_INST *pir1)
IR2_OPND mem_opnd = convert_mem_no_offset(opnd0);

gen_softfpu_helper2m_ptr((ADDR)helper_fxrstor, mem_opnd);
la_update_fp_status_from_env();
return true;
}

Expand Down Expand Up @@ -3227,6 +3264,7 @@ static bool translate_xrstor_softfpu(IR1_INST *pir1)
la_bstrins_d(temp_rfbm, eax_opnd, 31, 0);
la_bstrins_d(temp_rfbm, edx_opnd, 63, 32);
gen_softfpu_helper3_ll((ADDR)helper_xrstor, mem_opnd, temp_rfbm);
gen_softfpu_x87_fcsr_exit();
return true;
}
#endif
Expand Down Expand Up @@ -3268,7 +3306,7 @@ TRANS_FPU_WRAP_GEN(fisub);
TRANS_FPU_WRAP_GEN(fisubr);
TRANS_FPU_WRAP_GEN(fld1);
TRANS_FPU_WRAP_GEN(fld);
TRANS_FPU_WRAP_GEN(fldcw);
TRANS_FPU_WRAP_GEN_NO_PROLOGUE(fldcw);
TRANS_FPU_WRAP_GEN(fldenv);
TRANS_FPU_WRAP_GEN(fldl2e);
TRANS_FPU_WRAP_GEN(fldl2t);
Expand Down
116 changes: 116 additions & 0 deletions target/i386/latx/translator/translate.c
Original file line number Diff line number Diff line change
Expand Up @@ -2101,6 +2101,108 @@ typedef enum SoftFPURegionClass {
SOFTFPU_REGION_TRANSPARENT,
} SoftFPURegionClass;

static bool is_softfpu_x87_insn(IR1_OPCODE opcode)
{
switch (opcode) {
case dt_X86_INS_WAIT:
case dt_X86_INS_F2XM1:
case dt_X86_INS_FABS:
case dt_X86_INS_FADD:
case dt_X86_INS_FADDP:
case dt_X86_INS_FBLD:
case dt_X86_INS_FBSTP:
case dt_X86_INS_FCHS:
case dt_X86_INS_FCMOVB:
case dt_X86_INS_FCMOVBE:
case dt_X86_INS_FCMOVE:
case dt_X86_INS_FCMOVNB:
case dt_X86_INS_FCMOVNBE:
case dt_X86_INS_FCMOVNE:
case dt_X86_INS_FCMOVNU:
case dt_X86_INS_FCMOVU:
case dt_X86_INS_FCOM:
case dt_X86_INS_FCOMI:
case dt_X86_INS_FCOMIP:
case dt_X86_INS_FCOMP:
case dt_X86_INS_FCOMPP:
case dt_X86_INS_FCOS:
case dt_X86_INS_FDECSTP:
case dt_X86_INS_FDIV:
case dt_X86_INS_FDIVP:
case dt_X86_INS_FDIVR:
case dt_X86_INS_FDIVRP:
case dt_X86_INS_FFREE:
case dt_X86_INS_FFREEP:
case dt_X86_INS_FIADD:
case dt_X86_INS_FICOM:
case dt_X86_INS_FICOMP:
case dt_X86_INS_FIDIV:
case dt_X86_INS_FIDIVR:
case dt_X86_INS_FILD:
case dt_X86_INS_FIMUL:
case dt_X86_INS_FINCSTP:
case dt_X86_INS_FIST:
case dt_X86_INS_FISTP:
case dt_X86_INS_FISTTP:
case dt_X86_INS_FISUB:
case dt_X86_INS_FISUBR:
case dt_X86_INS_FLD1:
case dt_X86_INS_FLD:
case dt_X86_INS_FLDCW:
case dt_X86_INS_FLDENV:
case dt_X86_INS_FLDL2E:
case dt_X86_INS_FLDL2T:
case dt_X86_INS_FLDLG2:
case dt_X86_INS_FLDLN2:
case dt_X86_INS_FLDPI:
case dt_X86_INS_FLDZ:
case dt_X86_INS_FMUL:
case dt_X86_INS_FMULP:
case dt_X86_INS_FNCLEX:
case dt_X86_INS_FNINIT:
case dt_X86_INS_FNOP:
case dt_X86_INS_FNSAVE:
case dt_X86_INS_FNSTCW:
case dt_X86_INS_FNSTENV:
case dt_X86_INS_FNSTSW:
case dt_X86_INS_FPATAN:
case dt_X86_INS_FPREM1:
case dt_X86_INS_FPREM:
case dt_X86_INS_FPTAN:
case dt_X86_INS_FRNDINT:
case dt_X86_INS_FRSTOR:
case dt_X86_INS_FSCALE:
case dt_X86_INS_FSETPM:
case dt_X86_INS_FSIN:
case dt_X86_INS_FSINCOS:
case dt_X86_INS_FSQRT:
case dt_X86_INS_FST:
case dt_X86_INS_FSTP:
case dt_X86_INS_FSUB:
case dt_X86_INS_FSUBP:
case dt_X86_INS_FSUBR:
case dt_X86_INS_FSUBRP:
case dt_X86_INS_FTST:
case dt_X86_INS_FUCOM:
case dt_X86_INS_FUCOMI:
case dt_X86_INS_FUCOMIP:
case dt_X86_INS_FUCOMP:
case dt_X86_INS_FUCOMPP:
case dt_X86_INS_FXAM:
case dt_X86_INS_FXCH:
case dt_X86_INS_FXRSTOR:
case dt_X86_INS_FXRSTOR64:
case dt_X86_INS_FXSAVE:
case dt_X86_INS_FXSAVE64:
case dt_X86_INS_FXTRACT:
case dt_X86_INS_FYL2X:
case dt_X86_INS_FYL2XP1:
return true;
default:
return false;
}
}

static uint32_t softfpu_fast_mask(IR1_OPCODE opcode)
{
switch (opcode) {
Expand Down Expand Up @@ -2310,6 +2412,7 @@ int tr_ir2_generate(struct TranslationBlock *tb)
IR1_INST *pir1 = tb_ir1_inst(tb, 0);

bool reduce_proepo = false;
bool x87_fcsr_active = false;
int softfpu_region_end = -1;

lsenv->tr_data->softfpu_region_active = false;
Expand Down Expand Up @@ -2419,6 +2522,16 @@ int tr_ir2_generate(struct TranslationBlock *tb)
}
#endif

bool x87_insn = option_softfpu &&
is_softfpu_x87_insn(ir1_opcode(pir1));
if (x87_insn && !x87_fcsr_active) {
gen_softfpu_x87_fcsr_enter();
x87_fcsr_active = true;
} else if (!x87_insn && x87_fcsr_active) {
gen_softfpu_x87_fcsr_exit();
x87_fcsr_active = false;
}

if (option_softfpu == 2 && !reduce_proepo &&
softfpu_region_class(ir1_opcode(pir1)) ==
SOFTFPU_REGION_REQUIRED) {
Expand Down Expand Up @@ -2455,6 +2568,9 @@ int tr_ir2_generate(struct TranslationBlock *tb)

pir1++;
}
if (x87_fcsr_active) {
gen_softfpu_x87_fcsr_exit();
}
#ifdef CONFIG_LATX_DEBUG
if (option_dump_ir1) {
pir1 = tb_ir1_inst(tb, 0);
Expand Down
Loading