diff options
author | Richard Henderson <rth@twiddle.net> | 2014-02-24 15:53:40 -0800 |
---|---|---|
committer | Richard Henderson <rth@twiddle.net> | 2014-02-28 08:44:26 -0800 |
commit | cb48da7f8140b5cbb648d990876720da9cd04d8f (patch) | |
tree | a3ef85e21685885bd9c11daa18833e7f3c2f6b7b | |
parent | 4e47e39ab0ded72c0af174131ecf49d588d66c12 (diff) | |
download | qemu-cb48da7f8140b5cbb648d990876720da9cd04d8f.zip qemu-cb48da7f8140b5cbb648d990876720da9cd04d8f.tar.gz qemu-cb48da7f8140b5cbb648d990876720da9cd04d8f.tar.bz2 |
target-i386: Fix ucomis and comis memory access
We were loading 16 bytes for both single and double-precision
scalar comparisons.
Reported-by: Alexander Bluhm <bluhm@openbsd.org>
Signed-off-by: Richard Henderson <rth@twiddle.net>
-rw-r--r-- | target-i386/translate.c | 46 |
1 files changed, 36 insertions, 10 deletions
diff --git a/target-i386/translate.c b/target-i386/translate.c index aa985fa..707ebd5 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -4284,22 +4284,48 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b, if (is_xmm) { op1_offset = offsetof(CPUX86State,xmm_regs[reg]); if (mod != 3) { + int sz = 4; + gen_lea_modrm(env, s, modrm); op2_offset = offsetof(CPUX86State,xmm_t0); - if (b1 >= 2 && ((b >= 0x50 && b <= 0x5f && b != 0x5b) || - b == 0xc2)) { - /* specific case for SSE single instructions */ + + switch (b) { + case 0x50 ... 0x5a: + case 0x5c ... 0x5f: + case 0xc2: + /* Most sse scalar operations. */ if (b1 == 2) { - /* 32 bit access */ - gen_op_ld_v(s, MO_32, cpu_T[0], cpu_A0); - tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_t0.XMM_L(0))); + sz = 2; + } else if (b1 == 3) { + sz = 3; + } + break; + + case 0x2e: /* ucomis[sd] */ + case 0x2f: /* comis[sd] */ + if (b1 == 0) { + sz = 2; } else { - /* 64 bit access */ - gen_ldq_env_A0(s, offsetof(CPUX86State, - xmm_t0.XMM_D(0))); + sz = 3; } - } else { + break; + } + + switch (sz) { + case 2: + /* 32 bit access */ + gen_op_ld_v(s, MO_32, cpu_T[0], cpu_A0); + tcg_gen_st32_tl(cpu_T[0], cpu_env, + offsetof(CPUX86State,xmm_t0.XMM_L(0))); + break; + case 3: + /* 64 bit access */ + gen_ldq_env_A0(s, offsetof(CPUX86State, xmm_t0.XMM_D(0))); + break; + default: + /* 128 bit access */ gen_ldo_env_A0(s, op2_offset); + break; } } else { rm = (modrm & 7) | REX_B(s); |