diff mbox series

[2/9] tcg: Add INDEX_op_extract2_{i32,i64}

Message ID 20190307144126.31847-3-richard.henderson@linaro.org
State Superseded
Headers show
Series tcg: Add tcg_gen_extract2_{i32,i64} | expand

Commit Message

Richard Henderson March 7, 2019, 2:41 p.m. UTC
This will let backends implement the double-word shift operation.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

---
 tcg/aarch64/tcg-target.h |  2 ++
 tcg/arm/tcg-target.h     |  1 +
 tcg/i386/tcg-target.h    |  2 ++
 tcg/mips/tcg-target.h    |  2 ++
 tcg/ppc/tcg-target.h     |  2 ++
 tcg/riscv/tcg-target.h   |  2 ++
 tcg/s390/tcg-target.h    |  2 ++
 tcg/sparc/tcg-target.h   |  2 ++
 tcg/tcg-opc.h            |  2 ++
 tcg/tcg.h                |  1 +
 tcg/tci/tcg-target.h     |  2 ++
 tcg/optimize.c           | 10 ++++++++++
 tcg/tcg-op.c             |  4 ++++
 tcg/tcg.c                |  4 ++++
 tcg/README               |  5 +++++
 15 files changed, 43 insertions(+)

-- 
2.17.2

Comments

David Hildenbrand March 7, 2019, 3:19 p.m. UTC | #1
On 07.03.19 15:41, Richard Henderson wrote:
> This will let backends implement the double-word shift operation.

> 

> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

> ---

>  tcg/aarch64/tcg-target.h |  2 ++

>  tcg/arm/tcg-target.h     |  1 +

>  tcg/i386/tcg-target.h    |  2 ++

>  tcg/mips/tcg-target.h    |  2 ++

>  tcg/ppc/tcg-target.h     |  2 ++

>  tcg/riscv/tcg-target.h   |  2 ++

>  tcg/s390/tcg-target.h    |  2 ++

>  tcg/sparc/tcg-target.h   |  2 ++

>  tcg/tcg-opc.h            |  2 ++

>  tcg/tcg.h                |  1 +

>  tcg/tci/tcg-target.h     |  2 ++

>  tcg/optimize.c           | 10 ++++++++++

>  tcg/tcg-op.c             |  4 ++++

>  tcg/tcg.c                |  4 ++++

>  tcg/README               |  5 +++++

>  15 files changed, 43 insertions(+)

> 

> diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h

> index 2d93cf404e..6600a54a02 100644

> --- a/tcg/aarch64/tcg-target.h

> +++ b/tcg/aarch64/tcg-target.h

