extract and deposit_z are similar operations, only differing in that extract shifts the operand right and deposit_z shifts it left. Like extract, it is possible to implement deposit_z as either AND+SHL or SHL+SHR. Use tcg_op_imm_match to check whether the processor supports the immediate that is needed for the mask, and if not fall back to two shifts.
Signed-off-by: Paolo Bonzini <[email protected]> --- tcg/tcg-op.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index ccf66382623..e7d6702f9c4 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -960,8 +960,18 @@ void tcg_gen_deposit_z_i32(TCGv_i32 ret, TCGv_i32 arg, tcg_gen_extract_i32(ret, ret, 0, ofs + len); return; } - tcg_gen_andi_i32(ret, arg, (1u << len) - 1); - tcg_gen_shli_i32(ret, ret, ofs); + /* + * Use TCG_TARGET_extract_valid to check for 8- and 16-bit extension + * opcodes, which tcg_gen_andi_i32 can produce. + */ + if (TCG_TARGET_extract_valid(TCG_TYPE_I32, 0, len) || + tcg_op_imm_match(INDEX_op_and, TCG_TYPE_I32, (1u << len) - 1)) { + tcg_gen_andi_i32(ret, arg, (1u << len) - 1); + tcg_gen_shli_i32(ret, ret, ofs); + } else { + tcg_gen_shli_i32(ret, arg, 32 - len); + tcg_gen_shri_i32(ret, ret, 32 - len - ofs); + } } } @@ -2628,8 +2638,18 @@ void tcg_gen_deposit_z_i64(TCGv_i64 ret, TCGv_i64 arg, tcg_gen_extract_i64(ret, ret, 0, ofs + len); return; } - tcg_gen_andi_i64(ret, arg, (1ull << len) - 1); - tcg_gen_shli_i64(ret, ret, ofs); + /* + * Use TCG_TARGET_extract_valid to check for 8-, 16- and 32-bit extension + * opcodes, which tcg_gen_andi_i64 can produce. + */ + if (TCG_TARGET_extract_valid(TCG_TYPE_I64, 0, len) || + tcg_op_imm_match(INDEX_op_and, TCG_TYPE_I64, (1ull << len) - 1)) { + tcg_gen_andi_i64(ret, arg, (1ull << len) - 1); + tcg_gen_shli_i64(ret, ret, ofs); + } else { + tcg_gen_shli_i64(ret, arg, 64 - len); + tcg_gen_shri_i64(ret, ret, 64 - len - ofs); + } } } -- 2.52.0
