mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-07 09:43:56 -06:00
tcg/i386: Fold the ext{8,16,32}[us] cases into {s}extract
Accept byte and word extensions with the extract opcodes. This is preparatory to removing the specialized extracts. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
ad76017e51
commit
4bce752c1a
5 changed files with 107 additions and 36 deletions
|
@ -80,7 +80,7 @@
|
||||||
#define TCG_TARGET_HAS_ctpop_i64 have_popcnt
|
#define TCG_TARGET_HAS_ctpop_i64 have_popcnt
|
||||||
#define TCG_TARGET_HAS_deposit_i64 1
|
#define TCG_TARGET_HAS_deposit_i64 1
|
||||||
#define TCG_TARGET_HAS_extract_i64 1
|
#define TCG_TARGET_HAS_extract_i64 1
|
||||||
#define TCG_TARGET_HAS_sextract_i64 0
|
#define TCG_TARGET_HAS_sextract_i64 1
|
||||||
#define TCG_TARGET_HAS_extract2_i64 1
|
#define TCG_TARGET_HAS_extract2_i64 1
|
||||||
#define TCG_TARGET_HAS_negsetcond_i64 1
|
#define TCG_TARGET_HAS_negsetcond_i64 1
|
||||||
#define TCG_TARGET_HAS_add2_i64 1
|
#define TCG_TARGET_HAS_add2_i64 1
|
||||||
|
@ -130,10 +130,47 @@
|
||||||
(TCG_TARGET_REG_BITS == 32 && (ofs) == 8 && (len) == 8))
|
(TCG_TARGET_REG_BITS == 32 && (ofs) == 8 && (len) == 8))
|
||||||
#define TCG_TARGET_deposit_i64_valid TCG_TARGET_deposit_i32_valid
|
#define TCG_TARGET_deposit_i64_valid TCG_TARGET_deposit_i32_valid
|
||||||
|
|
||||||
/* Check for the possibility of high-byte extraction and, for 64-bit,
|
/*
|
||||||
zero-extending 32-bit right-shift. */
|
* Check for the possibility of low byte/word extraction, high-byte extraction
|
||||||
#define TCG_TARGET_extract_i32_valid(ofs, len) ((ofs) == 8 && (len) == 8)
|
* and zero-extending 32-bit right-shift.
|
||||||
#define TCG_TARGET_extract_i64_valid(ofs, len) \
|
*
|
||||||
(((ofs) == 8 && (len) == 8) || ((ofs) + (len)) == 32)
|
* We cannot sign-extend from high byte to 64-bits without using the
|
||||||
|
* REX prefix that explicitly excludes access to the high-byte registers.
|
||||||
|
*/
|
||||||
|
static inline bool
|
||||||
|
tcg_target_sextract_valid(TCGType type, unsigned ofs, unsigned len)
|
||||||
|
{
|
||||||
|
switch (ofs) {
|
||||||
|
case 0:
|
||||||
|
switch (len) {
|
||||||
|
case 8:
|
||||||
|
case 16:
|
||||||
|
return true;
|
||||||
|
case 32:
|
||||||
|
return type == TCG_TYPE_I64;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case 8:
|
||||||
|
return len == 8 && type == TCG_TYPE_I32;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#define TCG_TARGET_sextract_valid tcg_target_sextract_valid
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
tcg_target_extract_valid(TCGType type, unsigned ofs, unsigned len)
|
||||||
|
{
|
||||||
|
if (type == TCG_TYPE_I64 && ofs + len == 32) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
switch (ofs) {
|
||||||
|
case 0:
|
||||||
|
return len == 8 || len == 16;
|
||||||
|
case 8:
|
||||||
|
return len == 8;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#define TCG_TARGET_extract_valid tcg_target_extract_valid
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -3035,6 +3035,10 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type,
|
||||||
|
|
||||||
case INDEX_op_extract_i64:
|
case INDEX_op_extract_i64:
|
||||||
if (a2 + args[3] == 32) {
|
if (a2 + args[3] == 32) {
|
||||||
|
if (a2 == 0) {
|
||||||
|
tcg_out_ext32u(s, a0, a1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
/* This is a 32-bit zero-extending right shift. */
|
/* This is a 32-bit zero-extending right shift. */
|
||||||
tcg_out_mov(s, TCG_TYPE_I32, a0, a1);
|
tcg_out_mov(s, TCG_TYPE_I32, a0, a1);
|
||||||
tcg_out_shifti(s, SHIFT_SHR, a0, a2);
|
tcg_out_shifti(s, SHIFT_SHR, a0, a2);
|
||||||
|
@ -3042,29 +3046,54 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type,
|
||||||
}
|
}
|
||||||
/* FALLTHRU */
|
/* FALLTHRU */
|
||||||
case INDEX_op_extract_i32:
|
case INDEX_op_extract_i32:
|
||||||
/* On the off-chance that we can use the high-byte registers.
|
if (a2 == 0 && args[3] == 8) {
|
||||||
Otherwise we emit the same ext16 + shift pattern that we
|
tcg_out_ext8u(s, a0, a1);
|
||||||
would have gotten from the normal tcg-op.c expansion. */
|
} else if (a2 == 0 && args[3] == 16) {
|
||||||
tcg_debug_assert(a2 == 8 && args[3] == 8);
|
tcg_out_ext16u(s, a0, a1);
|
||||||
|
} else if (a2 == 8 && args[3] == 8) {
|
||||||
|
/*
|
||||||
|
* On the off-chance that we can use the high-byte registers.
|
||||||
|
* Otherwise we emit the same ext16 + shift pattern that we
|
||||||
|
* would have gotten from the normal tcg-op.c expansion.
|
||||||
|
*/
|
||||||
if (a1 < 4 && a0 < 8) {
|
if (a1 < 4 && a0 < 8) {
|
||||||
tcg_out_modrm(s, OPC_MOVZBL, a0, a1 + 4);
|
tcg_out_modrm(s, OPC_MOVZBL, a0, a1 + 4);
|
||||||
} else {
|
} else {
|
||||||
tcg_out_ext16u(s, a0, a1);
|
tcg_out_ext16u(s, a0, a1);
|
||||||
tcg_out_shifti(s, SHIFT_SHR, a0, 8);
|
tcg_out_shifti(s, SHIFT_SHR, a0, 8);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INDEX_op_sextract_i64:
|
||||||
|
if (a2 == 0 && args[3] == 8) {
|
||||||
|
tcg_out_ext8s(s, TCG_TYPE_I64, a0, a1);
|
||||||
|
} else if (a2 == 0 && args[3] == 16) {
|
||||||
|
tcg_out_ext16s(s, TCG_TYPE_I64, a0, a1);
|
||||||
|
} else if (a2 == 0 && args[3] == 32) {
|
||||||
|
tcg_out_ext32s(s, a0, a1);
|
||||||
|
} else {
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INDEX_op_sextract_i32:
|
case INDEX_op_sextract_i32:
|
||||||
/* We don't implement sextract_i64, as we cannot sign-extend to
|
if (a2 == 0 && args[3] == 8) {
|
||||||
64-bits without using the REX prefix that explicitly excludes
|
tcg_out_ext8s(s, TCG_TYPE_I32, a0, a1);
|
||||||
access to the high-byte registers. */
|
} else if (a2 == 0 && args[3] == 16) {
|
||||||
tcg_debug_assert(a2 == 8 && args[3] == 8);
|
tcg_out_ext16s(s, TCG_TYPE_I32, a0, a1);
|
||||||
|
} else if (a2 == 8 && args[3] == 8) {
|
||||||
if (a1 < 4 && a0 < 8) {
|
if (a1 < 4 && a0 < 8) {
|
||||||
tcg_out_modrm(s, OPC_MOVSBL, a0, a1 + 4);
|
tcg_out_modrm(s, OPC_MOVSBL, a0, a1 + 4);
|
||||||
} else {
|
} else {
|
||||||
tcg_out_ext16s(s, TCG_TYPE_I32, a0, a1);
|
tcg_out_ext16s(s, TCG_TYPE_I32, a0, a1);
|
||||||
tcg_out_shifti(s, SHIFT_SAR, a0, 8);
|
tcg_out_shifti(s, SHIFT_SAR, a0, 8);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
OP_32_64(extract2):
|
OP_32_64(extract2):
|
||||||
|
@ -3746,6 +3775,7 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags)
|
||||||
case INDEX_op_extract_i32:
|
case INDEX_op_extract_i32:
|
||||||
case INDEX_op_extract_i64:
|
case INDEX_op_extract_i64:
|
||||||
case INDEX_op_sextract_i32:
|
case INDEX_op_sextract_i32:
|
||||||
|
case INDEX_op_sextract_i64:
|
||||||
case INDEX_op_ctpop_i32:
|
case INDEX_op_ctpop_i32:
|
||||||
case INDEX_op_ctpop_i64:
|
case INDEX_op_ctpop_i64:
|
||||||
return C_O1_I1(r, r);
|
return C_O1_I1(r, r);
|
||||||
|
|
|
@ -2362,8 +2362,10 @@ static void fold_setcond_tst_pow2(OptContext *ctx, TCGOp *op, bool neg)
|
||||||
xor_opc = INDEX_op_xor_i32;
|
xor_opc = INDEX_op_xor_i32;
|
||||||
shr_opc = INDEX_op_shr_i32;
|
shr_opc = INDEX_op_shr_i32;
|
||||||
neg_opc = INDEX_op_neg_i32;
|
neg_opc = INDEX_op_neg_i32;
|
||||||
if (TCG_TARGET_extract_i32_valid(sh, 1)) {
|
if (TCG_TARGET_extract_valid(TCG_TYPE_I32, sh, 1)) {
|
||||||
uext_opc = TCG_TARGET_HAS_extract_i32 ? INDEX_op_extract_i32 : 0;
|
uext_opc = TCG_TARGET_HAS_extract_i32 ? INDEX_op_extract_i32 : 0;
|
||||||
|
}
|
||||||
|
if (TCG_TARGET_sextract_valid(TCG_TYPE_I32, sh, 1)) {
|
||||||
sext_opc = TCG_TARGET_HAS_sextract_i32 ? INDEX_op_sextract_i32 : 0;
|
sext_opc = TCG_TARGET_HAS_sextract_i32 ? INDEX_op_sextract_i32 : 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -2373,8 +2375,10 @@ static void fold_setcond_tst_pow2(OptContext *ctx, TCGOp *op, bool neg)
|
||||||
xor_opc = INDEX_op_xor_i64;
|
xor_opc = INDEX_op_xor_i64;
|
||||||
shr_opc = INDEX_op_shr_i64;
|
shr_opc = INDEX_op_shr_i64;
|
||||||
neg_opc = INDEX_op_neg_i64;
|
neg_opc = INDEX_op_neg_i64;
|
||||||
if (TCG_TARGET_extract_i64_valid(sh, 1)) {
|
if (TCG_TARGET_extract_valid(TCG_TYPE_I64, sh, 1)) {
|
||||||
uext_opc = TCG_TARGET_HAS_extract_i64 ? INDEX_op_extract_i64 : 0;
|
uext_opc = TCG_TARGET_HAS_extract_i64 ? INDEX_op_extract_i64 : 0;
|
||||||
|
}
|
||||||
|
if (TCG_TARGET_sextract_valid(TCG_TYPE_I64, sh, 1)) {
|
||||||
sext_opc = TCG_TARGET_HAS_sextract_i64 ? INDEX_op_sextract_i64 : 0;
|
sext_opc = TCG_TARGET_HAS_sextract_i64 ? INDEX_op_sextract_i64 : 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -56,11 +56,15 @@
|
||||||
#ifndef TCG_TARGET_deposit_i64_valid
|
#ifndef TCG_TARGET_deposit_i64_valid
|
||||||
#define TCG_TARGET_deposit_i64_valid(ofs, len) 1
|
#define TCG_TARGET_deposit_i64_valid(ofs, len) 1
|
||||||
#endif
|
#endif
|
||||||
#ifndef TCG_TARGET_extract_i32_valid
|
#ifndef TCG_TARGET_extract_valid
|
||||||
#define TCG_TARGET_extract_i32_valid(ofs, len) 1
|
#define TCG_TARGET_extract_valid(type, ofs, len) \
|
||||||
|
((type) == TCG_TYPE_I32 ? TCG_TARGET_HAS_extract_i32 \
|
||||||
|
: TCG_TARGET_HAS_extract_i64)
|
||||||
#endif
|
#endif
|
||||||
#ifndef TCG_TARGET_extract_i64_valid
|
#ifndef TCG_TARGET_sextract_valid
|
||||||
#define TCG_TARGET_extract_i64_valid(ofs, len) 1
|
#define TCG_TARGET_sextract_valid(type, ofs, len) \
|
||||||
|
((type) == TCG_TYPE_I32 ? TCG_TARGET_HAS_sextract_i32 \
|
||||||
|
: TCG_TARGET_HAS_sextract_i64)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Only one of DIV or DIV2 should be defined. */
|
/* Only one of DIV or DIV2 should be defined. */
|
||||||
|
|
12
tcg/tcg-op.c
12
tcg/tcg-op.c
|
@ -1014,8 +1014,7 @@ void tcg_gen_extract_i32(TCGv_i32 ret, TCGv_i32 arg,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TCG_TARGET_HAS_extract_i32
|
if (TCG_TARGET_extract_valid(TCG_TYPE_I32, ofs, len)) {
|
||||||
&& TCG_TARGET_extract_i32_valid(ofs, len)) {
|
|
||||||
tcg_gen_op4ii_i32(INDEX_op_extract_i32, ret, arg, ofs, len);
|
tcg_gen_op4ii_i32(INDEX_op_extract_i32, ret, arg, ofs, len);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1077,8 +1076,7 @@ void tcg_gen_sextract_i32(TCGv_i32 ret, TCGv_i32 arg,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TCG_TARGET_HAS_sextract_i32
|
if (TCG_TARGET_sextract_valid(TCG_TYPE_I32, ofs, len)) {
|
||||||
&& TCG_TARGET_extract_i32_valid(ofs, len)) {
|
|
||||||
tcg_gen_op4ii_i32(INDEX_op_sextract_i32, ret, arg, ofs, len);
|
tcg_gen_op4ii_i32(INDEX_op_sextract_i32, ret, arg, ofs, len);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2811,8 +2809,7 @@ void tcg_gen_extract_i64(TCGv_i64 ret, TCGv_i64 arg,
|
||||||
goto do_shift_and;
|
goto do_shift_and;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TCG_TARGET_HAS_extract_i64
|
if (TCG_TARGET_extract_valid(TCG_TYPE_I64, ofs, len)) {
|
||||||
&& TCG_TARGET_extract_i64_valid(ofs, len)) {
|
|
||||||
tcg_gen_op4ii_i64(INDEX_op_extract_i64, ret, arg, ofs, len);
|
tcg_gen_op4ii_i64(INDEX_op_extract_i64, ret, arg, ofs, len);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2917,8 +2914,7 @@ void tcg_gen_sextract_i64(TCGv_i64 ret, TCGv_i64 arg,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TCG_TARGET_HAS_sextract_i64
|
if (TCG_TARGET_sextract_valid(TCG_TYPE_I64, ofs, len)) {
|
||||||
&& TCG_TARGET_extract_i64_valid(ofs, len)) {
|
|
||||||
tcg_gen_op4ii_i64(INDEX_op_sextract_i64, ret, arg, ofs, len);
|
tcg_gen_op4ii_i64(INDEX_op_sextract_i64, ret, arg, ofs, len);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue