aboutsummaryrefslogtreecommitdiff
path: root/target-i386
diff options
context:
space:
mode:
authorBlue Swirl <blauwirbel@gmail.com>2012-05-13 18:53:07 +0000
committerBlue Swirl <blauwirbel@gmail.com>2012-06-28 20:28:08 +0000
commitc4baa0503d9623f1ce891f525ccd140c598bc29a (patch)
treef94504350b92adfaddc8fd5857da873aedc8d954 /target-i386
parentf299f4374affb6b838765841bb69a6e92566a9a8 (diff)
downloadqemu-c4baa0503d9623f1ce891f525ccd140c598bc29a.zip
qemu-c4baa0503d9623f1ce891f525ccd140c598bc29a.tar.gz
qemu-c4baa0503d9623f1ce891f525ccd140c598bc29a.tar.bz2
x86: improve SSE table type safety
SSE function tables could easily be corrupted because of use of void pointers. Introduce function pointer types and helper variables in order to improve type safety. Split sse_op_table3 according to types used. Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Diffstat (limited to 'target-i386')
-rw-r--r--target-i386/translate.c134
1 files changed, 89 insertions, 45 deletions
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 8ac6132..a902f4a 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -2786,6 +2786,14 @@ static inline void gen_op_movq_env_0(int d_offset)
tcg_gen_st_i64(cpu_tmp1_i64, cpu_env, d_offset);
}
+typedef void (*SSEFunc_i_p)(TCGv_i32 val, TCGv_ptr reg);
+typedef void (*SSEFunc_l_p)(TCGv_i64 val, TCGv_ptr reg);
+typedef void (*SSEFunc_0_pi)(TCGv_ptr reg, TCGv_i32 val);
+typedef void (*SSEFunc_0_pl)(TCGv_ptr reg, TCGv_i64 val);
+typedef void (*SSEFunc_0_pp)(TCGv_ptr reg_a, TCGv_ptr reg_b);
+typedef void (*SSEFunc_0_ppi)(TCGv_ptr reg_a, TCGv_ptr reg_b, TCGv_i32 val);
+typedef void (*SSEFunc_0_ppt)(TCGv_ptr reg_a, TCGv_ptr reg_b, TCGv val);
+
#define SSE_SPECIAL ((void *)1)
#define SSE_DUMMY ((void *)2)
@@ -2793,7 +2801,7 @@ static inline void gen_op_movq_env_0(int d_offset)
#define SSE_FOP(x) { gen_helper_ ## x ## ps, gen_helper_ ## x ## pd, \
gen_helper_ ## x ## ss, gen_helper_ ## x ## sd, }
-static void *sse_op_table1[256][4] = {
+static const SSEFunc_0_pp sse_op_table1[256][4] = {
/* 3DNow! extensions */
[0x0e] = { SSE_DUMMY }, /* femms */
[0x0f] = { SSE_DUMMY }, /* pf... */
@@ -2834,7 +2842,8 @@ static void *sse_op_table1[256][4] = {
[0x5f] = SSE_FOP(max),
[0xc2] = SSE_FOP(cmpeq),
- [0xc6] = { gen_helper_shufps, gen_helper_shufpd },
+ [0xc6] = { (SSEFunc_0_pp)gen_helper_shufps,
+ (SSEFunc_0_pp)gen_helper_shufpd }, /* XXX: casts */
[0x38] = { SSE_SPECIAL, SSE_SPECIAL, NULL, SSE_SPECIAL }, /* SSSE3/SSE4 */
[0x3a] = { SSE_SPECIAL, SSE_SPECIAL }, /* SSSE3/SSE4 */
@@ -2856,10 +2865,10 @@ static void *sse_op_table1[256][4] = {
[0x6d] = { NULL, gen_helper_punpckhqdq_xmm },
[0x6e] = { SSE_SPECIAL, SSE_SPECIAL }, /* movd mm, ea */
[0x6f] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movq, movdqa, , movqdu */
- [0x70] = { gen_helper_pshufw_mmx,
- gen_helper_pshufd_xmm,
- gen_helper_pshufhw_xmm,
- gen_helper_pshuflw_xmm },
+ [0x70] = { (SSEFunc_0_pp)gen_helper_pshufw_mmx,
+ (SSEFunc_0_pp)gen_helper_pshufd_xmm,
+ (SSEFunc_0_pp)gen_helper_pshufhw_xmm,
+ (SSEFunc_0_pp)gen_helper_pshuflw_xmm }, /* XXX: casts */
[0x71] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftw */
[0x72] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftd */
[0x73] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftq */
@@ -2914,7 +2923,8 @@ static void *sse_op_table1[256][4] = {
[0xf4] = MMX_OP2(pmuludq),
[0xf5] = MMX_OP2(pmaddwd),
[0xf6] = MMX_OP2(psadbw),
- [0xf7] = MMX_OP2(maskmov),
+ [0xf7] = { (SSEFunc_0_pp)gen_helper_maskmov_mmx,
+ (SSEFunc_0_pp)gen_helper_maskmov_xmm }, /* XXX: casts */
[0xf8] = MMX_OP2(psubb),
[0xf9] = MMX_OP2(psubw),
[0xfa] = MMX_OP2(psubl),
@@ -2924,7 +2934,7 @@ static void *sse_op_table1[256][4] = {
[0xfe] = MMX_OP2(paddl),
};
-static void *sse_op_table2[3 * 8][2] = {
+static const SSEFunc_0_pp sse_op_table2[3 * 8][2] = {
[0 + 2] = MMX_OP2(psrlw),
[0 + 4] = MMX_OP2(psraw),
[0 + 6] = MMX_OP2(psllw),
@@ -2937,12 +2947,14 @@ static void *sse_op_table2[3 * 8][2] = {
[16 + 7] = { NULL, gen_helper_pslldq_xmm },
};
-static void *sse_op_table3[4 * 3] = {
+static const SSEFunc_0_pi sse_op_table3a[4] = {
gen_helper_cvtsi2ss,
gen_helper_cvtsi2sd,
X86_64_ONLY(gen_helper_cvtsq2ss),
X86_64_ONLY(gen_helper_cvtsq2sd),
+};
+static const SSEFunc_i_p sse_op_table3b[4 * 2] = {
gen_helper_cvttss2si,
gen_helper_cvttsd2si,
X86_64_ONLY(gen_helper_cvttss2sq),
@@ -2954,7 +2966,7 @@ static void *sse_op_table3[4 * 3] = {
X86_64_ONLY(gen_helper_cvtsd2sq),
};
-static void *sse_op_table4[8][4] = {
+static const SSEFunc_0_pp sse_op_table4[8][4] = {
SSE_FOP(cmpeq),
SSE_FOP(cmplt),
SSE_FOP(cmple),
@@ -2965,7 +2977,7 @@ static void *sse_op_table4[8][4] = {
SSE_FOP(cmpord),
};
-static void *sse_op_table5[256] = {
+static const SSEFunc_0_pp sse_op_table5[256] = {
[0x0c] = gen_helper_pi2fw,
[0x0d] = gen_helper_pi2fd,
[0x1c] = gen_helper_pf2iw,
@@ -2992,14 +3004,22 @@ static void *sse_op_table5[256] = {
[0xbf] = gen_helper_pavgb_mmx /* pavgusb */
};
-struct sse_op_helper_s {
- void *op[2]; uint32_t ext_mask;
+struct SSEOpHelper_pp {
+ SSEFunc_0_pp op[2];
+ uint32_t ext_mask;
+};
+
+struct SSEOpHelper_ppi {
+ SSEFunc_0_ppi op[2];
+ uint32_t ext_mask;
};
+
#define SSSE3_OP(x) { MMX_OP2(x), CPUID_EXT_SSSE3 }
#define SSE41_OP(x) { { NULL, gen_helper_ ## x ## _xmm }, CPUID_EXT_SSE41 }
#define SSE42_OP(x) { { NULL, gen_helper_ ## x ## _xmm }, CPUID_EXT_SSE42 }
#define SSE41_SPECIAL { { NULL, SSE_SPECIAL }, CPUID_EXT_SSE41 }
-static struct sse_op_helper_s sse_op_table6[256] = {
+
+static const struct SSEOpHelper_pp sse_op_table6[256] = {
[0x00] = SSSE3_OP(pshufb),
[0x01] = SSSE3_OP(phaddw),
[0x02] = SSSE3_OP(phaddd),
@@ -3048,7 +3068,7 @@ static struct sse_op_helper_s sse_op_table6[256] = {
[0x41] = SSE41_OP(phminposuw),
};
-static struct sse_op_helper_s sse_op_table7[256] = {
+static const struct SSEOpHelper_ppi sse_op_table7[256] = {
[0x08] = SSE41_OP(roundps),
[0x09] = SSE41_OP(roundpd),
[0x0a] = SSE41_OP(roundss),
@@ -3077,7 +3097,13 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
{
int b1, op1_offset, op2_offset, is_xmm, val, ot;
int modrm, mod, rm, reg, reg_addr, offset_addr;
- void *sse_op2;
+ SSEFunc_i_p sse_fn_i_p;
+ SSEFunc_l_p sse_fn_l_p;
+ SSEFunc_0_pi sse_fn_pi;
+ SSEFunc_0_pl sse_fn_pl;
+ SSEFunc_0_pp sse_fn_pp;
+ SSEFunc_0_ppi sse_fn_ppi;
+ SSEFunc_0_ppt sse_fn_ppt;
b &= 0xff;
if (s->prefix & PREFIX_DATA)
@@ -3088,9 +3114,10 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
b1 = 3;
else
b1 = 0;
- sse_op2 = sse_op_table1[b][b1];
- if (!sse_op2)
+ sse_fn_pp = sse_op_table1[b][b1];
+ if (!sse_fn_pp) {
goto illegal_op;
+ }
if ((b <= 0x5f && b >= 0x10) || b == 0xc6 || b == 0xc2) {
is_xmm = 1;
} else {
@@ -3137,7 +3164,7 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
if (is_xmm)
reg |= rex_r;
mod = (modrm >> 6) & 3;
- if (sse_op2 == SSE_SPECIAL) {
+ if (sse_fn_pp == SSE_SPECIAL) {
b |= (b1 << 8);
switch(b) {
case 0x0e7: /* movntq */
@@ -3474,9 +3501,10 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,mmx_t0.MMX_L(1)));
op1_offset = offsetof(CPUX86State,mmx_t0);
}
- sse_op2 = sse_op_table2[((b - 1) & 3) * 8 + (((modrm >> 3)) & 7)][b1];
- if (!sse_op2)
+ sse_fn_pp = sse_op_table2[((b - 1) & 3) * 8 + (((modrm >> 3)) & 7)][b1];
+ if (!sse_fn_pp) {
goto illegal_op;
+ }
if (is_xmm) {
rm = (modrm & 7) | REX_B(s);
op2_offset = offsetof(CPUX86State,xmm_regs[rm]);
@@ -3486,7 +3514,7 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
}
tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op2_offset);
tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op1_offset);
- ((void (*)(TCGv_ptr, TCGv_ptr))sse_op2)(cpu_ptr0, cpu_ptr1);
+ sse_fn_pp(cpu_ptr0, cpu_ptr1);
break;
case 0x050: /* movmskps */
rm = (modrm & 7) | REX_B(s);
@@ -3534,12 +3562,15 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
op1_offset = offsetof(CPUX86State,xmm_regs[reg]);
tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
- sse_op2 = sse_op_table3[(s->dflag == 2) * 2 + ((b >> 8) - 2)];
if (ot == OT_LONG) {
+ sse_fn_pi = sse_op_table3a[(s->dflag == 2) * 2 +
+ ((b >> 8) - 2)];
tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
- ((void (*)(TCGv_ptr, TCGv_i32))sse_op2)(cpu_ptr0, cpu_tmp2_i32);
+ sse_fn_pi(cpu_ptr0, cpu_tmp2_i32);
} else {
- ((void (*)(TCGv_ptr, TCGv))sse_op2)(cpu_ptr0, cpu_T[0]);
+ sse_fn_pl = sse_op_table3a[(s->dflag == 2) * 2 +
+ ((b >> 8) - 2)];
+ sse_fn_pl(cpu_ptr0, cpu_T[0]);
}
break;
case 0x02c: /* cvttps2pi */
@@ -3591,14 +3622,18 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
rm = (modrm & 7) | REX_B(s);
op2_offset = offsetof(CPUX86State,xmm_regs[rm]);
}
- sse_op2 = sse_op_table3[(s->dflag == 2) * 2 + ((b >> 8) - 2) + 4 +
- (b & 1) * 4];
tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op2_offset);
if (ot == OT_LONG) {
- ((void (*)(TCGv_i32, TCGv_ptr))sse_op2)(cpu_tmp2_i32, cpu_ptr0);
+ sse_fn_i_p = sse_op_table3b[(s->dflag == 2) * 2 +
+ ((b >> 8) - 2) +
+ (b & 1) * 4];
+ sse_fn_i_p(cpu_tmp2_i32, cpu_ptr0);
tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
} else {
- ((void (*)(TCGv, TCGv_ptr))sse_op2)(cpu_T[0], cpu_ptr0);
+ sse_fn_l_p = sse_op_table3b[(s->dflag == 2) * 2 +
+ ((b >> 8) - 2) +
+ (b & 1) * 4];
+ sse_fn_l_p(cpu_T[0], cpu_ptr0);
}
gen_op_mov_reg_T0(ot, reg);
break;
@@ -3691,9 +3726,10 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
goto illegal_op;
}
- sse_op2 = sse_op_table6[b].op[b1];
- if (!sse_op2)
+ sse_fn_pp = sse_op_table6[b].op[b1];
+ if (!sse_fn_pp) {
goto illegal_op;
+ }
if (!(s->cpuid_ext_features & sse_op_table6[b].ext_mask))
goto illegal_op;
@@ -3742,12 +3778,13 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
gen_ldq_env_A0(s->mem_index, op2_offset);
}
}
- if (sse_op2 == SSE_SPECIAL)
+ if (sse_fn_pp == SSE_SPECIAL) {
goto illegal_op;
+ }
tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
- ((void (*)(TCGv_ptr, TCGv_ptr))sse_op2)(cpu_ptr0, cpu_ptr1);
+ sse_fn_pp(cpu_ptr0, cpu_ptr1);
if (b == 0x17)
s->cc_op = CC_OP_EFLAGS;
@@ -3793,13 +3830,14 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
goto illegal_op;
}
- sse_op2 = sse_op_table7[b].op[b1];
- if (!sse_op2)
+ sse_fn_ppi = sse_op_table7[b].op[b1];
+ if (!sse_fn_ppi) {
goto illegal_op;
+ }
if (!(s->cpuid_ext_features & sse_op_table7[b].ext_mask))
goto illegal_op;
- if (sse_op2 == SSE_SPECIAL) {
+ if (sse_fn_ppi == SSE_SPECIAL) {
ot = (s->dflag == 2) ? OT_QUAD : OT_LONG;
rm = (modrm & 7) | REX_B(s);
if (mod != 3)
@@ -3960,7 +3998,7 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
- ((void (*)(TCGv_ptr, TCGv_ptr, TCGv_i32))sse_op2)(cpu_ptr0, cpu_ptr1, tcg_const_i32(val));
+ sse_fn_ppi(cpu_ptr0, cpu_ptr1, tcg_const_i32(val));
break;
default:
goto illegal_op;
@@ -4015,29 +4053,33 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
if (!(s->cpuid_ext2_features & CPUID_EXT2_3DNOW))
goto illegal_op;
val = ldub_code(s->pc++);
- sse_op2 = sse_op_table5[val];
- if (!sse_op2)
+ sse_fn_pp = sse_op_table5[val];
+ if (!sse_fn_pp) {
goto illegal_op;
+ }
tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
- ((void (*)(TCGv_ptr, TCGv_ptr))sse_op2)(cpu_ptr0, cpu_ptr1);
+ sse_fn_pp(cpu_ptr0, cpu_ptr1);
break;
case 0x70: /* pshufx insn */
case 0xc6: /* pshufx insn */
val = ldub_code(s->pc++);
tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
- ((void (*)(TCGv_ptr, TCGv_ptr, TCGv_i32))sse_op2)(cpu_ptr0, cpu_ptr1, tcg_const_i32(val));
+ /* XXX: introduce a new table? */
+ sse_fn_ppi = (SSEFunc_0_ppi)sse_fn_pp;
+ sse_fn_ppi(cpu_ptr0, cpu_ptr1, tcg_const_i32(val));
break;
case 0xc2:
/* compare insns */
val = ldub_code(s->pc++);
if (val >= 8)
goto illegal_op;
- sse_op2 = sse_op_table4[val][b1];
+ sse_fn_pp = sse_op_table4[val][b1];
+
tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
- ((void (*)(TCGv_ptr, TCGv_ptr))sse_op2)(cpu_ptr0, cpu_ptr1);
+ sse_fn_pp(cpu_ptr0, cpu_ptr1);
break;
case 0xf7:
/* maskmov : we must prepare A0 */
@@ -4057,12 +4099,14 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
- ((void (*)(TCGv_ptr, TCGv_ptr, TCGv))sse_op2)(cpu_ptr0, cpu_ptr1, cpu_A0);
+ /* XXX: introduce a new table? */
+ sse_fn_ppt = (SSEFunc_0_ppt)sse_fn_pp;
+ sse_fn_ppt(cpu_ptr0, cpu_ptr1, cpu_A0);
break;
default:
tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
- ((void (*)(TCGv_ptr, TCGv_ptr))sse_op2)(cpu_ptr0, cpu_ptr1);
+ sse_fn_pp(cpu_ptr0, cpu_ptr1);
break;
}
if (b == 0x2e || b == 0x2f) {