> @@ -77,6 +77,7 @@ typedef enum {

>  #define TCG_TARGET_HAS_deposit_i32      1

>  #define TCG_TARGET_HAS_extract_i32      1

>  #define TCG_TARGET_HAS_sextract_i32     1

> +#define TCG_TARGET_HAS_extract2_i32     0

>  #define TCG_TARGET_HAS_movcond_i32      1

>  #define TCG_TARGET_HAS_add2_i32         1

>  #define TCG_TARGET_HAS_sub2_i32         1

> @@ -113,6 +114,7 @@ typedef enum {

>  #define TCG_TARGET_HAS_deposit_i64      1

>  #define TCG_TARGET_HAS_extract_i64      1

>  #define TCG_TARGET_HAS_sextract_i64     1

> +#define TCG_TARGET_HAS_extract2_i64     0

>  #define TCG_TARGET_HAS_movcond_i64      1

>  #define TCG_TARGET_HAS_add2_i64         1

>  #define TCG_TARGET_HAS_sub2_i64         1

> diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h

> index 16172f73a3..4ee6c98958 100644

> --- a/tcg/arm/tcg-target.h

> +++ b/tcg/arm/tcg-target.h

> @@ -116,6 +116,7 @@ extern bool use_idiv_instructions;

>  #define TCG_TARGET_HAS_deposit_i32      use_armv7_instructions

>  #define TCG_TARGET_HAS_extract_i32      use_armv7_instructions

>  #define TCG_TARGET_HAS_sextract_i32     use_armv7_instructions

> +#define TCG_TARGET_HAS_extract2_i32     0

>  #define TCG_TARGET_HAS_movcond_i32      1

>  #define TCG_TARGET_HAS_mulu2_i32        1

>  #define TCG_TARGET_HAS_muls2_i32        1

> diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h

> index 7995fe3eab..2c58eaa9ed 100644

> --- a/tcg/i386/tcg-target.h

> +++ b/tcg/i386/tcg-target.h

> @@ -124,6 +124,7 @@ extern bool have_avx2;

>  #define TCG_TARGET_HAS_deposit_i32      1

>  #define TCG_TARGET_HAS_extract_i32      1

>  #define TCG_TARGET_HAS_sextract_i32     1

> +#define TCG_TARGET_HAS_extract2_i32     0

>  #define TCG_TARGET_HAS_movcond_i32      1

>  #define TCG_TARGET_HAS_add2_i32         1

>  #define TCG_TARGET_HAS_sub2_i32         1

> @@ -162,6 +163,7 @@ extern bool have_avx2;

>  #define TCG_TARGET_HAS_deposit_i64      1

>  #define TCG_TARGET_HAS_extract_i64      1

>  #define TCG_TARGET_HAS_sextract_i64     0

> +#define TCG_TARGET_HAS_extract2_i64     0

>  #define TCG_TARGET_HAS_movcond_i64      1

>  #define TCG_TARGET_HAS_add2_i64         1

>  #define TCG_TARGET_HAS_sub2_i64         1

> diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h

> index 5cb8672470..c6b091d849 100644

> --- a/tcg/mips/tcg-target.h

> +++ b/tcg/mips/tcg-target.h

> @@ -162,6 +162,7 @@ extern bool use_mips32r2_instructions;

>  #define TCG_TARGET_HAS_deposit_i32      use_mips32r2_instructions

>  #define TCG_TARGET_HAS_extract_i32      use_mips32r2_instructions

>  #define TCG_TARGET_HAS_sextract_i32     0

> +#define TCG_TARGET_HAS_extract2_i32     0

>  #define TCG_TARGET_HAS_ext8s_i32        use_mips32r2_instructions

>  #define TCG_TARGET_HAS_ext16s_i32       use_mips32r2_instructions

>  #define TCG_TARGET_HAS_rot_i32          use_mips32r2_instructions

> @@ -177,6 +178,7 @@ extern bool use_mips32r2_instructions;

>  #define TCG_TARGET_HAS_deposit_i64      use_mips32r2_instructions

>  #define TCG_TARGET_HAS_extract_i64      use_mips32r2_instructions

>  #define TCG_TARGET_HAS_sextract_i64     0

> +#define TCG_TARGET_HAS_extract2_i64     0

>  #define TCG_TARGET_HAS_ext8s_i64        use_mips32r2_instructions

>  #define TCG_TARGET_HAS_ext16s_i64       use_mips32r2_instructions

>  #define TCG_TARGET_HAS_rot_i64          use_mips32r2_instructions

> diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h

> index 52c1bb04b1..7627fb62d3 100644

> --- a/tcg/ppc/tcg-target.h

> +++ b/tcg/ppc/tcg-target.h

> @@ -77,6 +77,7 @@ extern bool have_isa_3_00;

>  #define TCG_TARGET_HAS_deposit_i32      1

>  #define TCG_TARGET_HAS_extract_i32      1

>  #define TCG_TARGET_HAS_sextract_i32     0

> +#define TCG_TARGET_HAS_extract2_i32     0

>  #define TCG_TARGET_HAS_movcond_i32      1

>  #define TCG_TARGET_HAS_mulu2_i32        0

>  #define TCG_TARGET_HAS_muls2_i32        0

> @@ -115,6 +116,7 @@ extern bool have_isa_3_00;

>  #define TCG_TARGET_HAS_deposit_i64      1

>  #define TCG_TARGET_HAS_extract_i64      1

>  #define TCG_TARGET_HAS_sextract_i64     0

> +#define TCG_TARGET_HAS_extract2_i64     0

>  #define TCG_TARGET_HAS_movcond_i64      1

>  #define TCG_TARGET_HAS_add2_i64         1

>  #define TCG_TARGET_HAS_sub2_i64         1

> diff --git a/tcg/riscv/tcg-target.h b/tcg/riscv/tcg-target.h

> index 60918cacb4..032439d806 100644

> --- a/tcg/riscv/tcg-target.h

> +++ b/tcg/riscv/tcg-target.h

> @@ -93,6 +93,7 @@ typedef enum {

>  #define TCG_TARGET_HAS_deposit_i32      0

>  #define TCG_TARGET_HAS_extract_i32      0

>  #define TCG_TARGET_HAS_sextract_i32     0

> +#define TCG_TARGET_HAS_extract2_i32     0

>  #define TCG_TARGET_HAS_add2_i32         1

>  #define TCG_TARGET_HAS_sub2_i32         1

>  #define TCG_TARGET_HAS_mulu2_i32        0

> @@ -128,6 +129,7 @@ typedef enum {

>  #define TCG_TARGET_HAS_deposit_i64      0

>  #define TCG_TARGET_HAS_extract_i64      0

>  #define TCG_TARGET_HAS_sextract_i64     0

> +#define TCG_TARGET_HAS_extract2_i64     0

>  #define TCG_TARGET_HAS_extrl_i64_i32    1

>  #define TCG_TARGET_HAS_extrh_i64_i32    1

>  #define TCG_TARGET_HAS_ext8s_i64        1

> diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h

> index 853ed6e7aa..07accabbd1 100644

> --- a/tcg/s390/tcg-target.h

> +++ b/tcg/s390/tcg-target.h

> @@ -85,6 +85,7 @@ extern uint64_t s390_facilities;

>  #define TCG_TARGET_HAS_deposit_i32    (s390_facilities & FACILITY_GEN_INST_EXT)

>  #define TCG_TARGET_HAS_extract_i32    (s390_facilities & FACILITY_GEN_INST_EXT)

>  #define TCG_TARGET_HAS_sextract_i32   0

> +#define TCG_TARGET_HAS_extract2_i32   0

>  #define TCG_TARGET_HAS_movcond_i32    1

>  #define TCG_TARGET_HAS_add2_i32       1

>  #define TCG_TARGET_HAS_sub2_i32       1

> @@ -121,6 +122,7 @@ extern uint64_t s390_facilities;

>  #define TCG_TARGET_HAS_deposit_i64    (s390_facilities & FACILITY_GEN_INST_EXT)

>  #define TCG_TARGET_HAS_extract_i64    (s390_facilities & FACILITY_GEN_INST_EXT)

>  #define TCG_TARGET_HAS_sextract_i64   0

> +#define TCG_TARGET_HAS_extract2_i64   0

>  #define TCG_TARGET_HAS_movcond_i64    1

>  #define TCG_TARGET_HAS_add2_i64       1

>  #define TCG_TARGET_HAS_sub2_i64       1

> diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h

> index a0ed2a3342..633841ebf2 100644

> --- a/tcg/sparc/tcg-target.h

> +++ b/tcg/sparc/tcg-target.h

> @@ -116,6 +116,7 @@ extern bool use_vis3_instructions;

>  #define TCG_TARGET_HAS_deposit_i32      0

>  #define TCG_TARGET_HAS_extract_i32      0

>  #define TCG_TARGET_HAS_sextract_i32     0

> +#define TCG_TARGET_HAS_extract2_i32     0

>  #define TCG_TARGET_HAS_movcond_i32      1

>  #define TCG_TARGET_HAS_add2_i32         1

>  #define TCG_TARGET_HAS_sub2_i32         1

> @@ -153,6 +154,7 @@ extern bool use_vis3_instructions;

>  #define TCG_TARGET_HAS_deposit_i64      0

>  #define TCG_TARGET_HAS_extract_i64      0

>  #define TCG_TARGET_HAS_sextract_i64     0

> +#define TCG_TARGET_HAS_extract2_i64     0

>  #define TCG_TARGET_HAS_movcond_i64      1

>  #define TCG_TARGET_HAS_add2_i64         1

>  #define TCG_TARGET_HAS_sub2_i64         1

> diff --git a/tcg/tcg-opc.h b/tcg/tcg-opc.h

> index 4e0238ad1a..1bad6e4208 100644

> --- a/tcg/tcg-opc.h

> +++ b/tcg/tcg-opc.h

> @@ -79,6 +79,7 @@ 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(extract_i32, 1, 1, 2, IMPL(TCG_TARGET_HAS_extract_i32))

>  DEF(sextract_i32, 1, 1, 2, IMPL(TCG_TARGET_HAS_sextract_i32))

> +DEF(extract2_i32, 1, 2, 1, IMPL(TCG_TARGET_HAS_extract2_i32))

>  

>  DEF(brcond_i32, 0, 2, 2, TCG_OPF_BB_END)

>  

> @@ -146,6 +147,7 @@ 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(extract_i64, 1, 1, 2, IMPL64 | IMPL(TCG_TARGET_HAS_extract_i64))

>  DEF(sextract_i64, 1, 1, 2, IMPL64 | IMPL(TCG_TARGET_HAS_sextract_i64))

> +DEF(extract2_i64, 1, 2, 1, IMPL64 | IMPL(TCG_TARGET_HAS_extract2_i64))

>  

>  /* size changing ops */

>  DEF(ext_i32_i64, 1, 1, 0, IMPL64)

> diff --git a/tcg/tcg.h b/tcg/tcg.h

> index 32b7cf3489..7b1c15b40b 100644

> --- a/tcg/tcg.h

> +++ b/tcg/tcg.h

> @@ -125,6 +125,7 @@ typedef uint64_t TCGRegSet;

>  #define TCG_TARGET_HAS_deposit_i64      0

>  #define TCG_TARGET_HAS_extract_i64      0

>  #define TCG_TARGET_HAS_sextract_i64     0

> +#define TCG_TARGET_HAS_extract2_i64     0

>  #define TCG_TARGET_HAS_movcond_i64      0

>  #define TCG_TARGET_HAS_add2_i64         0

>  #define TCG_TARGET_HAS_sub2_i64         0

> diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h

> index 086f34e69a..8b90ab71cb 100644

> --- a/tcg/tci/tcg-target.h

> +++ b/tcg/tci/tcg-target.h

> @@ -71,6 +71,7 @@

>  #define TCG_TARGET_HAS_deposit_i32      1

>  #define TCG_TARGET_HAS_extract_i32      0

>  #define TCG_TARGET_HAS_sextract_i32     0

> +#define TCG_TARGET_HAS_extract2_i32     0

>  #define TCG_TARGET_HAS_eqv_i32          0

>  #define TCG_TARGET_HAS_nand_i32         0

>  #define TCG_TARGET_HAS_nor_i32          0

> @@ -97,6 +98,7 @@

>  #define TCG_TARGET_HAS_deposit_i64      1

>  #define TCG_TARGET_HAS_extract_i64      0

>  #define TCG_TARGET_HAS_sextract_i64     0

> +#define TCG_TARGET_HAS_extract2_i64     0

>  #define TCG_TARGET_HAS_div_i64          0

>  #define TCG_TARGET_HAS_rem_i64          0

>  #define TCG_TARGET_HAS_ext8s_i64        1

> diff --git a/tcg/optimize.c b/tcg/optimize.c

> index 01e80c3e46..a5f50a0608 100644

> --- a/tcg/optimize.c

> +++ b/tcg/optimize.c

> @@ -1202,6 +1202,16 @@ void tcg_optimize(TCGContext *s)

>              }

>              goto do_default;

>  

> +        CASE_OP_32_64(extract2):

> +            if (arg_is_const(op->args[1]) && arg_is_const(op->args[2])) {

> +                TCGArg v1 = arg_info(op->args[1])->val;

> +                TCGArg v2 = arg_info(op->args[2])->val;

> +                tmp = (v1 >> op->args[3]) | (v2 << (64 - op->args[3]));> +                tcg_opt_gen_movi(s, op, op->args[0], tmp);

> +                break;

> +            }

> +            goto do_default;

> +

>          CASE_OP_32_64(setcond):

>              tmp = do_constant_folding_cond(opc, op->args[1],

>                                             op->args[2], op->args[3]);

> diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c

> index 7c56c92c8e..deacc63e3b 100644

> --- a/tcg/tcg-op.c

> +++ b/tcg/tcg-op.c

> @@ -823,6 +823,8 @@ void tcg_gen_extract2_i32(TCGv_i32 ret, TCGv_i32 al, TCGv_i32 ah,

>          tcg_gen_mov_i32(ret, ah);

>      } else if (al == ah) {

>          tcg_gen_rotri_i32(ret, al, ofs);

> +    } else if (TCG_TARGET_HAS_extract2_i32) {

> +        tcg_gen_op4i_i32(INDEX_op_extract2_i32, ret, al, ah, ofs);

>      } else {

>          TCGv_i32 t0 = tcg_temp_new_i32();

>          tcg_gen_shri_i32(t0, al, ofs);

> @@ -2333,6 +2335,8 @@ void tcg_gen_extract2_i64(TCGv_i64 ret, TCGv_i64 al, TCGv_i64 ah,

>          tcg_gen_mov_i64(ret, ah);

>      } else if (al == ah) {

>          tcg_gen_rotri_i64(ret, al, ofs);

> +    } else if (TCG_TARGET_HAS_extract2_i64) {

> +        tcg_gen_op4i_i64(INDEX_op_extract2_i64, ret, al, ah, ofs);

>      } else {

>          TCGv_i64 t0 = tcg_temp_new_i64();

>          tcg_gen_shri_i64(t0, al, ofs);

> diff --git a/tcg/tcg.c b/tcg/tcg.c

> index 9b2bf7f439..ade6050982 100644

> --- a/tcg/tcg.c

> +++ b/tcg/tcg.c

> @@ -1425,6 +1425,8 @@ bool tcg_op_supported(TCGOpcode op)

>          return TCG_TARGET_HAS_extract_i32;

>      case INDEX_op_sextract_i32:

>          return TCG_TARGET_HAS_sextract_i32;

> +    case INDEX_op_extract2_i32:

> +        return TCG_TARGET_HAS_extract2_i32;

>      case INDEX_op_add2_i32:

>          return TCG_TARGET_HAS_add2_i32;

>      case INDEX_op_sub2_i32:

> @@ -1522,6 +1524,8 @@ bool tcg_op_supported(TCGOpcode op)

>          return TCG_TARGET_HAS_extract_i64;

>      case INDEX_op_sextract_i64:

>          return TCG_TARGET_HAS_sextract_i64;

> +    case INDEX_op_extract2_i64:

> +        return TCG_TARGET_HAS_extract2_i64;

>      case INDEX_op_extrl_i64_i32:

>          return TCG_TARGET_HAS_extrl_i64_i32;

>      case INDEX_op_extrh_i64_i32:

> diff --git a/tcg/README b/tcg/README

> index 603f4df659..ddabf33017 100644

> --- a/tcg/README

> +++ b/tcg/README

> @@ -343,6 +343,11 @@ at bit 8.  This operation would be equivalent to

>  

>  (using an arithmetic right shift).

>  

> +* extract2_i64 dest, t1, t2, pos

> +

> +Extract a 64-bit quantity from the concatenation of t2:t1,

> +beginning at pos.

> +

>  * extrl_i64_i32 t0, t1

>  

>  For 64-bit hosts only, extract the low 32-bits of input T1 and place it

> 


Looks good to me

Reviewed-by: David Hildenbrand <david@redhat.com>


-- 

Thanks,

David / dhildenb
Philippe Mathieu-Daudé March 8, 2019, 11:28 p.m. UTC | #2
Hi Richard,

On 3/7/19 3:41 PM, Richard Henderson wrote:
> This will let backends implement the double-word shift operation.

> 

> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

> ---

>  tcg/aarch64/tcg-target.h |  2 ++

>  tcg/arm/tcg-target.h     |  1 +

>  tcg/i386/tcg-target.h    |  2 ++

>  tcg/mips/tcg-target.h    |  2 ++

>  tcg/ppc/tcg-target.h     |  2 ++

>  tcg/riscv/tcg-target.h   |  2 ++

>  tcg/s390/tcg-target.h    |  2 ++

>  tcg/sparc/tcg-target.h   |  2 ++

>  tcg/tcg-opc.h            |  2 ++

>  tcg/tcg.h                |  1 +

>  tcg/tci/tcg-target.h     |  2 ++

>  tcg/optimize.c           | 10 ++++++++++

>  tcg/tcg-op.c             |  4 ++++

>  tcg/tcg.c                |  4 ++++

>  tcg/README               |  5 +++++

>  15 files changed, 43 insertions(+)

> 

> diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h

> index 2d93cf404e..6600a54a02 100644

> --- a/tcg/aarch64/tcg-target.h

> +++ b/tcg/aarch64/tcg-target.h

> @@ -77,6 +77,7 @@ typedef enum {

>  #define TCG_TARGET_HAS_deposit_i32      1

>  #define TCG_TARGET_HAS_extract_i32      1

>  #define TCG_TARGET_HAS_sextract_i32     1

> +#define TCG_TARGET_HAS_extract2_i32     0

>  #define TCG_TARGET_HAS_movcond_i32      1

>  #define TCG_TARGET_HAS_add2_i32         1

>  #define TCG_TARGET_HAS_sub2_i32         1

> @@ -113,6 +114,7 @@ typedef enum {

>  #define TCG_TARGET_HAS_deposit_i64      1

>  #define TCG_TARGET_HAS_extract_i64      1

>  #define TCG_TARGET_HAS_sextract_i64     1

> +#define TCG_TARGET_HAS_extract2_i64     0

>  #define TCG_TARGET_HAS_movcond_i64      1

>  #define TCG_TARGET_HAS_add2_i64         1

>  #define TCG_TARGET_HAS_sub2_i64         1

> diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h

> index 16172f73a3..4ee6c98958 100644

> --- a/tcg/arm/tcg-target.h

> +++ b/tcg/arm/tcg-target.h

> @@ -116,6 +116,7 @@ extern bool use_idiv_instructions;

>  #define TCG_TARGET_HAS_deposit_i32      use_armv7_instructions

>  #define TCG_TARGET_HAS_extract_i32      use_armv7_instructions

>  #define TCG_TARGET_HAS_sextract_i32     use_armv7_instructions

> +#define TCG_TARGET_HAS_extract2_i32     0

>  #define TCG_TARGET_HAS_movcond_i32      1

>  #define TCG_TARGET_HAS_mulu2_i32        1

>  #define TCG_TARGET_HAS_muls2_i32        1

> diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h

> index 7995fe3eab..2c58eaa9ed 100644

> --- a/tcg/i386/tcg-target.h

> +++ b/tcg/i386/tcg-target.h

> @@ -124,6 +124,7 @@ extern bool have_avx2;

>  #define TCG_TARGET_HAS_deposit_i32      1

>  #define TCG_TARGET_HAS_extract_i32      1

>  #define TCG_TARGET_HAS_sextract_i32     1

> +#define TCG_TARGET_HAS_extract2_i32     0

>  #define TCG_TARGET_HAS_movcond_i32      1

>  #define TCG_TARGET_HAS_add2_i32         1

>  #define TCG_TARGET_HAS_sub2_i32         1

> @@ -162,6 +163,7 @@ extern bool have_avx2;

>  #define TCG_TARGET_HAS_deposit_i64      1

>  #define TCG_TARGET_HAS_extract_i64      1

>  #define TCG_TARGET_HAS_sextract_i64     0

> +#define TCG_TARGET_HAS_extract2_i64     0

>  #define TCG_TARGET_HAS_movcond_i64      1

>  #define TCG_TARGET_HAS_add2_i64         1

>  #define TCG_TARGET_HAS_sub2_i64         1

> diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h

> index 5cb8672470..c6b091d849 100644

> --- a/tcg/mips/tcg-target.h

> +++ b/tcg/mips/tcg-target.h

> @@ -162,6 +162,7 @@ extern bool use_mips32r2_instructions;

>  #define TCG_TARGET_HAS_deposit_i32      use_mips32r2_instructions

>  #define TCG_TARGET_HAS_extract_i32      use_mips32r2_instructions

>  #define TCG_TARGET_HAS_sextract_i32     0

> +#define TCG_TARGET_HAS_extract2_i32     0

>  #define TCG_TARGET_HAS_ext8s_i32        use_mips32r2_instructions

>  #define TCG_TARGET_HAS_ext16s_i32       use_mips32r2_instructions

>  #define TCG_TARGET_HAS_rot_i32          use_mips32r2_instructions

> @@ -177,6 +178,7 @@ extern bool use_mips32r2_instructions;

>  #define TCG_TARGET_HAS_deposit_i64      use_mips32r2_instructions

>  #define TCG_TARGET_HAS_extract_i64      use_mips32r2_instructions

>  #define TCG_TARGET_HAS_sextract_i64     0

> +#define TCG_TARGET_HAS_extract2_i64     0

>  #define TCG_TARGET_HAS_ext8s_i64        use_mips32r2_instructions

>  #define TCG_TARGET_HAS_ext16s_i64       use_mips32r2_instructions

>  #define TCG_TARGET_HAS_rot_i64          use_mips32r2_instructions

> diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h

> index 52c1bb04b1..7627fb62d3 100644

> --- a/tcg/ppc/tcg-target.h

> +++ b/tcg/ppc/tcg-target.h

> @@ -77,6 +77,7 @@ extern bool have_isa_3_00;

>  #define TCG_TARGET_HAS_deposit_i32      1

>  #define TCG_TARGET_HAS_extract_i32      1

>  #define TCG_TARGET_HAS_sextract_i32     0

> +#define TCG_TARGET_HAS_extract2_i32     0

>  #define TCG_TARGET_HAS_movcond_i32      1

>  #define TCG_TARGET_HAS_mulu2_i32        0

>  #define TCG_TARGET_HAS_muls2_i32        0

> @@ -115,6 +116,7 @@ extern bool have_isa_3_00;

>  #define TCG_TARGET_HAS_deposit_i64      1

>  #define TCG_TARGET_HAS_extract_i64      1

>  #define TCG_TARGET_HAS_sextract_i64     0

> +#define TCG_TARGET_HAS_extract2_i64     0

>  #define TCG_TARGET_HAS_movcond_i64      1

>  #define TCG_TARGET_HAS_add2_i64         1

>  #define TCG_TARGET_HAS_sub2_i64         1

> diff --git a/tcg/riscv/tcg-target.h b/tcg/riscv/tcg-target.h

> index 60918cacb4..032439d806 100644

> --- a/tcg/riscv/tcg-target.h

> +++ b/tcg/riscv/tcg-target.h

> @@ -93,6 +93,7 @@ typedef enum {

>  #define TCG_TARGET_HAS_deposit_i32      0

>  #define TCG_TARGET_HAS_extract_i32      0

>  #define TCG_TARGET_HAS_sextract_i32     0

> +#define TCG_TARGET_HAS_extract2_i32     0

>  #define TCG_TARGET_HAS_add2_i32         1

>  #define TCG_TARGET_HAS_sub2_i32         1

>  #define TCG_TARGET_HAS_mulu2_i32        0

> @@ -128,6 +129,7 @@ typedef enum {

>  #define TCG_TARGET_HAS_deposit_i64      0

>  #define TCG_TARGET_HAS_extract_i64      0

>  #define TCG_TARGET_HAS_sextract_i64     0

> +#define TCG_TARGET_HAS_extract2_i64     0

>  #define TCG_TARGET_HAS_extrl_i64_i32    1

>  #define TCG_TARGET_HAS_extrh_i64_i32    1

>  #define TCG_TARGET_HAS_ext8s_i64        1

> diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h

> index 853ed6e7aa..07accabbd1 100644

> --- a/tcg/s390/tcg-target.h

> +++ b/tcg/s390/tcg-target.h

> @@ -85,6 +85,7 @@ extern uint64_t s390_facilities;

>  #define TCG_TARGET_HAS_deposit_i32    (s390_facilities & FACILITY_GEN_INST_EXT)

>  #define TCG_TARGET_HAS_extract_i32    (s390_facilities & FACILITY_GEN_INST_EXT)

>  #define TCG_TARGET_HAS_sextract_i32   0

> +#define TCG_TARGET_HAS_extract2_i32   0

>  #define TCG_TARGET_HAS_movcond_i32    1

>  #define TCG_TARGET_HAS_add2_i32       1

>  #define TCG_TARGET_HAS_sub2_i32       1

> @@ -121,6 +122,7 @@ extern uint64_t s390_facilities;

>  #define TCG_TARGET_HAS_deposit_i64    (s390_facilities & FACILITY_GEN_INST_EXT)

>  #define TCG_TARGET_HAS_extract_i64    (s390_facilities & FACILITY_GEN_INST_EXT)

>  #define TCG_TARGET_HAS_sextract_i64   0

> +#define TCG_TARGET_HAS_extract2_i64   0

>  #define TCG_TARGET_HAS_movcond_i64    1

>  #define TCG_TARGET_HAS_add2_i64       1

>  #define TCG_TARGET_HAS_sub2_i64       1

> diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h

> index a0ed2a3342..633841ebf2 100644

> --- a/tcg/sparc/tcg-target.h

> +++ b/tcg/sparc/tcg-target.h

> @@ -116,6 +116,7 @@ extern bool use_vis3_instructions;

>  #define TCG_TARGET_HAS_deposit_i32      0

>  #define TCG_TARGET_HAS_extract_i32      0

>  #define TCG_TARGET_HAS_sextract_i32     0

> +#define TCG_TARGET_HAS_extract2_i32     0

>  #define TCG_TARGET_HAS_movcond_i32      1

>  #define TCG_TARGET_HAS_add2_i32         1

>  #define TCG_TARGET_HAS_sub2_i32         1

> @@ -153,6 +154,7 @@ extern bool use_vis3_instructions;

>  #define TCG_TARGET_HAS_deposit_i64      0

>  #define TCG_TARGET_HAS_extract_i64      0

>  #define TCG_TARGET_HAS_sextract_i64     0

> +#define TCG_TARGET_HAS_extract2_i64     0

>  #define TCG_TARGET_HAS_movcond_i64      1

>  #define TCG_TARGET_HAS_add2_i64         1

>  #define TCG_TARGET_HAS_sub2_i64         1

> diff --git a/tcg/tcg-opc.h b/tcg/tcg-opc.h

> index 4e0238ad1a..1bad6e4208 100644

> --- a/tcg/tcg-opc.h

> +++ b/tcg/tcg-opc.h

> @@ -79,6 +79,7 @@ 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(extract_i32, 1, 1, 2, IMPL(TCG_TARGET_HAS_extract_i32))

>  DEF(sextract_i32, 1, 1, 2, IMPL(TCG_TARGET_HAS_sextract_i32))

> +DEF(extract2_i32, 1, 2, 1, IMPL(TCG_TARGET_HAS_extract2_i32))

>  

>  DEF(brcond_i32, 0, 2, 2, TCG_OPF_BB_END)

>  

> @@ -146,6 +147,7 @@ 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(extract_i64, 1, 1, 2, IMPL64 | IMPL(TCG_TARGET_HAS_extract_i64))

>  DEF(sextract_i64, 1, 1, 2, IMPL64 | IMPL(TCG_TARGET_HAS_sextract_i64))

> +DEF(extract2_i64, 1, 2, 1, IMPL64 | IMPL(TCG_TARGET_HAS_extract2_i64))

>  

>  /* size changing ops */

>  DEF(ext_i32_i64, 1, 1, 0, IMPL64)

> diff --git a/tcg/tcg.h b/tcg/tcg.h

> index 32b7cf3489..7b1c15b40b 100644

> --- a/tcg/tcg.h

> +++ b/tcg/tcg.h

> @@ -125,6 +125,7 @@ typedef uint64_t TCGRegSet;

>  #define TCG_TARGET_HAS_deposit_i64      0

>  #define TCG_TARGET_HAS_extract_i64      0

>  #define TCG_TARGET_HAS_sextract_i64     0

> +#define TCG_TARGET_HAS_extract2_i64     0

>  #define TCG_TARGET_HAS_movcond_i64      0

>  #define TCG_TARGET_HAS_add2_i64         0

>  #define TCG_TARGET_HAS_sub2_i64         0

> diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h

> index 086f34e69a..8b90ab71cb 100644

> --- a/tcg/tci/tcg-target.h

> +++ b/tcg/tci/tcg-target.h

> @@ -71,6 +71,7 @@

>  #define TCG_TARGET_HAS_deposit_i32      1

>  #define TCG_TARGET_HAS_extract_i32      0

>  #define TCG_TARGET_HAS_sextract_i32     0

> +#define TCG_TARGET_HAS_extract2_i32     0

>  #define TCG_TARGET_HAS_eqv_i32          0

>  #define TCG_TARGET_HAS_nand_i32         0

>  #define TCG_TARGET_HAS_nor_i32          0

> @@ -97,6 +98,7 @@

>  #define TCG_TARGET_HAS_deposit_i64      1

>  #define TCG_TARGET_HAS_extract_i64      0

>  #define TCG_TARGET_HAS_sextract_i64     0

> +#define TCG_TARGET_HAS_extract2_i64     0

>  #define TCG_TARGET_HAS_div_i64          0

>  #define TCG_TARGET_HAS_rem_i64          0

>  #define TCG_TARGET_HAS_ext8s_i64        1

> diff --git a/tcg/optimize.c b/tcg/optimize.c

> index 01e80c3e46..a5f50a0608 100644

> --- a/tcg/optimize.c

> +++ b/tcg/optimize.c

> @@ -1202,6 +1202,16 @@ void tcg_optimize(TCGContext *s)

>              }

>              goto do_default;

>  

> +        CASE_OP_32_64(extract2):

> +            if (arg_is_const(op->args[1]) && arg_is_const(op->args[2])) {

> +                TCGArg v1 = arg_info(op->args[1])->val;

> +                TCGArg v2 = arg_info(op->args[2])->val;

> +                tmp = (v1 >> op->args[3]) | (v2 << (64 - op->args[3]));


Shouldn't this be:

tmp = (v1 >> op->args[3]) | (v2 << (TCG_TARGET_REG_BITS - op->args[3]));

?

> +                tcg_opt_gen_movi(s, op, op->args[0], tmp);

> +                break;

> +            }

> +            goto do_default;

> +

>          CASE_OP_32_64(setcond):

>              tmp = do_constant_folding_cond(opc, op->args[1],

>                                             op->args[2], op->args[3]);

> diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c

> index 7c56c92c8e..deacc63e3b 100644

> --- a/tcg/tcg-op.c

> +++ b/tcg/tcg-op.c

> @@ -823,6 +823,8 @@ void tcg_gen_extract2_i32(TCGv_i32 ret, TCGv_i32 al, TCGv_i32 ah,

>          tcg_gen_mov_i32(ret, ah);

>      } else if (al == ah) {

>          tcg_gen_rotri_i32(ret, al, ofs);

> +    } else if (TCG_TARGET_HAS_extract2_i32) {

> +        tcg_gen_op4i_i32(INDEX_op_extract2_i32, ret, al, ah, ofs);

>      } else {

>          TCGv_i32 t0 = tcg_temp_new_i32();

>          tcg_gen_shri_i32(t0, al, ofs);

> @@ -2333,6 +2335,8 @@ void tcg_gen_extract2_i64(TCGv_i64 ret, TCGv_i64 al, TCGv_i64 ah,

>          tcg_gen_mov_i64(ret, ah);

>      } else if (al == ah) {

>          tcg_gen_rotri_i64(ret, al, ofs);

> +    } else if (TCG_TARGET_HAS_extract2_i64) {

> +        tcg_gen_op4i_i64(INDEX_op_extract2_i64, ret, al, ah, ofs);

>      } else {

>          TCGv_i64 t0 = tcg_temp_new_i64();

>          tcg_gen_shri_i64(t0, al, ofs);

> diff --git a/tcg/tcg.c b/tcg/tcg.c

> index 9b2bf7f439..ade6050982 100644

> --- a/tcg/tcg.c

> +++ b/tcg/tcg.c

> @@ -1425,6 +1425,8 @@ bool tcg_op_supported(TCGOpcode op)

>          return TCG_TARGET_HAS_extract_i32;

>      case INDEX_op_sextract_i32:

>          return TCG_TARGET_HAS_sextract_i32;

> +    case INDEX_op_extract2_i32:

> +        return TCG_TARGET_HAS_extract2_i32;

>      case INDEX_op_add2_i32:

>          return TCG_TARGET_HAS_add2_i32;

>      case INDEX_op_sub2_i32:

> @@ -1522,6 +1524,8 @@ bool tcg_op_supported(TCGOpcode op)

>          return TCG_TARGET_HAS_extract_i64;

>      case INDEX_op_sextract_i64:

>          return TCG_TARGET_HAS_sextract_i64;

> +    case INDEX_op_extract2_i64:

> +        return TCG_TARGET_HAS_extract2_i64;

>      case INDEX_op_extrl_i64_i32:

>          return TCG_TARGET_HAS_extrl_i64_i32;

>      case INDEX_op_extrh_i64_i32:

> diff --git a/tcg/README b/tcg/README

> index 603f4df659..ddabf33017 100644

> --- a/tcg/README

> +++ b/tcg/README

> @@ -343,6 +343,11 @@ at bit 8.  This operation would be equivalent to

>  

>  (using an arithmetic right shift).

>  

> +* extract2_i64 dest, t1, t2, pos

> +

> +Extract a 64-bit quantity from the concatenation of t2:t1,

> +beginning at pos.

> +

>  * extrl_i64_i32 t0, t1

>  

>  For 64-bit hosts only, extract the low 32-bits of input T1 and place it

>
Richard Henderson March 9, 2019, 4:37 p.m. UTC | #3
On 3/8/19 3:28 PM, Philippe Mathieu-Daudé wrote:
>> +        CASE_OP_32_64(extract2):

>> +            if (arg_is_const(op->args[1]) && arg_is_const(op->args[2])) {

>> +                TCGArg v1 = arg_info(op->args[1])->val;

>> +                TCGArg v2 = arg_info(op->args[2])->val;

>> +                tmp = (v1 >> op->args[3]) | (v2 << (64 - op->args[3]));

> Shouldn't this be:

> 

> tmp = (v1 >> op->args[3]) | (v2 << (TCG_TARGET_REG_BITS - op->args[3]));


No, but there should be different constants for the two cases.

Thanks.


r~
Peter Maydell March 26, 2019, 1:35 p.m. UTC | #4
On Thu, 7 Mar 2019 at 14:47, Richard Henderson
<richard.henderson@linaro.org> wrote:
>

> This will let backends implement the double-word shift operation.

>

> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

> diff --git a/tcg/README b/tcg/README

> index 603f4df659..ddabf33017 100644

> --- a/tcg/README

> +++ b/tcg/README

> @@ -343,6 +343,11 @@ at bit 8.  This operation would be equivalent to

>

>  (using an arithmetic right shift).

>

> +* extract2_i64 dest, t1, t2, pos

> +

> +Extract a 64-bit quantity from the concatenation of t2:t1,

> +beginning at pos.

> +


I think we should document the valid values of 'pos'.
My guess is "0 <= pos <= 63".

thanks
-- PMM
Peter Maydell March 26, 2019, 1:38 p.m. UTC | #5
On Tue, 26 Mar 2019 at 13:35, Peter Maydell <peter.maydell@linaro.org> wrote:
>

> On Thu, 7 Mar 2019 at 14:47, Richard Henderson

> <richard.henderson@linaro.org> wrote:

> >

> > This will let backends implement the double-word shift operation.

> >

> > Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

> > diff --git a/tcg/README b/tcg/README

> > index 603f4df659..ddabf33017 100644

> > --- a/tcg/README

> > +++ b/tcg/README

> > @@ -343,6 +343,11 @@ at bit 8.  This operation would be equivalent to

> >

> >  (using an arithmetic right shift).

> >

> > +* extract2_i64 dest, t1, t2, pos

> > +

> > +Extract a 64-bit quantity from the concatenation of t2:t1,

> > +beginning at pos.

> > +

>

> I think we should document the valid values of 'pos'.

> My guess is "0 <= pos <= 63".


...also, patch 1 implements "extract2_i64" and "extract2_i32",
but this patch only documents one of those.

thanks
-- PMM
Richard Henderson April 3, 2019, 11:37 a.m. UTC | #6
On 3/26/19 8:35 PM, Peter Maydell wrote:
> On Thu, 7 Mar 2019 at 14:47, Richard Henderson

> <richard.henderson@linaro.org> wrote:

>>

>> This will let backends implement the double-word shift operation.

>>

>> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

>> diff --git a/tcg/README b/tcg/README

>> index 603f4df659..ddabf33017 100644

>> --- a/tcg/README

>> +++ b/tcg/README

>> @@ -343,6 +343,11 @@ at bit 8.  This operation would be equivalent to

>>

>>  (using an arithmetic right shift).

>>

>> +* extract2_i64 dest, t1, t2, pos

>> +

>> +Extract a 64-bit quantity from the concatenation of t2:t1,

>> +beginning at pos.

>> +

> 

> I think we should document the valid values of 'pos'.

> My guess is "0 <= pos <= 63".


How about

----
* extract2_i32/i64 dest, t1, t2, pos

For N = {32,64}, extract an N-bit quantity from the concatenation
of t2:t1, beginning at pos.  The tcg_gen_extract2_* expander allows
values 0 <= pos <= N, but will expand 0 and N with mov, so only
1 <= pos <= N-1 will be seen by the host tcg_out_op.
----

?


r~
Peter Maydell April 3, 2019, 11:56 a.m. UTC | #7
On Wed, 3 Apr 2019 at 18:37, Richard Henderson
<richard.henderson@linaro.org> wrote:
>

> On 3/26/19 8:35 PM, Peter Maydell wrote:

> > On Thu, 7 Mar 2019 at 14:47, Richard Henderson

> > <richard.henderson@linaro.org> wrote:

> >>

> >> This will let backends implement the double-word shift operation.

> >>

> >> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

> >> diff --git a/tcg/README b/tcg/README

> >> index 603f4df659..ddabf33017 100644

> >> --- a/tcg/README

> >> +++ b/tcg/README

> >> @@ -343,6 +343,11 @@ at bit 8.  This operation would be equivalent to

> >>

> >>  (using an arithmetic right shift).

> >>

> >> +* extract2_i64 dest, t1, t2, pos

> >> +

> >> +Extract a 64-bit quantity from the concatenation of t2:t1,

> >> +beginning at pos.

> >> +

> >

> > I think we should document the valid values of 'pos'.

> > My guess is "0 <= pos <= 63".

>

> How about

>

> ----

> * extract2_i32/i64 dest, t1, t2, pos

>

> For N = {32,64}, extract an N-bit quantity from the concatenation

> of t2:t1, beginning at pos.  The tcg_gen_extract2_* expander allows

> values 0 <= pos <= N, but will expand 0 and N with mov, so only

> 1 <= pos <= N-1 will be seen by the host tcg_out_op.


If I'm reading that correctly, it seems to be combining in one sentence
the behaviour of the TCG API exposed to the front-end (pos can be
between 0 and N inclusive) with a detail of the API that a backend
needs to care about (that it can assume it never sees 0 or N).
I think we should be more careful to keep those separate, because
a reader of this document is almost always going to care only about
one or the other, never both at the same time. Perhaps things that
apply only to the backend end of the interface should go in section 4
of tcg/README? At any rate I think they should at least be in
different sentences :-)

thanks
-- PMM
Richard Henderson April 13, 2019, 8:31 a.m. UTC | #8
On 4/3/19 1:56 AM, Peter Maydell wrote:
> On Wed, 3 Apr 2019 at 18:37, Richard Henderson

>> * extract2_i32/i64 dest, t1, t2, pos

>>

>> For N = {32,64}, extract an N-bit quantity from the concatenation

>> of t2:t1, beginning at pos.  The tcg_gen_extract2_* expander allows

>> values 0 <= pos <= N, but will expand 0 and N with mov, so only

>> 1 <= pos <= N-1 will be seen by the host tcg_out_op.

> 

> If I'm reading that correctly, it seems to be combining in one sentence

> the behaviour of the TCG API exposed to the front-end (pos can be

> between 0 and N inclusive) with a detail of the API that a backend

> needs to care about (that it can assume it never sees 0 or N).


You're not wrong.  ;-P

> I think we should be more careful to keep those separate, because

> a reader of this document is almost always going to care only about

> one or the other, never both at the same time. Perhaps things that

> apply only to the backend end of the interface should go in section 4

> of tcg/README?


Sadly, there's a lot of mix up on that count.

Indeed, the very next paragraph,

> * extrl_i64_i32 t0, t1

> 

> For 64-bit hosts only, extract the low 32-bits of input T1 and place it

> into 32-bit output T0.  Depending on the host, this may be a simple move,

> or may require additional canonicalization.


is entirely about the "section 4" opcode.  The "section 2" function,
tcg_gen_extrl_i64_i32, is expanded correctly for 32-bit hosts as a
simple move from the i32 "sub-temp" of the i64 temp.

Clearly the whole thing should be reorganized, but I'm not sure how best that
should be done.

> At any rate I think they should at least be in different sentences :-)


Now that I can do.  ;-)


r~
diff mbox series

Patch

diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h
index 2d93cf404e..6600a54a02 100644
--- a/tcg/aarch64/tcg-target.h
+++ b/tcg/aarch64/tcg-target.h
@@ -77,6 +77,7 @@  typedef enum {
 #define TCG_TARGET_HAS_deposit_i32      1
 #define TCG_TARGET_HAS_extract_i32      1
 #define TCG_TARGET_HAS_sextract_i32     1
+#define TCG_TARGET_HAS_extract2_i32     0
 #define TCG_TARGET_HAS_movcond_i32      1
 #define TCG_TARGET_HAS_add2_i32         1
 #define TCG_TARGET_HAS_sub2_i32         1
@@ -113,6 +114,7 @@  typedef enum {
 #define TCG_TARGET_HAS_deposit_i64      1
 #define TCG_TARGET_HAS_extract_i64      1
 #define TCG_TARGET_HAS_sextract_i64     1
+#define TCG_TARGET_HAS_extract2_i64     0
 #define TCG_TARGET_HAS_movcond_i64      1
 #define TCG_TARGET_HAS_add2_i64         1
 #define TCG_TARGET_HAS_sub2_i64         1
diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h
index 16172f73a3..4ee6c98958 100644
--- a/tcg/arm/tcg-target.h
+++ b/tcg/arm/tcg-target.h
@@ -116,6 +116,7 @@  extern bool use_idiv_instructions;
 #define TCG_TARGET_HAS_deposit_i32      use_armv7_instructions
 #define TCG_TARGET_HAS_extract_i32      use_armv7_instructions
 #define TCG_TARGET_HAS_sextract_i32     use_armv7_instructions
+#define TCG_TARGET_HAS_extract2_i32     0
 #define TCG_TARGET_HAS_movcond_i32      1
 #define TCG_TARGET_HAS_mulu2_i32        1
 #define TCG_TARGET_HAS_muls2_i32        1
diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h
index 7995fe3eab..2c58eaa9ed 100644
--- a/tcg/i386/tcg-target.h
+++ b/tcg/i386/tcg-target.h
@@ -124,6 +124,7 @@  extern bool have_avx2;
 #define TCG_TARGET_HAS_deposit_i32      1
 #define TCG_TARGET_HAS_extract_i32      1
 #define TCG_TARGET_HAS_sextract_i32     1
+#define TCG_TARGET_HAS_extract2_i32     0
 #define TCG_TARGET_HAS_movcond_i32      1
 #define TCG_TARGET_HAS_add2_i32         1
 #define TCG_TARGET_HAS_sub2_i32         1
@@ -162,6 +163,7 @@  extern bool have_avx2;
 #define TCG_TARGET_HAS_deposit_i64      1
 #define TCG_TARGET_HAS_extract_i64      1
 #define TCG_TARGET_HAS_sextract_i64     0
+#define TCG_TARGET_HAS_extract2_i64     0
 #define TCG_TARGET_HAS_movcond_i64      1
 #define TCG_TARGET_HAS_add2_i64         1
 #define TCG_TARGET_HAS_sub2_i64         1
diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h
index 5cb8672470..c6b091d849 100644
--- a/tcg/mips/tcg-target.h
+++ b/tcg/mips/tcg-target.h
@@ -162,6 +162,7 @@  extern bool use_mips32r2_instructions;
 #define TCG_TARGET_HAS_deposit_i32      use_mips32r2_instructions
 #define TCG_TARGET_HAS_extract_i32      use_mips32r2_instructions
 #define TCG_TARGET_HAS_sextract_i32     0
+#define TCG_TARGET_HAS_extract2_i32     0
 #define TCG_TARGET_HAS_ext8s_i32        use_mips32r2_instructions
 #define TCG_TARGET_HAS_ext16s_i32       use_mips32r2_instructions
 #define TCG_TARGET_HAS_rot_i32          use_mips32r2_instructions
@@ -177,6 +178,7 @@  extern bool use_mips32r2_instructions;
 #define TCG_TARGET_HAS_deposit_i64      use_mips32r2_instructions
 #define TCG_TARGET_HAS_extract_i64      use_mips32r2_instructions
 #define TCG_TARGET_HAS_sextract_i64     0
+#define TCG_TARGET_HAS_extract2_i64     0
 #define TCG_TARGET_HAS_ext8s_i64        use_mips32r2_instructions
 #define TCG_TARGET_HAS_ext16s_i64       use_mips32r2_instructions
 #define TCG_TARGET_HAS_rot_i64          use_mips32r2_instructions
diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h
index 52c1bb04b1..7627fb62d3 100644
--- a/tcg/ppc/tcg-target.h
+++ b/tcg/ppc/tcg-target.h
@@ -77,6 +77,7 @@  extern bool have_isa_3_00;
 #define TCG_TARGET_HAS_deposit_i32      1
 #define TCG_TARGET_HAS_extract_i32      1
 #define TCG_TARGET_HAS_sextract_i32     0
+#define TCG_TARGET_HAS_extract2_i32     0
 #define TCG_TARGET_HAS_movcond_i32      1
 #define TCG_TARGET_HAS_mulu2_i32        0
 #define TCG_TARGET_HAS_muls2_i32        0
@@ -115,6 +116,7 @@  extern bool have_isa_3_00;
 #define TCG_TARGET_HAS_deposit_i64      1
 #define TCG_TARGET_HAS_extract_i64      1
 #define TCG_TARGET_HAS_sextract_i64     0
+#define TCG_TARGET_HAS_extract2_i64     0
 #define TCG_TARGET_HAS_movcond_i64      1
 #define TCG_TARGET_HAS_add2_i64         1
 #define TCG_TARGET_HAS_sub2_i64         1
diff --git a/tcg/riscv/tcg-target.h b/tcg/riscv/tcg-target.h
index 60918cacb4..032439d806 100644
--- a/tcg/riscv/tcg-target.h
+++ b/tcg/riscv/tcg-target.h
@@ -93,6 +93,7 @@  typedef enum {
 #define TCG_TARGET_HAS_deposit_i32      0
 #define TCG_TARGET_HAS_extract_i32      0
 #define TCG_TARGET_HAS_sextract_i32     0
+#define TCG_TARGET_HAS_extract2_i32     0
 #define TCG_TARGET_HAS_add2_i32         1
 #define TCG_TARGET_HAS_sub2_i32         1
 #define TCG_TARGET_HAS_mulu2_i32        0
@@ -128,6 +129,7 @@  typedef enum {
 #define TCG_TARGET_HAS_deposit_i64      0
 #define TCG_TARGET_HAS_extract_i64      0
 #define TCG_TARGET_HAS_sextract_i64     0
+#define TCG_TARGET_HAS_extract2_i64     0
 #define TCG_TARGET_HAS_extrl_i64_i32    1
 #define TCG_TARGET_HAS_extrh_i64_i32    1
 #define TCG_TARGET_HAS_ext8s_i64        1
diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h
index 853ed6e7aa..07accabbd1 100644
--- a/tcg/s390/tcg-target.h
+++ b/tcg/s390/tcg-target.h
@@ -85,6 +85,7 @@  extern uint64_t s390_facilities;
 #define TCG_TARGET_HAS_deposit_i32    (s390_facilities & FACILITY_GEN_INST_EXT)
 #define TCG_TARGET_HAS_extract_i32    (s390_facilities & FACILITY_GEN_INST_EXT)
 #define TCG_TARGET_HAS_sextract_i32   0
+#define TCG_TARGET_HAS_extract2_i32   0
 #define TCG_TARGET_HAS_movcond_i32    1
 #define TCG_TARGET_HAS_add2_i32       1
 #define TCG_TARGET_HAS_sub2_i32       1
@@ -121,6 +122,7 @@  extern uint64_t s390_facilities;
 #define TCG_TARGET_HAS_deposit_i64    (s390_facilities & FACILITY_GEN_INST_EXT)
 #define TCG_TARGET_HAS_extract_i64    (s390_facilities & FACILITY_GEN_INST_EXT)
 #define TCG_TARGET_HAS_sextract_i64   0
+#define TCG_TARGET_HAS_extract2_i64   0
 #define TCG_TARGET_HAS_movcond_i64    1
 #define TCG_TARGET_HAS_add2_i64       1
 #define TCG_TARGET_HAS_sub2_i64       1
diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h
index a0ed2a3342..633841ebf2 100644
--- a/tcg/sparc/tcg-target.h
+++ b/tcg/sparc/tcg-target.h
@@ -116,6 +116,7 @@  extern bool use_vis3_instructions;
 #define TCG_TARGET_HAS_deposit_i32      0
 #define TCG_TARGET_HAS_extract_i32      0
 #define TCG_TARGET_HAS_sextract_i32     0
+#define TCG_TARGET_HAS_extract2_i32     0
 #define TCG_TARGET_HAS_movcond_i32      1
 #define TCG_TARGET_HAS_add2_i32         1
 #define TCG_TARGET_HAS_sub2_i32         1
@@ -153,6 +154,7 @@  extern bool use_vis3_instructions;
 #define TCG_TARGET_HAS_deposit_i64      0
 #define TCG_TARGET_HAS_extract_i64      0
 #define TCG_TARGET_HAS_sextract_i64     0
+#define TCG_TARGET_HAS_extract2_i64     0
 #define TCG_TARGET_HAS_movcond_i64      1
 #define TCG_TARGET_HAS_add2_i64         1
 #define TCG_TARGET_HAS_sub2_i64         1
diff --git a/tcg/tcg-opc.h b/tcg/tcg-opc.h
index 4e0238ad1a..1bad6e4208 100644
--- a/tcg/tcg-opc.h
+++ b/tcg/tcg-opc.h
@@ -79,6 +79,7 @@  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(extract_i32, 1, 1, 2, IMPL(TCG_TARGET_HAS_extract_i32))
 DEF(sextract_i32, 1, 1, 2, IMPL(TCG_TARGET_HAS_sextract_i32))
+DEF(extract2_i32, 1, 2, 1, IMPL(TCG_TARGET_HAS_extract2_i32))
 
 DEF(brcond_i32, 0, 2, 2, TCG_OPF_BB_END)
 
@@ -146,6 +147,7 @@  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(extract_i64, 1, 1, 2, IMPL64 | IMPL(TCG_TARGET_HAS_extract_i64))
 DEF(sextract_i64, 1, 1, 2, IMPL64 | IMPL(TCG_TARGET_HAS_sextract_i64))
+DEF(extract2_i64, 1, 2, 1, IMPL64 | IMPL(TCG_TARGET_HAS_extract2_i64))
 
 /* size changing ops */
 DEF(ext_i32_i64, 1, 1, 0, IMPL64)
diff --git a/tcg/tcg.h b/tcg/tcg.h
index 32b7cf3489..7b1c15b40b 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -125,6 +125,7 @@  typedef uint64_t TCGRegSet;
 #define TCG_TARGET_HAS_deposit_i64      0
 #define TCG_TARGET_HAS_extract_i64      0
 #define TCG_TARGET_HAS_sextract_i64     0
+#define TCG_TARGET_HAS_extract2_i64     0
 #define TCG_TARGET_HAS_movcond_i64      0
 #define TCG_TARGET_HAS_add2_i64         0
 #define TCG_TARGET_HAS_sub2_i64         0
diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h
index 086f34e69a..8b90ab71cb 100644
--- a/tcg/tci/tcg-target.h
+++ b/tcg/tci/tcg-target.h
@@ -71,6 +71,7 @@ 
 #define TCG_TARGET_HAS_deposit_i32      1
 #define TCG_TARGET_HAS_extract_i32      0
 #define TCG_TARGET_HAS_sextract_i32     0
+#define TCG_TARGET_HAS_extract2_i32     0
 #define TCG_TARGET_HAS_eqv_i32          0
 #define TCG_TARGET_HAS_nand_i32         0
 #define TCG_TARGET_HAS_nor_i32          0
@@ -97,6 +98,7 @@ 
 #define TCG_TARGET_HAS_deposit_i64      1
 #define TCG_TARGET_HAS_extract_i64      0
 #define TCG_TARGET_HAS_sextract_i64     0
+#define TCG_TARGET_HAS_extract2_i64     0
 #define TCG_TARGET_HAS_div_i64          0
 #define TCG_TARGET_HAS_rem_i64          0
 #define TCG_TARGET_HAS_ext8s_i64        1
diff --git a/tcg/optimize.c b/tcg/optimize.c
index 01e80c3e46..a5f50a0608 100644
--- a/tcg/optimize.c
+++ b/tcg/optimize.c
@@ -1202,6 +1202,16 @@  void tcg_optimize(TCGContext *s)
             }
             goto do_default;
 
+        CASE_OP_32_64(extract2):
+            if (arg_is_const(op->args[1]) && arg_is_const(op->args[2])) {
+                TCGArg v1 = arg_info(op->args[1])->val;
+                TCGArg v2 = arg_info(op->args[2])->val;
+                tmp = (v1 >> op->args[3]) | (v2 << (64 - op->args[3]));
+                tcg_opt_gen_movi(s, op, op->args[0], tmp);
+                break;
+            }
+            goto do_default;
+
         CASE_OP_32_64(setcond):
             tmp = do_constant_folding_cond(opc, op->args[1],
                                            op->args[2], op->args[3]);
diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c
index 7c56c92c8e..deacc63e3b 100644
--- a/tcg/tcg-op.c
+++ b/tcg/tcg-op.c
@@ -823,6 +823,8 @@  void tcg_gen_extract2_i32(TCGv_i32 ret, TCGv_i32 al, TCGv_i32 ah,
         tcg_gen_mov_i32(ret, ah);
     } else if (al == ah) {
         tcg_gen_rotri_i32(ret, al, ofs);
+    } else if (TCG_TARGET_HAS_extract2_i32) {
+        tcg_gen_op4i_i32(INDEX_op_extract2_i32, ret, al, ah, ofs);
     } else {
         TCGv_i32 t0 = tcg_temp_new_i32();
         tcg_gen_shri_i32(t0, al, ofs);
@@ -2333,6 +2335,8 @@  void tcg_gen_extract2_i64(TCGv_i64 ret, TCGv_i64 al, TCGv_i64 ah,
         tcg_gen_mov_i64(ret, ah);
     } else if (al == ah) {
         tcg_gen_rotri_i64(ret, al, ofs);
+    } else if (TCG_TARGET_HAS_extract2_i64) {
+        tcg_gen_op4i_i64(INDEX_op_extract2_i64, ret, al, ah, ofs);
     } else {
         TCGv_i64 t0 = tcg_temp_new_i64();
         tcg_gen_shri_i64(t0, al, ofs);
diff --git a/tcg/tcg.c b/tcg/tcg.c
index 9b2bf7f439..ade6050982 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -1425,6 +1425,8 @@  bool tcg_op_supported(TCGOpcode op)
         return TCG_TARGET_HAS_extract_i32;
     case INDEX_op_sextract_i32:
         return TCG_TARGET_HAS_sextract_i32;
+    case INDEX_op_extract2_i32:
+        return TCG_TARGET_HAS_extract2_i32;
     case INDEX_op_add2_i32:
         return TCG_TARGET_HAS_add2_i32;
     case INDEX_op_sub2_i32:
@@ -1522,6 +1524,8 @@  bool tcg_op_supported(TCGOpcode op)
         return TCG_TARGET_HAS_extract_i64;
     case INDEX_op_sextract_i64:
         return TCG_TARGET_HAS_sextract_i64;
+    case INDEX_op_extract2_i64:
+        return TCG_TARGET_HAS_extract2_i64;
     case INDEX_op_extrl_i64_i32:
         return TCG_TARGET_HAS_extrl_i64_i32;
     case INDEX_op_extrh_i64_i32:
diff --git a/tcg/README b/tcg/README
index 603f4df659..ddabf33017 100644
--- a/tcg/README
+++ b/tcg/README
@@ -343,6 +343,11 @@  at bit 8.  This operation would be equivalent to
 
 (using an arithmetic right shift).
 
+* extract2_i64 dest, t1, t2, pos
+
+Extract a 64-bit quantity from the concatenation of t2:t1,
+beginning at pos.
+
 * extrl_i64_i32 t0, t1
 
 For 64-bit hosts only, extract the low 32-bits of input T1 and place it