tcg-i386: Introduce specific deposit helpers
PATCH 1/1 tcg-i386: Introduce specific deposit helpers
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, a version using only a single instruction is feasible. Introducing such helpers improves emulating 16-bit x86 code on x86, but also rarer cases where 32-bit or 64-bit code accesses bytes or words.
--- tcg/i386/tcg-target.c | 25 +++++++++++++++++++++++++ tcg/i386/tcg-target.h | 6 ++++++ tcg/tcg-op.h | 12 ++++++++++++ tcg/tcg-opc.h | 6 ++++++ tcg/tcg.h | 3 +++ 5 files changed, 52 insertions(+), 0 deletions(-)
tcg/i386/tcg-target.c +25 -0
@@ -1747,6 +1747,19 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,break ;#endif + OP_32_64(deposit8l): + tcg_out_modrm(s, OPC_MOVB_EvGv | P_REXB_R | P_REXB_RM, +args [2 ],args [0 ]); +break ; + + OP_32_64(deposit8h): + tcg_out_modrm(s, OPC_MOVB_EvGv, args[2], args[0] + 4); +break ; + + OP_32_64(deposit16l): + tcg_out_modrm(s, OPC_MOVL_EvGv | P_DATA16, args[2], args[0]); +break ; +default :tcg_abort (); }
@@ -1802,6 +1815,14 @@ static const TCGTargetOpDef x86_op_defs[] = { { INDEX_op_setcond_i32, { "q", "r", "ri" } }, +#if TCG_TARGET_REG_BITS ==64 + { INDEX_op_deposit8l_i32, { "r", "0", "r" } }, +#else + { INDEX_op_deposit8l_i32, { "abcd", "0", "abcd" } }, +#endif + { INDEX_op_deposit8h_i32, { "abcd", "0", "abcd" } }, + { INDEX_op_deposit16l_i32, { "r", "0", "r" } }, + #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 +1874,10 @@ 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_deposit8l_i64, { "r", "0", "r" } }, + { INDEX_op_deposit8h_i64, { "abcd", "0", "abcd" } }, + { INDEX_op_deposit16l_i64, { "r", "0", "r" } }, #endif #if TCG_TARGET_REG_BITS == 64
tcg/i386/tcg-target.h +6 -0
@@ -91,6 +91,9 @@ enum {#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_deposit8l_i32 1 +#define TCG_TARGET_HAS_deposit8h_i32 1 +#define TCG_TARGET_HAS_deposit16l_i32 1#if TCG_TARGET_REG_BITS ==64 #define TCG_TARGET_HAS_div2_i64 1
@@ -112,6 +115,9 @@ enum {#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_deposit8l_i64 1 +#define TCG_TARGET_HAS_deposit8h_i64 1 +#define TCG_TARGET_HAS_deposit16l_i64 1#endif #define TCG_TARGET_HAS_GUEST_BASE
tcg/tcg-op.h +12 -0
@@ -2047,6 +2047,12 @@ static inline void tcg_gen_deposit_i32(TCGv_i32 ret, TCGv_i32 arg1, {if (TCG_TARGET_HAS_deposit_i32) {tcg_gen_op5ii_i32 (INDEX_op_deposit_i32, ret, arg1, arg2, ofs, len); + }else if (ofs ==0 && len ==8 && TCG_TARGET_HAS_deposit8l_i32) { +tcg_gen_op3_i32 (INDEX_op_deposit8l_i32, ret, arg1, arg2); + }else if (ofs ==8 && len ==8 && TCG_TARGET_HAS_deposit8h_i32) { +tcg_gen_op3_i32 (INDEX_op_deposit8h_i32, ret, arg1, arg2); + }else if (ofs ==0 && len ==16 && TCG_TARGET_HAS_deposit16l_i32) { +tcg_gen_op3_i32 (INDEX_op_deposit16l_i32, ret, arg1, arg2); }else {uint32_t mask = (1u << len) -1 ;TCGv_i32 t1 =tcg_temp_new_i32 ();
@@ -2066,6 +2072,12 @@ static inline void tcg_gen_deposit_i64(TCGv_i64 ret, TCGv_i64 arg1, {if (TCG_TARGET_HAS_deposit_i64) {tcg_gen_op5ii_i64 (INDEX_op_deposit_i64, ret, arg1, arg2, ofs, len); + }else if (ofs ==0 && len ==8 && TCG_TARGET_HAS_deposit8l_i64) { +tcg_gen_op3_i32 (INDEX_op_deposit8l_i64, ret, arg1, arg2); + }else if (ofs ==8 && len ==8 && TCG_TARGET_HAS_deposit8h_i64) { +tcg_gen_op3_i32 (INDEX_op_deposit8h_i64, ret, arg1, arg2); + }else if (ofs ==0 && len ==16 && TCG_TARGET_HAS_deposit16l_i64) { +tcg_gen_op3_i32 (INDEX_op_deposit16l_i64, ret, arg1, arg2); }else {uint64_t mask = (1ull << len) -1 ;TCGv_i64 t1 =tcg_temp_new_i64 ();
tcg/tcg-opc.h +6 -0
@@ -80,6 +80,9 @@ DEF(sar_i32, 1, 2, 0, 0) DEF(rotl_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_rot_i32)) DEF(rotr_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_rot_i32)) DEF(deposit_i32, 1, 2, 2, IMPL(TCG_TARGET_HAS_deposit_i32)) +DEF(deposit8l_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_deposit8l_i32)) +DEF(deposit8h_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_deposit8h_i32)) +DEF(deposit16l_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_deposit16l_i32))DEF (brcond_i32,0 ,2 ,2 ,TCG_OPF_BB_END |TCG_OPF_SIDE_EFFECTS )
@@ -139,6 +142,9 @@ DEF(sar_i64, 1, 2, 0, IMPL64) DEF(rotl_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_rot_i64)) DEF(rotr_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_rot_i64)) DEF(deposit_i64, 1, 2, 2, IMPL64 | IMPL(TCG_TARGET_HAS_deposit_i64)) +DEF(deposit8l_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_deposit8l_i64)) +DEF(deposit8h_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_deposit8h_i64)) +DEF(deposit16l_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_deposit16l_i64)) DEF(brcond_i64, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS | IMPL64)DEF (ext8s_i64,1 ,1 ,0 ,IMPL64 |IMPL (TCG_TARGET_HAS_ext8s_i64))
tcg/tcg.h +3 -0
@@ -69,6 +69,9 @@ typedef uint64_t TCGRegSet;#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_deposit8l_i64 0 +#define TCG_TARGET_HAS_deposit8h_i64 0 +#define TCG_TARGET_HAS_deposit16l_i64 0#endif /* Only one of DIV or DIV2 should be defined. */
Signature · 1 line
1.7.3.4
tcg/i386/tcg-target.c static const TCGTargetOpDef x86_op_defs[] = { · line 1822
Quoted 5 lines · Jan Kiszka
tcg/i386/tcg-target.c +5
-0+#if TCG_TARGET_REG_BITS == 64 + { INDEX_op_deposit8l_i32, { "r", "0", "r" } }, +#else + { INDEX_op_deposit8l_i32, { "abcd", "0", "abcd" } }, +#endif
At minimum, abcd is spelled "q".
I don't particularly care for the 3 different opcodes. Perhaps we'd be better off with an inline predicate for when the deposit opcode is "valid"?
r~
Quoted 8 lines · Richard Henderson
tcg/i386/tcg-target.c static const TCGTargetOpDef x86_op_defs[] = { · line 1822
Quoted 5 lines · Jan Kiszka
tcg/i386/tcg-target.c +5
-0+#if TCG_TARGET_REG_BITS == 64 + { INDEX_op_deposit8l_i32, { "r", "0", "r" } }, +#else + { INDEX_op_deposit8l_i32, { "abcd", "0", "abcd" } }, +#endifAt minimum, abcd is spelled "q".
Ah, perfect.
Quoted 4 lines
I don't particularly care for the 3 different opcodes. Perhaps we'd be better off with an inline predicate for when the deposit opcode is "valid"?
We still need to dispatch at tcg generation time which variant is valid. Or what do you have in mind?
Thanks,
Jan
Signature · 2 lines
Siemens AG, Corporate Technology, CT T DE IT 1 Corporate Competence Center Embedded Linux
Quoted 5 lines · Jan Kiszka
Quoted 3 lines
I don't particularly care for the 3 different opcodes. Perhaps we'd be better off with an inline predicate for when the deposit opcode is "valid"?
We still need to dispatch at tcg generation time which variant is valid. Or what do you have in mind?
Yes, but we'd know at tcg generation time that it *does* fit one of the few patterns you point out.
The predicate would be used in e.g. tcg_gen_deposit_i32 to select either INDEX_op_deposit_i32 or the and/shift/and/or fallback.
r~
Quoted 5 lines · Richard Henderson
Quoted 4 lines · Jan Kiszka
Quoted 3 lines
I don't particularly care for the 3 different opcodes. Perhaps we'd be better off with an inline predicate for when the deposit opcode is "valid"?
Quoted 7 lines
Quoted 1 line
We still need to dispatch at tcg generation time which variant is valid. Or what do you have in mind?
Yes, but we'd know at tcg generation time that it *does* fit one of the few patterns you point out.
The predicate would be used in e.g.
tcg_gen_deposit_i32to select eitherINDEX_op_deposit_i32or the and/shift/and/or fallback.
I think I'm slowly starting to understand:
#define TCG_TARGET_HAS_deposit_i32(ofs, len) \
(((ofs) == 0 && (len) == 8 && TCG_TARGET_HAS_deposit8l_i32) || \
...)defined by the i386 tcg target, right?
Jan
Quoted 14 lines · Jan Kiszka
Quoted 5 lines · Richard Henderson
Quoted 4 lines · Jan Kiszka
Quoted 3 lines
I don't particularly care for the 3 different opcodes. Perhaps we'd be better off with an inline predicate for when the deposit opcode is "valid"?
Quoted 7 lines
Quoted 1 line
We still need to dispatch at tcg generation time which variant is valid. Or what do you have in mind?
Yes, but we'd know at tcg generation time that it *does* fit one of the few patterns you point out.
The predicate would be used in e.g.
tcg_gen_deposit_i32to select eitherINDEX_op_deposit_i32or the and/shift/and/or fallback.
Quoted 7 lines
I think I'm slowly starting to understand:
#define TCG_TARGET_HAS_deposit_i32(ofs, len) \ (((ofs) == 0 && (len) == 8 && TCG_TARGET_HAS_deposit8l_i32) || \ ...)defined by the i386 tcg target, right?
Something like that. Except without the TCG_TARGET_HAS_deposit8l_i32.
r~
PATCH v2 1/1 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.
---
Changes in v2:
- introduce restricting predicates TCG_TARGET_deposit_i32/64_valid to decide if deposit support can be used
- express register constraints via new 'Q' symbol
tcg/i386/tcg-target.c | 24 ++++++++++++++++++++++++ tcg/i386/tcg-target.h | 9 +++++++-- tcg/tcg-op.h | 4 ++-- 3 files changed, 33 insertions(+), 4 deletions(-)
tcg/i386/tcg-target.c +24 -0
@@ -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
tcg/i386/tcg-target.h +7 -2
@@ -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 */
tcg/tcg-op.h +2 -2
@@ -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 ;
Signature · 1 line
1.7.3.4
Re: [Qemu-devel] [PATCH v2] tcg-i386: Introduce limited deposit support
Quoted 7 lines · Jan Kiszka
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.
Quoted 7 lines
Signed-off-by Jan Kiszka <[email protected]>---
Changes in v2:
- introduce restricting predicates TCG_TARGET_deposit_i32/64_valid to decide if deposit support can be used
- express register constraints via new 'Q' symbol
That's what I had in mind, yes.
The only thing that's missing now is a default version of
tcg/i386/tcg-target.h enum { · line 120
Quoted 4 lines
tcg/i386/tcg-target.h +4
-0+#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
These.
r~
Re: [Qemu-devel] [PATCH v2] tcg-i386: Introduce limited deposit support
Quoted 18 lines · Richard Henderson
Quoted 7 lines · Jan Kiszka
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.
Quoted 7 lines
Signed-off-by Jan Kiszka <[email protected]>---
Changes in v2:
- introduce restricting predicates TCG_TARGET_deposit_i32/64_valid to decide if deposit support can be used
- express register constraints via new 'Q' symbolThat's what I had in mind, yes.
Quoted 8 lines
The only thing that's missing now is a default version of
tcg/i386/tcg-target.h enum { · line 120
Quoted 4 lines
tcg/i386/tcg-target.h +4
-0+#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_validThese.
Interestingly, that didn't break the build here. Seems like gcc became too smart to report this.
Jan
Signature · 2 lines
Siemens AG, Corporate Technology, CT T DE IT 1 Corporate Competence Center Embedded Linux
PATCH v3 1/1 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.
---
Changes in v3:
- provide default TCG_TARGET_deposit_i32_valid - just in case
Changes in v2:
- introduce restricting predicates TCG_TARGET_deposit_i32/64_valid to decide if deposit support can be used
- express register constraints via new 'Q' symbol
tcg/i386/tcg-target.c | 24 ++++++++++++++++++++++++ tcg/i386/tcg-target.h | 9 +++++++-- tcg/tcg-op.h | 4 ++-- tcg/tcg.h | 7 +++++++ 4 files changed, 40 insertions(+), 4 deletions(-)
tcg/i386/tcg-target.c +24 -0
@@ -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
tcg/i386/tcg-target.h +7 -2
@@ -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 */
tcg/tcg-op.h +2 -2
@@ -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 ;
tcg/tcg.h +7 -0
@@ -71,6 +71,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) 0 +#endif +#ifndef TCG_TARGET_deposit_i64_valid +#define TCG_TARGET_deposit_i64_valid (ofs, len) 0 +#endif +/* Only one of DIV or DIV2 should be defined. */ #if defined(TCG_TARGET_HAS_div_i32)#define TCG_TARGET_HAS_div2_i32 0
Signature · 1 line
1.7.3.4
Re: [Qemu-devel] [PATCH v3] tcg-i386: Introduce limited deposit support
tcg/tcg.h typedef uint64_t TCGRegSet; · line 79
Quoted 6 lines · Jan Kiszka
tcg/tcg.h +6
-0+#ifndef TCG_TARGET_deposit_i32_valid +#define TCG_TARGET_deposit_i32_valid (ofs, len) 0 +#endif +#ifndef TCG_TARGET_deposit_i64_valid +#define TCG_TARGET_deposit_i64_valid (ofs, len) 0 +#endif
Err, no. The default is true. The targets that currently implement deposit at present can handle arbitrary inputs.
r~
PATCH v4 1/1 tcg-i386: Introduce limited deposit support
Quoted 10 lines · Richard Henderson
Review
Quoted 6 lines · Jan Kiszka
(quoted diff) +6
-0+#ifndef TCG_TARGET_deposit_i32_valid +#define TCG_TARGET_deposit_i32_valid(ofs, len) 0 +#endif +#ifndef TCG_TARGET_deposit_i64_valid +#define TCG_TARGET_deposit_i64_valid(ofs, len) 0 +#endifErr, no. The default is true. The targets that currently implement deposit at present can handle arbitrary inputs.
Grr, of course.
---
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.
---
Changes in v4:
- provide correct default TCG_TARGET_deposit_i32_valid
Changes in v3:
- provide default TCG_TARGET_deposit_i32_valid - just in case
Changes in v2:
- introduce restricting predicates TCG_TARGET_deposit_i32/64_valid to decide if deposit support can be used
- express register constraints via new 'Q' symbol
tcg/i386/tcg-target.c | 24 ++++++++++++++++++++++++ tcg/i386/tcg-target.h | 9 +++++++-- tcg/tcg-op.h | 4 ++-- tcg/tcg.h | 7 +++++++ 4 files changed, 40 insertions(+), 4 deletions(-)
tcg/i386/tcg-target.c +24 -0
@@ -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
tcg/i386/tcg-target.h +7 -2
@@ -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 */
tcg/tcg-op.h +2 -2
@@ -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 ;
tcg/tcg.h +7 -0
@@ -71,6 +71,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
Signature · 1 line
1.7.3.4
Re: [Qemu-devel] [PATCH v4] tcg-i386: Introduce limited deposit support
Quoted 21 lines · Jan Kiszka
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 <[email protected]>---
Changes in v4:
- provide correct defaultTCG_TARGET_deposit_i32_validChanges in v3:
- provide defaultTCG_TARGET_deposit_i32_valid- just in caseChanges in v2:
- introduce restricting predicates TCG_TARGET_deposit_i32/64_valid to decide if deposit support can be used
- express register constraints via new 'Q' symbol
Quoted 5 lines
tcg/i386/tcg-target.c | 24 ++++++++++++++++++++++++ tcg/i386/tcg-target.h | 9 +++++++-- tcg/tcg-op.h | 4 ++-- tcg/tcg.h | 7 +++++++ 4 files changed, 40 insertions(+), 4 deletions(-)
r~
Blue Swirl
AppliedRe: [Qemu-devel] [PATCH v4] tcg-i386: Introduce limited deposit support
In reply to Jan KiszkaThanks, applied.
Quoted 171 lines · Jan Kiszka
Quoted 10 lines · Richard Henderson
tcg/tcg.h typedef uint64_t TCGRegSet; · line 79
Quoted 6 lines · Jan Kiszka
tcg/tcg.h +6
-0+#ifndef TCG_TARGET_deposit_i32_valid +#define TCG_TARGET_deposit_i32_valid (ofs, len) 0 +#endif +#ifndef TCG_TARGET_deposit_i64_valid +#define TCG_TARGET_deposit_i64_valid (ofs, len) 0 +#endif Err, no. The default is true. The targets that currently implement deposit at present can handle arbitrary inputs.
Grr, of course.
---
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 <[email protected]>---
Changes in v4:
- provide correct defaultTCG_TARGET_deposit_i32_validChanges in v3:
- provide defaultTCG_TARGET_deposit_i32_valid- just in caseChanges in v2:
- introduce restricting predicates TCG_TARGET_deposit_i32/64_valid to decide if deposit support can be used
- express register constraints via new 'Q' symboltcg/i386/tcg-target.c | 24 ++++++++++++++++++++++++
tcg/i386/tcg-target.h| 9 +++++++--tcg/tcg-op.h| 4 ++--
tcg/tcg.h | 7 +++++++4 files changed, 40 insertions(+), 4 deletions(-)tcg/i386/tcg-target.c +4
-0@@ -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) {tcg/i386/tcg-target.c +16
-0@@ -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();
}tcg/i386/tcg-target.c +4
-0@@ -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 == 64tcg/i386/tcg-target.h +7
-2@@ -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 */tcg/tcg-op.h +2
-2@@ -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;tcg/tcg.h +7
-1@@ -71,6 +71,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 --1.7.3.4