diff options
author | Jan Kiszka <jan.kiszka@siemens.com> | 2011-09-29 18:52:11 +0200 |
---|---|---|
committer | Blue Swirl <blauwirbel@gmail.com> | 2011-10-01 06:42:46 +0000 |
commit | a4773324b4bc5f15fe9b438e4cfff05e1ab16dfa (patch) | |
tree | ca5efb7a06cf3f553b339b7a945447ae242ad6b3 | |
parent | 7e17a217061e402243499d96fc8dec92162d8b4a (diff) | |
download | qemu-a4773324b4bc5f15fe9b438e4cfff05e1ab16dfa.zip qemu-a4773324b4bc5f15fe9b438e4cfff05e1ab16dfa.tar.gz qemu-a4773324b4bc5f15fe9b438e4cfff05e1ab16dfa.tar.bz2 |
tcg-i386: Introduce limited deposit support
x86 cannot provide an optimized generic deposit implementation. But at
least for a few special cases, namely for writing bits 0..7, 8..15, and
0..15, versions using only a single instruction are feasible.
Introducing such limited support improves emulating 16-bit x86 code on
x86, but also rarer cases where 32-bit or 64-bit code accesses bytes or
words.
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
-rw-r--r-- | tcg/i386/tcg-target.c | 24 | ||||
-rw-r--r-- | tcg/i386/tcg-target.h | 9 | ||||
-rw-r--r-- | tcg/tcg-op.h | 4 | ||||
-rw-r--r-- | tcg/tcg.h | 7 |
4 files changed, 40 insertions, 4 deletions
diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c index 281f87d..3069e53 100644 --- a/tcg/i386/tcg-target.c +++ b/tcg/i386/tcg-target.c @@ -168,6 +168,10 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) tcg_regset_set32(ct->u.regs, 0, 0xf); } break; + case 'Q': + ct->ct |= TCG_CT_REG; + tcg_regset_set32(ct->u.regs, 0, 0xf); + break; case 'r': ct->ct |= TCG_CT_REG; if (TCG_TARGET_REG_BITS == 64) { @@ -1747,6 +1751,22 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, break; #endif + OP_32_64(deposit): + if (args[3] == 0 && args[4] == 8) { + /* load bits 0..7 */ + tcg_out_modrm(s, OPC_MOVB_EvGv | P_REXB_R | P_REXB_RM, + args[2], args[0]); + } else if (args[3] == 8 && args[4] == 8) { + /* load bits 8..15 */ + tcg_out_modrm(s, OPC_MOVB_EvGv, args[2], args[0] + 4); + } else if (args[3] == 0 && args[4] == 16) { + /* load bits 0..15 */ + tcg_out_modrm(s, OPC_MOVL_EvGv | P_DATA16, args[2], args[0]); + } else { + tcg_abort(); + } + break; + default: tcg_abort(); } @@ -1802,6 +1822,8 @@ static const TCGTargetOpDef x86_op_defs[] = { { INDEX_op_setcond_i32, { "q", "r", "ri" } }, + { INDEX_op_deposit_i32, { "Q", "0", "Q" } }, + #if TCG_TARGET_REG_BITS == 32 { INDEX_op_mulu2_i32, { "a", "d", "a", "r" } }, { INDEX_op_add2_i32, { "r", "r", "0", "1", "ri", "ri" } }, @@ -1853,6 +1875,8 @@ static const TCGTargetOpDef x86_op_defs[] = { { INDEX_op_ext8u_i64, { "r", "r" } }, { INDEX_op_ext16u_i64, { "r", "r" } }, { INDEX_op_ext32u_i64, { "r", "r" } }, + + { INDEX_op_deposit_i64, { "Q", "0", "Q" } }, #endif #if TCG_TARGET_REG_BITS == 64 diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h index 5088e47..b9c9d4e 100644 --- a/tcg/i386/tcg-target.h +++ b/tcg/i386/tcg-target.h @@ -90,7 +90,7 @@ enum { #define TCG_TARGET_HAS_eqv_i32 0 #define TCG_TARGET_HAS_nand_i32 0 #define TCG_TARGET_HAS_nor_i32 0 -#define TCG_TARGET_HAS_deposit_i32 0 +#define TCG_TARGET_HAS_deposit_i32 1 #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_div2_i64 1 @@ -111,9 +111,14 @@ enum { #define TCG_TARGET_HAS_eqv_i64 0 #define TCG_TARGET_HAS_nand_i64 0 #define TCG_TARGET_HAS_nor_i64 0 -#define TCG_TARGET_HAS_deposit_i64 0 +#define TCG_TARGET_HAS_deposit_i64 1 #endif +#define TCG_TARGET_deposit_i32_valid(ofs, len) \ + (((ofs) == 0 && (len) == 8) || ((ofs) == 8 && (len) == 8) || \ + ((ofs) == 0 && (len) == 16)) +#define TCG_TARGET_deposit_i64_valid TCG_TARGET_deposit_i32_valid + #define TCG_TARGET_HAS_GUEST_BASE /* Note: must be synced with dyngen-exec.h */ diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h index 404b637..fea5983 100644 --- a/tcg/tcg-op.h +++ b/tcg/tcg-op.h @@ -2045,7 +2045,7 @@ static inline void tcg_gen_deposit_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2, unsigned int ofs, unsigned int len) { - if (TCG_TARGET_HAS_deposit_i32) { + if (TCG_TARGET_HAS_deposit_i32 && TCG_TARGET_deposit_i32_valid(ofs, len)) { tcg_gen_op5ii_i32(INDEX_op_deposit_i32, ret, arg1, arg2, ofs, len); } else { uint32_t mask = (1u << len) - 1; @@ -2064,7 +2064,7 @@ static inline void tcg_gen_deposit_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2, unsigned int ofs, unsigned int len) { - if (TCG_TARGET_HAS_deposit_i64) { + if (TCG_TARGET_HAS_deposit_i64 && TCG_TARGET_deposit_i64_valid(ofs, len)) { tcg_gen_op5ii_i64(INDEX_op_deposit_i64, ret, arg1, arg2, ofs, len); } else { uint64_t mask = (1ull << len) - 1; @@ -81,6 +81,13 @@ typedef uint64_t TCGRegSet; #define TCG_TARGET_HAS_deposit_i64 0 #endif +#ifndef TCG_TARGET_deposit_i32_valid +#define TCG_TARGET_deposit_i32_valid(ofs, len) 1 +#endif +#ifndef TCG_TARGET_deposit_i64_valid +#define TCG_TARGET_deposit_i64_valid(ofs, len) 1 +#endif + /* Only one of DIV or DIV2 should be defined. */ #if defined(TCG_TARGET_HAS_div_i32) #define TCG_TARGET_HAS_div2_i32 0 |