target/i386: do not cast gen_helper_* function pointers
Use a union to store the various possible kinds of function pointers, and access the correct one based on the flags. SSEOpHelper_table6 and SSEOpHelper_table7 right now only have one case, but this would change with AVX's 3- and 4-argument operations. Use unions there too, to keep the code more similar for the three tables. Extracted from a patch by Paul Brook <paul@nowt.org>. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
ce4fa29f94
commit
7f32690243
@ -2784,6 +2784,8 @@ typedef void (*SSEFunc_l_ep)(TCGv_i64 val, TCGv_ptr env, TCGv_ptr reg);
|
|||||||
typedef void (*SSEFunc_0_epi)(TCGv_ptr env, TCGv_ptr reg, TCGv_i32 val);
|
typedef void (*SSEFunc_0_epi)(TCGv_ptr env, TCGv_ptr reg, TCGv_i32 val);
|
||||||
typedef void (*SSEFunc_0_epl)(TCGv_ptr env, TCGv_ptr reg, TCGv_i64 val);
|
typedef void (*SSEFunc_0_epl)(TCGv_ptr env, TCGv_ptr reg, TCGv_i64 val);
|
||||||
typedef void (*SSEFunc_0_epp)(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b);
|
typedef void (*SSEFunc_0_epp)(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b);
|
||||||
|
typedef void (*SSEFunc_0_eppp)(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b,
|
||||||
|
TCGv_ptr reg_c);
|
||||||
typedef void (*SSEFunc_0_eppi)(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b,
|
typedef void (*SSEFunc_0_eppi)(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b,
|
||||||
TCGv_i32 val);
|
TCGv_i32 val);
|
||||||
typedef void (*SSEFunc_0_ppi)(TCGv_ptr reg_a, TCGv_ptr reg_b, TCGv_i32 val);
|
typedef void (*SSEFunc_0_ppi)(TCGv_ptr reg_a, TCGv_ptr reg_b, TCGv_i32 val);
|
||||||
@ -2798,7 +2800,7 @@ typedef void (*SSEFunc_0_eppt)(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b,
|
|||||||
#define SSE_OPF_SHUF (1 << 9) /* pshufx/shufpx */
|
#define SSE_OPF_SHUF (1 << 9) /* pshufx/shufpx */
|
||||||
|
|
||||||
#define OP(op, flags, a, b, c, d) \
|
#define OP(op, flags, a, b, c, d) \
|
||||||
{flags, {a, b, c, d} }
|
{flags, {{.op = a}, {.op = b}, {.op = c}, {.op = d} } }
|
||||||
|
|
||||||
#define MMX_OP(x) OP(op1, SSE_OPF_MMX, \
|
#define MMX_OP(x) OP(op1, SSE_OPF_MMX, \
|
||||||
gen_helper_ ## x ## _mmx, gen_helper_ ## x ## _xmm, NULL, NULL)
|
gen_helper_ ## x ## _mmx, gen_helper_ ## x ## _xmm, NULL, NULL)
|
||||||
@ -2809,9 +2811,15 @@ typedef void (*SSEFunc_0_eppt)(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b,
|
|||||||
#define SSE_OP(sname, dname, op, flags) OP(op, flags, \
|
#define SSE_OP(sname, dname, op, flags) OP(op, flags, \
|
||||||
gen_helper_##sname##_xmm, gen_helper_##dname##_xmm, NULL, NULL)
|
gen_helper_##sname##_xmm, gen_helper_##dname##_xmm, NULL, NULL)
|
||||||
|
|
||||||
|
typedef union SSEFuncs {
|
||||||
|
SSEFunc_0_epp op1;
|
||||||
|
SSEFunc_0_ppi op1i;
|
||||||
|
SSEFunc_0_eppt op1t;
|
||||||
|
} SSEFuncs;
|
||||||
|
|
||||||
struct SSEOpHelper_table1 {
|
struct SSEOpHelper_table1 {
|
||||||
int flags;
|
int flags;
|
||||||
SSEFunc_0_epp op[4];
|
SSEFuncs fn[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SSE_3DNOW { SSE_OPF_3DNOW }
|
#define SSE_3DNOW { SSE_OPF_3DNOW }
|
||||||
@ -2867,8 +2875,7 @@ static const struct SSEOpHelper_table1 sse_op_table1[256] = {
|
|||||||
[0x5f] = SSE_FOP(max),
|
[0x5f] = SSE_FOP(max),
|
||||||
|
|
||||||
[0xc2] = SSE_FOP(cmpeq), /* sse_op_table4 */
|
[0xc2] = SSE_FOP(cmpeq), /* sse_op_table4 */
|
||||||
[0xc6] = OP(dummy, SSE_OPF_SHUF, (SSEFunc_0_epp)gen_helper_shufps_xmm,
|
[0xc6] = SSE_OP(shufps, shufpd, op1i, SSE_OPF_SHUF),
|
||||||
(SSEFunc_0_epp)gen_helper_shufpd_xmm, NULL, NULL),
|
|
||||||
|
|
||||||
/* SSSE3, SSE4, MOVBE, CRC32, BMI1, BMI2, ADX. */
|
/* SSSE3, SSE4, MOVBE, CRC32, BMI1, BMI2, ADX. */
|
||||||
[0x38] = SSE_SPECIAL,
|
[0x38] = SSE_SPECIAL,
|
||||||
@ -2894,10 +2901,8 @@ static const struct SSEOpHelper_table1 sse_op_table1[256] = {
|
|||||||
[0x6e] = SSE_SPECIAL, /* movd mm, ea */
|
[0x6e] = SSE_SPECIAL, /* movd mm, ea */
|
||||||
[0x6f] = SSE_SPECIAL, /* movq, movdqa, , movqdu */
|
[0x6f] = SSE_SPECIAL, /* movq, movdqa, , movqdu */
|
||||||
[0x70] = OP(op1i, SSE_OPF_SHUF | SSE_OPF_MMX,
|
[0x70] = OP(op1i, SSE_OPF_SHUF | SSE_OPF_MMX,
|
||||||
(SSEFunc_0_epp)gen_helper_pshufw_mmx,
|
gen_helper_pshufw_mmx, gen_helper_pshufd_xmm,
|
||||||
(SSEFunc_0_epp)gen_helper_pshufd_xmm,
|
gen_helper_pshufhw_xmm, gen_helper_pshuflw_xmm),
|
||||||
(SSEFunc_0_epp)gen_helper_pshufhw_xmm,
|
|
||||||
(SSEFunc_0_epp)gen_helper_pshuflw_xmm),
|
|
||||||
[0x71] = SSE_SPECIAL, /* shiftw */
|
[0x71] = SSE_SPECIAL, /* shiftw */
|
||||||
[0x72] = SSE_SPECIAL, /* shiftd */
|
[0x72] = SSE_SPECIAL, /* shiftd */
|
||||||
[0x73] = SSE_SPECIAL, /* shiftq */
|
[0x73] = SSE_SPECIAL, /* shiftq */
|
||||||
@ -2959,8 +2964,7 @@ static const struct SSEOpHelper_table1 sse_op_table1[256] = {
|
|||||||
[0xf5] = MMX_OP(pmaddwd),
|
[0xf5] = MMX_OP(pmaddwd),
|
||||||
[0xf6] = MMX_OP(psadbw),
|
[0xf6] = MMX_OP(psadbw),
|
||||||
[0xf7] = OP(op1t, SSE_OPF_MMX,
|
[0xf7] = OP(op1t, SSE_OPF_MMX,
|
||||||
(SSEFunc_0_epp)gen_helper_maskmov_mmx,
|
gen_helper_maskmov_mmx, gen_helper_maskmov_xmm, NULL, NULL),
|
||||||
(SSEFunc_0_epp)gen_helper_maskmov_xmm, NULL, NULL),
|
|
||||||
[0xf8] = MMX_OP(psubb),
|
[0xf8] = MMX_OP(psubb),
|
||||||
[0xf9] = MMX_OP(psubw),
|
[0xf9] = MMX_OP(psubw),
|
||||||
[0xfa] = MMX_OP(psubl),
|
[0xfa] = MMX_OP(psubl),
|
||||||
@ -3057,17 +3061,19 @@ static const SSEFunc_0_epp sse_op_table5[256] = {
|
|||||||
[0xb6] = gen_helper_movq, /* pfrcpit2 */
|
[0xb6] = gen_helper_movq, /* pfrcpit2 */
|
||||||
[0xb7] = gen_helper_pmulhrw_mmx,
|
[0xb7] = gen_helper_pmulhrw_mmx,
|
||||||
[0xbb] = gen_helper_pswapd,
|
[0xbb] = gen_helper_pswapd,
|
||||||
[0xbf] = gen_helper_pavgb_mmx /* pavgusb */
|
[0xbf] = gen_helper_pavgb_mmx,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SSEOpHelper_table6 {
|
struct SSEOpHelper_table6 {
|
||||||
SSEFunc_0_epp op[2];
|
SSEFuncs fn[2];
|
||||||
uint32_t ext_mask;
|
uint32_t ext_mask;
|
||||||
int flags;
|
int flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SSEOpHelper_table7 {
|
struct SSEOpHelper_table7 {
|
||||||
SSEFunc_0_eppi op[2];
|
union {
|
||||||
|
SSEFunc_0_eppi op1;
|
||||||
|
} fn[2];
|
||||||
uint32_t ext_mask;
|
uint32_t ext_mask;
|
||||||
int flags;
|
int flags;
|
||||||
};
|
};
|
||||||
@ -3075,7 +3081,8 @@ struct SSEOpHelper_table7 {
|
|||||||
#define gen_helper_special_xmm NULL
|
#define gen_helper_special_xmm NULL
|
||||||
|
|
||||||
#define OP(name, op, flags, ext, mmx_name) \
|
#define OP(name, op, flags, ext, mmx_name) \
|
||||||
{{mmx_name, gen_helper_ ## name ## _xmm}, CPUID_EXT_ ## ext, flags}
|
{{{.op = mmx_name}, {.op = gen_helper_ ## name ## _xmm} }, \
|
||||||
|
CPUID_EXT_ ## ext, flags}
|
||||||
#define BINARY_OP_MMX(name, ext) \
|
#define BINARY_OP_MMX(name, ext) \
|
||||||
OP(name, op1, SSE_OPF_MMX, ext, gen_helper_ ## name ## _mmx)
|
OP(name, op1, SSE_OPF_MMX, ext, gen_helper_ ## name ## _mmx)
|
||||||
#define BINARY_OP(name, ext, flags) \
|
#define BINARY_OP(name, ext, flags) \
|
||||||
@ -3185,11 +3192,9 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
|
|||||||
int b1, op1_offset, op2_offset, is_xmm, val;
|
int b1, op1_offset, op2_offset, is_xmm, val;
|
||||||
int modrm, mod, rm, reg;
|
int modrm, mod, rm, reg;
|
||||||
int sse_op_flags;
|
int sse_op_flags;
|
||||||
|
SSEFuncs sse_op_fn;
|
||||||
const struct SSEOpHelper_table6 *op6;
|
const struct SSEOpHelper_table6 *op6;
|
||||||
const struct SSEOpHelper_table7 *op7;
|
const struct SSEOpHelper_table7 *op7;
|
||||||
SSEFunc_0_epp sse_fn_epp;
|
|
||||||
SSEFunc_0_ppi sse_fn_ppi;
|
|
||||||
SSEFunc_0_eppt sse_fn_eppt;
|
|
||||||
MemOp ot;
|
MemOp ot;
|
||||||
|
|
||||||
b &= 0xff;
|
b &= 0xff;
|
||||||
@ -3202,9 +3207,9 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
|
|||||||
else
|
else
|
||||||
b1 = 0;
|
b1 = 0;
|
||||||
sse_op_flags = sse_op_table1[b].flags;
|
sse_op_flags = sse_op_table1[b].flags;
|
||||||
sse_fn_epp = sse_op_table1[b].op[b1];
|
sse_op_fn = sse_op_table1[b].fn[b1];
|
||||||
if ((sse_op_flags & (SSE_OPF_SPECIAL | SSE_OPF_3DNOW)) == 0
|
if ((sse_op_flags & (SSE_OPF_SPECIAL | SSE_OPF_3DNOW)) == 0
|
||||||
&& !sse_fn_epp) {
|
&& !sse_op_fn.op1) {
|
||||||
goto unknown_op;
|
goto unknown_op;
|
||||||
}
|
}
|
||||||
if ((b <= 0x5f && b >= 0x10) || b == 0xc6 || b == 0xc2) {
|
if ((b <= 0x5f && b >= 0x10) || b == 0xc6 || b == 0xc2) {
|
||||||
@ -3618,9 +3623,9 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
|
|||||||
op1_offset = offsetof(CPUX86State,mmx_t0);
|
op1_offset = offsetof(CPUX86State,mmx_t0);
|
||||||
}
|
}
|
||||||
assert(b1 < 2);
|
assert(b1 < 2);
|
||||||
sse_fn_epp = sse_op_table2[((b - 1) & 3) * 8 +
|
SSEFunc_0_epp fn = sse_op_table2[((b - 1) & 3) * 8 +
|
||||||
(((modrm >> 3)) & 7)][b1];
|
(((modrm >> 3)) & 7)][b1];
|
||||||
if (!sse_fn_epp) {
|
if (!fn) {
|
||||||
goto unknown_op;
|
goto unknown_op;
|
||||||
}
|
}
|
||||||
if (is_xmm) {
|
if (is_xmm) {
|
||||||
@ -3632,7 +3637,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
|
|||||||
}
|
}
|
||||||
tcg_gen_addi_ptr(s->ptr0, cpu_env, op2_offset);
|
tcg_gen_addi_ptr(s->ptr0, cpu_env, op2_offset);
|
||||||
tcg_gen_addi_ptr(s->ptr1, cpu_env, op1_offset);
|
tcg_gen_addi_ptr(s->ptr1, cpu_env, op1_offset);
|
||||||
sse_fn_epp(cpu_env, s->ptr0, s->ptr1);
|
fn(cpu_env, s->ptr0, s->ptr1);
|
||||||
break;
|
break;
|
||||||
case 0x050: /* movmskps */
|
case 0x050: /* movmskps */
|
||||||
rm = (modrm & 7) | REX_B(s);
|
rm = (modrm & 7) | REX_B(s);
|
||||||
@ -3889,12 +3894,12 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
|
|||||||
gen_ldo_env_A0(s, op2_offset);
|
gen_ldo_env_A0(s, op2_offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!op6->op[b1]) {
|
if (!op6->fn[b1].op1) {
|
||||||
goto illegal_op;
|
goto illegal_op;
|
||||||
}
|
}
|
||||||
tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset);
|
tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset);
|
||||||
tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
|
tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
|
||||||
op6->op[b1](cpu_env, s->ptr0, s->ptr1);
|
op6->fn[b1].op1(cpu_env, s->ptr0, s->ptr1);
|
||||||
} else {
|
} else {
|
||||||
if ((op6->flags & SSE_OPF_MMX) == 0) {
|
if ((op6->flags & SSE_OPF_MMX) == 0) {
|
||||||
goto unknown_op;
|
goto unknown_op;
|
||||||
@ -3909,7 +3914,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
|
|||||||
}
|
}
|
||||||
tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset);
|
tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset);
|
||||||
tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
|
tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
|
||||||
op6->op[0](cpu_env, s->ptr0, s->ptr1);
|
op6->fn[0].op1(cpu_env, s->ptr0, s->ptr1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (op6->flags & SSE_OPF_CMP) {
|
if (op6->flags & SSE_OPF_CMP) {
|
||||||
@ -4450,8 +4455,8 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
|
|||||||
/* We only actually have one MMX instuction (palignr) */
|
/* We only actually have one MMX instuction (palignr) */
|
||||||
assert(b == 0x0f);
|
assert(b == 0x0f);
|
||||||
|
|
||||||
op7->op[0](cpu_env, s->ptr0, s->ptr1,
|
op7->fn[0].op1(cpu_env, s->ptr0, s->ptr1,
|
||||||
tcg_const_i32(val));
|
tcg_const_i32(val));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4477,7 +4482,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
|
|||||||
|
|
||||||
tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset);
|
tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset);
|
||||||
tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
|
tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
|
||||||
op7->op[b1](cpu_env, s->ptr0, s->ptr1, tcg_const_i32(val));
|
op7->fn[b1].op1(cpu_env, s->ptr0, s->ptr1, tcg_const_i32(val));
|
||||||
if (op7->flags & SSE_OPF_CMP) {
|
if (op7->flags & SSE_OPF_CMP) {
|
||||||
set_cc_op(s, CC_OP_EFLAGS);
|
set_cc_op(s, CC_OP_EFLAGS);
|
||||||
}
|
}
|
||||||
@ -4603,9 +4608,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
|
|||||||
tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
|
tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
|
||||||
if (sse_op_flags & SSE_OPF_SHUF) {
|
if (sse_op_flags & SSE_OPF_SHUF) {
|
||||||
val = x86_ldub_code(env, s);
|
val = x86_ldub_code(env, s);
|
||||||
/* XXX: introduce a new table? */
|
sse_op_fn.op1i(s->ptr0, s->ptr1, tcg_const_i32(val));
|
||||||
sse_fn_ppi = (SSEFunc_0_ppi)sse_fn_epp;
|
|
||||||
sse_fn_ppi(s->ptr0, s->ptr1, tcg_const_i32(val));
|
|
||||||
} else if (b == 0xf7) {
|
} else if (b == 0xf7) {
|
||||||
/* maskmov : we must prepare A0 */
|
/* maskmov : we must prepare A0 */
|
||||||
if (mod != 3) {
|
if (mod != 3) {
|
||||||
@ -4614,17 +4617,13 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
|
|||||||
tcg_gen_mov_tl(s->A0, cpu_regs[R_EDI]);
|
tcg_gen_mov_tl(s->A0, cpu_regs[R_EDI]);
|
||||||
gen_extu(s->aflag, s->A0);
|
gen_extu(s->aflag, s->A0);
|
||||||
gen_add_A0_ds_seg(s);
|
gen_add_A0_ds_seg(s);
|
||||||
|
sse_op_fn.op1t(cpu_env, s->ptr0, s->ptr1, s->A0);
|
||||||
/* XXX: introduce a new table? */
|
|
||||||
sse_fn_eppt = (SSEFunc_0_eppt)sse_fn_epp;
|
|
||||||
sse_fn_eppt(cpu_env, s->ptr0, s->ptr1, s->A0);
|
|
||||||
} else if (b == 0xc2) {
|
} else if (b == 0xc2) {
|
||||||
/* compare insns, bits 7:3 (7:5 for AVX) are ignored */
|
/* compare insns, bits 7:3 (7:5 for AVX) are ignored */
|
||||||
val = x86_ldub_code(env, s) & 7;
|
val = x86_ldub_code(env, s) & 7;
|
||||||
sse_fn_epp = sse_op_table4[val][b1];
|
sse_op_table4[val][b1](cpu_env, s->ptr0, s->ptr1);
|
||||||
sse_fn_epp(cpu_env, s->ptr0, s->ptr1);
|
|
||||||
} else {
|
} else {
|
||||||
sse_fn_epp(cpu_env, s->ptr0, s->ptr1);
|
sse_op_fn.op1(cpu_env, s->ptr0, s->ptr1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sse_op_flags & SSE_OPF_CMP) {
|
if (sse_op_flags & SSE_OPF_CMP) {
|
||||||
|
Loading…
Reference in New Issue
Block a user