aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--target-i386/fpu_helper.c22
-rw-r--r--target-i386/translate.c16
2 files changed, 34 insertions, 4 deletions
diff --git a/target-i386/fpu_helper.c b/target-i386/fpu_helper.c
index 1d4eee3974..30d34d5aee 100644
--- a/target-i386/fpu_helper.c
+++ b/target-i386/fpu_helper.c
@@ -251,16 +251,34 @@ int32_t helper_fist_ST0(CPUX86State *env)
int32_t helper_fistl_ST0(CPUX86State *env)
{
int32_t val;
+ signed char old_exp_flags;
+
+ old_exp_flags = get_float_exception_flags(&env->fp_status);
+ set_float_exception_flags(0, &env->fp_status);
val = floatx80_to_int32(ST0, &env->fp_status);
+ if (get_float_exception_flags(&env->fp_status) & float_flag_invalid) {
+ val = 0x80000000;
+ }
+ set_float_exception_flags(get_float_exception_flags(&env->fp_status)
+ | old_exp_flags, &env->fp_status);
return val;
}
int64_t helper_fistll_ST0(CPUX86State *env)
{
int64_t val;
+ signed char old_exp_flags;
- val = floatx80_to_int64(ST0, &env->fp_status);
+ old_exp_flags = get_float_exception_flags(&env->fp_status);
+ set_float_exception_flags(0, &env->fp_status);
+
+ val = floatx80_to_int32(ST0, &env->fp_status);
+ if (get_float_exception_flags(&env->fp_status) & float_flag_invalid) {
+ val = 0x8000000000000000ULL;
+ }
+ set_float_exception_flags(get_float_exception_flags(&env->fp_status)
+ | old_exp_flags, &env->fp_status);
return val;
}
@@ -621,7 +639,7 @@ void helper_fbld_ST0(CPUX86State *env, target_ulong ptr)
}
tmp = int64_to_floatx80(val, &env->fp_status);
if (cpu_ldub_data(env, ptr + 9) & 0x80) {
- floatx80_chs(tmp);
+ tmp = floatx80_chs(tmp);
}
fpush(env);
ST0 = tmp;
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 782f7d2666..6243e36661 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -115,6 +115,7 @@ typedef struct DisasContext {
int tf; /* TF cpu flag */
int singlestep_enabled; /* "hardware" single step enabled */
int jmp_opt; /* use direct block chaining for direct jumps */
+ int repz_opt; /* optimize jumps within repz instructions */
int mem_index; /* select memory access functions */
uint64_t flags; /* all execution flags */
struct TranslationBlock *tb;
@@ -1215,7 +1216,7 @@ static inline void gen_repz_ ## op(DisasContext *s, TCGMemOp ot, \
gen_op_add_reg_im(s->aflag, R_ECX, -1); \
/* a loop would cause two single step exceptions if ECX = 1 \
before rep string_insn */ \
- if (!s->jmp_opt) \
+ if (s->repz_opt) \
gen_op_jz_ecx(s->aflag, l2); \
gen_jmp(s, cur_eip); \
}
@@ -1233,7 +1234,7 @@ static inline void gen_repz_ ## op(DisasContext *s, TCGMemOp ot, \
gen_op_add_reg_im(s->aflag, R_ECX, -1); \
gen_update_cc_op(s); \
gen_jcc1(s, (JCC_Z << 1) | (nz ^ 1), l2); \
- if (!s->jmp_opt) \
+ if (s->repz_opt) \
gen_op_jz_ecx(s->aflag, l2); \
gen_jmp(s, cur_eip); \
}
@@ -7951,6 +7952,17 @@ static inline void gen_intermediate_code_internal(X86CPU *cpu,
|| (flags & HF_SOFTMMU_MASK)
#endif
);
+ /* Do not optimize repz jumps at all in icount mode, because
+ rep movsS instructions are execured with different paths
+ in !repz_opt and repz_opt modes. The first one was used
+ always except single step mode. And this setting
+ disables jumps optimization and control paths become
+ equivalent in run and single step modes.
+ Now there will be no jump optimization for repz in
+ record/replay modes and there will always be an
+ additional step for ecx=0 when icount is enabled.
+ */
+ dc->repz_opt = !dc->jmp_opt && !use_icount;
#if 0
/* check addseg logic */
if (!dc->addseg && (dc->vm86 || !dc->pe || !dc->code32))