[PATCH 07/11] tcg: Add revbit{32,64} opcodes
Richard Henderson <[email protected]> Thu, 30 Jul 2026 17:04:59 -0700
| Newsgroups | org.nongnu.qemu-arm,org.nongnu.qemu-devel |
|---|---|
| Message-ID | <[email protected]> |
Add the plumbing, but not yet implemented for any host. Signed-off-by: Richard Henderson <[email protected]> --- include/tcg/tcg-opc.h | 2 ++ tcg/tcg-op.c | 43 +++++++++++++++++++++++--------- tcg/tcg.c | 6 +++++ docs/devel/tcg-ops.rst | 11 ++++++++ tcg/aarch64/tcg-target.c.inc | 8 ++++++ tcg/loongarch64/tcg-target.c.inc | 8 ++++++ tcg/ppc64/tcg-target.c.inc | 8 ++++++ tcg/riscv64/tcg-target.c.inc | 8 ++++++ tcg/s390x/tcg-target.c.inc | 8 ++++++ tcg/sparc64/tcg-target.c.inc | 8 ++++++ tcg/tci/tcg-target.c.inc | 8 ++++++ tcg/x86_64/tcg-target.c.inc | 8 ++++++ 12 files changed, 114 insertions(+), 12 deletions(-) diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 61f1c28858..ca2077733e 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -79,6 +79,8 @@ DEF(or, 1, 2, 0, TCG_OPF_INT) DEF(orc, 1, 2, 0, TCG_OPF_INT) DEF(rems, 1, 2, 0, TCG_OPF_INT) DEF(remu, 1, 2, 0, TCG_OPF_INT) +DEF(revbit32, 1, 1, 1, TCG_OPF_INT) +DEF(revbit64, 1, 1, 1, TCG_OPF_INT) DEF(rotl, 1, 2, 0, TCG_OPF_INT) DEF(rotr, 1, 2, 0, TCG_OPF_INT) DEF(sar, 1, 2, 0, TCG_OPF_INT) diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 02fb3504b1..04d5e15167 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1262,10 +1262,14 @@ static void gen_bitswap_i32(TCGv_i32 ret, TCGv_i32 arg, uint32_t mask) void tcg_gen_revbit32_i32(TCGv_i32 ret, TCGv_i32 arg) { - gen_bitswap_i32(ret, arg, 0x55555555u); - gen_bitswap_i32(ret, ret, 0x33333333u); - gen_bitswap_i32(ret, ret, 0x0f0f0f0fu); - tcg_gen_bswap32_i32(ret, ret); + if (tcg_op_supported(INDEX_op_revbit32, TCG_TYPE_I32, 0)) { + tcg_gen_op3i_i32(INDEX_op_revbit32, ret, arg, 0); + } else { + gen_bitswap_i32(ret, arg, 0x55555555u); + gen_bitswap_i32(ret, ret, 0x33333333u); + gen_bitswap_i32(ret, ret, 0x0f0f0f0fu); + tcg_gen_bswap32_i32(ret, ret); + } } void tcg_gen_smin_i32(TCGv_i32 ret, TCGv_i32 a, TCGv_i32 b) @@ -1914,18 +1918,33 @@ void tcg_gen_revbit32_i64(TCGv_i64 ret, TCGv_i64 arg, int flags) /* Only one extension flag may be present. */ tcg_debug_assert(!(flags & TCG_BSWAP_OS) || !(flags & TCG_BSWAP_OZ)); - gen_bitswap_i64(ret, arg, 0x55555555ull); - gen_bitswap_i64(ret, ret, 0x33333333ull); - gen_bitswap_i64(ret, ret, 0x0f0f0f0full); - tcg_gen_bswap32_i64(ret, ret, flags | TCG_BSWAP_IZ); + if (tcg_op_supported(INDEX_op_revbit32, TCG_TYPE_I64, 0)) { + tcg_gen_op3i_i64(INDEX_op_revbit32, ret, arg, flags); + } else if (tcg_op_supported(INDEX_op_revbit64, TCG_TYPE_I64, 0)) { + tcg_gen_op3i_i64(INDEX_op_revbit64, ret, arg, 0); + if (flags & TCG_BSWAP_OS) { + tcg_gen_sari_i64(ret, ret, 32); + } else { + tcg_gen_shri_i64(ret, ret, 32); + } + } else { + gen_bitswap_i64(ret, arg, 0x55555555ull); + gen_bitswap_i64(ret, ret, 0x33333333ull); + gen_bitswap_i64(ret, ret, 0x0f0f0f0full); + tcg_gen_bswap32_i64(ret, ret, flags | TCG_BSWAP_IZ); + } } void tcg_gen_revbit64_i64(TCGv_i64 ret, TCGv_i64 arg) { - gen_bitswap_i64(ret, arg, 0x5555555555555555ull); - gen_bitswap_i64(ret, ret, 0x3333333333333333ull); - gen_bitswap_i64(ret, ret, 0x0f0f0f0f0f0f0f0full); - tcg_gen_bswap64_i64(ret, ret); + if (tcg_op_supported(INDEX_op_revbit64, TCG_TYPE_I64, 0)) { + tcg_gen_op3i_i64(INDEX_op_revbit64, ret, arg, 0); + } else { + gen_bitswap_i64(ret, arg, 0x5555555555555555ull); + gen_bitswap_i64(ret, ret, 0x3333333333333333ull); + gen_bitswap_i64(ret, ret, 0x0f0f0f0f0f0f0f0full); + tcg_gen_bswap64_i64(ret, ret); + } } void tcg_gen_not_i64(TCGv_i64 ret, TCGv_i64 arg) diff --git a/tcg/tcg.c b/tcg/tcg.c index e023ee8b9a..c2eb591f86 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1203,6 +1203,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_qemu_st2, TCGOutOpQemuLdSt2, outop_qemu_st2), OUTOP(INDEX_op_rems, TCGOutOpBinary, outop_rems), OUTOP(INDEX_op_remu, TCGOutOpBinary, outop_remu), + OUTOP(INDEX_op_revbit32, TCGOutOpBswap, outop_revbit32), OUTOP(INDEX_op_rotl, TCGOutOpBinary, outop_rotl), OUTOP(INDEX_op_rotr, TCGOutOpBinary, outop_rotr), OUTOP(INDEX_op_sar, TCGOutOpBinary, outop_sar), @@ -1230,6 +1231,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_extrh_i64_i32, TCGOutOpUnary, outop_extrh_i64_i32), OUTOP(INDEX_op_ld32u, TCGOutOpLoad, outop_ld32u), OUTOP(INDEX_op_ld32s, TCGOutOpLoad, outop_ld32s), + OUTOP(INDEX_op_revbit64, TCGOutOpUnary, outop_revbit64), OUTOP(INDEX_op_st32, TCGOutOpStore, outop_st), }; @@ -2944,6 +2946,8 @@ void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs) case INDEX_op_bswap16: case INDEX_op_bswap32: case INDEX_op_bswap64: + case INDEX_op_revbit32: + case INDEX_op_revbit64: { TCGArg flags = op->args[k]; const char *name = NULL; @@ -5575,6 +5579,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_ctpop: case INDEX_op_neg: case INDEX_op_not: + case INDEX_op_revbit64: { const TCGOutOpUnary *out = container_of(all_outop[op->opc], TCGOutOpUnary, base); @@ -5587,6 +5592,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_bswap16: case INDEX_op_bswap32: + case INDEX_op_revbit32: { const TCGOutOpBswap *out = container_of(all_outop[op->opc], TCGOutOpBswap, base); diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index 92ef127c80..1b3a2618b6 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -495,6 +495,17 @@ Misc into 32-bit output *t0*. Depending on the host, this may be a simple shift, or may require additional canonicalization. + * - revbit32 *t0*, *t1*, *flags* + + - | 32 bit bit reverse. The flags are the same as for bswap32. + On TCG_TYPE_I32, the flags should be zero. + + * - revbit64 *t0*, *t1*, *flags* + + - | 64 bit bit reverse. The flags are ignored, but still present + for consistency with the other revbit opcodes. For future + compatibility, the flags should be zero. + Conditional moves ----------------- diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index cc9c2a5158..aa2c4e42ed 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2652,6 +2652,14 @@ static const TCGOutOpUnary outop_bswap64 = { .out_rr = tgen_bswap64, }; +static const TCGOutOpBswap outop_revbit32 = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpUnary outop_revbit64 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tgen_sub(s, type, a0, TCG_REG_XZR, a1); diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 182dcfd5eb..a5cd3c3b1e 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1866,6 +1866,14 @@ static const TCGOutOpUnary outop_bswap64 = { .out_rr = tgen_bswap64, }; +static const TCGOutOpBswap outop_revbit32 = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpUnary outop_revbit64 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tgen_sub(s, type, a0, TCG_REG_ZERO, a1); diff --git a/tcg/ppc64/tcg-target.c.inc b/tcg/ppc64/tcg-target.c.inc index b54afa0b6d..a9a41ebd4f 100644 --- a/tcg/ppc64/tcg-target.c.inc +++ b/tcg/ppc64/tcg-target.c.inc @@ -3421,6 +3421,14 @@ static const TCGOutOpUnary outop_bswap64 = { .out_rr = tgen_bswap64, }; +static const TCGOutOpBswap outop_revbit32 = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpUnary outop_revbit64 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tcg_out32(s, NEG | RT(a0) | RA(a1)); diff --git a/tcg/riscv64/tcg-target.c.inc b/tcg/riscv64/tcg-target.c.inc index 76dd4fca97..4ebbe24774 100644 --- a/tcg/riscv64/tcg-target.c.inc +++ b/tcg/riscv64/tcg-target.c.inc @@ -2469,6 +2469,14 @@ static const TCGOutOpUnary outop_bswap64 = { .out_rr = tgen_bswap64, }; +static const TCGOutOpBswap outop_revbit32 = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpUnary outop_revbit64 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tgen_sub(s, type, a0, TCG_REG_ZERO, a1); diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 84a9e73a46..10b9dcb0cf 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -3020,6 +3020,14 @@ static const TCGOutOpUnary outop_bswap64 = { .out_rr = tgen_bswap64, }; +static const TCGOutOpBswap outop_revbit32 = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpUnary outop_revbit64 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { if (type == TCG_TYPE_I32) { diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 5e5c3f1cda..d22c1bd566 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1947,6 +1947,14 @@ static const TCGOutOpUnary outop_bswap64 = { .base.static_constraint = C_NotImplemented, }; +static const TCGOutOpBswap outop_revbit32 = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpUnary outop_revbit64 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tgen_sub(s, type, a0, TCG_REG_G0, a1); diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 1b22c70616..e8b82a0c85 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -959,6 +959,14 @@ static const TCGOutOpUnary outop_bswap64 = { .out_rr = tgen_bswap64, }; +static const TCGOutOpBswap outop_revbit32 = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpUnary outop_revbit64 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tcg_out_op_rr(s, INDEX_op_neg, a0, a1); diff --git a/tcg/x86_64/tcg-target.c.inc b/tcg/x86_64/tcg-target.c.inc index 1fc45e4ec6..70fec08c4c 100644 --- a/tcg/x86_64/tcg-target.c.inc +++ b/tcg/x86_64/tcg-target.c.inc @@ -1290,6 +1290,14 @@ static inline void tcg_out_bswap64(TCGContext *s, int reg) tcg_out_opc(s, OPC_BSWAP + P_REXW + LOWREGMASK(reg), 0, reg, 0); } +static const TCGOutOpBswap outop_revbit32 = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpUnary outop_revbit64 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_arithi(TCGContext *s, int c, int r0, tcg_target_long val, int cf) { -- 2.43.0