@samitouri / QOSamiQemu / commits / db1c58d777

tcg: Add revbit{8,32,64} opcodes

Add the plumbing, but not yet implemented for any host. Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

Richard Henderson committed Jul 30, 2026 at 15:35 UTC db1c58d777088b4c0de124c7b4d21d7b7d3adbab
12 files changed +174 -14
docs/devel/tcg-ops.rst
+16
@@ -495,6 +495,22 @@ Misc
495 into 32-bit output *t0*. Depending on the host, this may be a simple shift,
496 or may require additional canonicalization.
497
498 + * - revbit8 *dest*, *t1*
499 +
500 + - | Reverse the 8 bits within each byte of input *t1* with
501 + | output in *dest*; the byte order is unchanged.
502 +
503 + * - revbit32 *dest*, *t1*, *flags*
504 +
505 + - | Reverse the 32 bits of the lower 32 bits of input *t1*
506 + | with output in *dest*. On TCG_TYPE_I64, *flags* control
507 + | any required sign or zero extension of the result in
508 + | the same way as for bswap32.
509 + | On TCG_TYPE_I32, *flags* should be zero.
510 +
511 + * - revbit64 *dest*, *t1*
512 +
513 + - | Reverse the 64 bits of input *t1* with output in *dest*.
514
515 Conditional moves
516 -----------------
include/tcg/tcg-opc.h
+3
@@ -79,6 +79,9 @@ DEF(or, 1, 2, 0, TCG_OPF_INT)
79 DEF(orc, 1, 2, 0, TCG_OPF_INT)
80 DEF(rems, 1, 2, 0, TCG_OPF_INT)
81 DEF(remu, 1, 2, 0, TCG_OPF_INT)
82 +DEF(revbit8, 1, 1, 0, TCG_OPF_INT)
83 +DEF(revbit32, 1, 1, 1, TCG_OPF_INT)
84 +DEF(revbit64, 1, 1, 0, TCG_OPF_INT)
85 DEF(rotl, 1, 2, 0, TCG_OPF_INT)
86 DEF(rotr, 1, 2, 0, TCG_OPF_INT)
87 DEF(sar, 1, 2, 0, TCG_OPF_INT)
tcg/aarch64/tcg-target.c.inc
+12
@@ -2652,6 +2652,18 @@ static const TCGOutOpUnary outop_bswap64 = {
2652 .out_rr = tgen_bswap64,
2653 };
2654
2655 +static const TCGOutOpUnary outop_revbit8 = {
2656 + .base.static_constraint = C_NotImplemented,
2657 +};
2658 +
2659 +static const TCGOutOpBswap outop_revbit32 = {
2660 + .base.static_constraint = C_NotImplemented,
2661 +};
2662 +
2663 +static const TCGOutOpUnary outop_revbit64 = {
2664 + .base.static_constraint = C_NotImplemented,
2665 +};
2666 +
2667 static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1)
2668 {
2669 tgen_sub(s, type, a0, TCG_REG_XZR, a1);
tcg/loongarch64/tcg-target.c.inc
+12
@@ -1866,6 +1866,18 @@ static const TCGOutOpUnary outop_bswap64 = {
1866 .out_rr = tgen_bswap64,
1867 };
1868
1869 +static const TCGOutOpUnary outop_revbit8 = {
1870 + .base.static_constraint = C_NotImplemented,
1871 +};
1872 +
1873 +static const TCGOutOpBswap outop_revbit32 = {
1874 + .base.static_constraint = C_NotImplemented,
1875 +};
1876 +
1877 +static const TCGOutOpUnary outop_revbit64 = {
1878 + .base.static_constraint = C_NotImplemented,
1879 +};
1880 +
1881 static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1)
1882 {
1883 tgen_sub(s, type, a0, TCG_REG_ZERO, a1);
tcg/ppc64/tcg-target.c.inc
+12
@@ -3421,6 +3421,18 @@ static const TCGOutOpUnary outop_bswap64 = {
3421 .out_rr = tgen_bswap64,
3422 };
3423
3424 +static const TCGOutOpUnary outop_revbit8 = {
3425 + .base.static_constraint = C_NotImplemented,
3426 +};
3427 +
3428 +static const TCGOutOpBswap outop_revbit32 = {
3429 + .base.static_constraint = C_NotImplemented,
3430 +};
3431 +
3432 +static const TCGOutOpUnary outop_revbit64 = {
3433 + .base.static_constraint = C_NotImplemented,
3434 +};
3435 +
3436 static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1)
3437 {
3438 tcg_out32(s, NEG | RT(a0) | RA(a1));
tcg/riscv64/tcg-target.c.inc
+12
@@ -2469,6 +2469,18 @@ static const TCGOutOpUnary outop_bswap64 = {
2469 .out_rr = tgen_bswap64,
2470 };
2471
2472 +static const TCGOutOpUnary outop_revbit8 = {
2473 + .base.static_constraint = C_NotImplemented,
2474 +};
2475 +
2476 +static const TCGOutOpBswap outop_revbit32 = {
2477 + .base.static_constraint = C_NotImplemented,
2478 +};
2479 +
2480 +static const TCGOutOpUnary outop_revbit64 = {
2481 + .base.static_constraint = C_NotImplemented,
2482 +};
2483 +
2484 static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1)
2485 {
2486 tgen_sub(s, type, a0, TCG_REG_ZERO, a1);
tcg/s390x/tcg-target.c.inc
+12
@@ -3020,6 +3020,18 @@ static const TCGOutOpUnary outop_bswap64 = {
3020 .out_rr = tgen_bswap64,
3021 };
3022
3023 +static const TCGOutOpUnary outop_revbit8 = {
3024 + .base.static_constraint = C_NotImplemented,
3025 +};
3026 +
3027 +static const TCGOutOpBswap outop_revbit32 = {
3028 + .base.static_constraint = C_NotImplemented,
3029 +};
3030 +
3031 +static const TCGOutOpUnary outop_revbit64 = {
3032 + .base.static_constraint = C_NotImplemented,
3033 +};
3034 +
3035 static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1)
3036 {
3037 if (type == TCG_TYPE_I32) {
tcg/sparc64/tcg-target.c.inc
+12
@@ -1947,6 +1947,18 @@ static const TCGOutOpUnary outop_bswap64 = {
1947 .base.static_constraint = C_NotImplemented,
1948 };
1949
1950 +static const TCGOutOpUnary outop_revbit8 = {
1951 + .base.static_constraint = C_NotImplemented,
1952 +};
1953 +
1954 +static const TCGOutOpBswap outop_revbit32 = {
1955 + .base.static_constraint = C_NotImplemented,
1956 +};
1957 +
1958 +static const TCGOutOpUnary outop_revbit64 = {
1959 + .base.static_constraint = C_NotImplemented,
1960 +};
1961 +
1962 static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1)
1963 {
1964 tgen_sub(s, type, a0, TCG_REG_G0, a1);
tcg/tcg-op.c
+52 -14
@@ -1270,15 +1270,26 @@ void tcg_gen_hswap_i32(TCGv_i32 ret, TCGv_i32 arg)
1270
1271 void tcg_gen_revbit8_i32(TCGv_i32 ret, TCGv_i32 arg)
1272 {
1273 - gen_bitswap_i32(ret, arg, 0x55555555u);
1274 - gen_bitswap_i32(ret, ret, 0x33333333u);
1275 - gen_bitswap_i32(ret, ret, 0x0f0f0f0fu);
1273 + if (tcg_op_supported(INDEX_op_revbit8, TCG_TYPE_I32, 0)) {
1274 + tcg_gen_op2_i32(INDEX_op_revbit8, ret, arg);
1275 + } else if (tcg_op_supported(INDEX_op_revbit32, TCG_TYPE_I32, 0)) {
1276 + tcg_gen_op2_i32(INDEX_op_revbit32, ret, arg);
1277 + tcg_gen_bswap32_i32(ret, ret);
1278 + } else {
1279 + gen_bitswap_i32(ret, arg, 0x55555555u);
1280 + gen_bitswap_i32(ret, ret, 0x33333333u);
1281 + gen_bitswap_i32(ret, ret, 0x0f0f0f0fu);
1282 + }
1283 }
1284
1285 void tcg_gen_revbit32_i32(TCGv_i32 ret, TCGv_i32 arg)
1286 {
1280 - tcg_gen_revbit8_i32(ret, arg);
1281 - tcg_gen_bswap32_i32(ret, ret);
1287 + if (tcg_op_supported(INDEX_op_revbit32, TCG_TYPE_I32, 0)) {
1288 + tcg_gen_op3i_i32(INDEX_op_revbit32, ret, arg, 0);
1289 + } else {
1290 + tcg_gen_revbit8_i32(ret, arg);
1291 + tcg_gen_bswap32_i32(ret, ret);
1292 + }
1293 }
1294
1295 void tcg_gen_smin_i32(TCGv_i32 ret, TCGv_i32 a, TCGv_i32 b)
@@ -1870,23 +1881,50 @@ void tcg_gen_revbit32_i64(TCGv_i64 ret, TCGv_i64 arg, int flags)
1881 /* Only one extension flag may be present. */
1882 tcg_debug_assert(!(flags & TCG_BSWAP_OS) || !(flags & TCG_BSWAP_OZ));
1883
1873 - gen_bitswap_i64(ret, arg, 0x55555555ull);
1874 - gen_bitswap_i64(ret, ret, 0x33333333ull);
1875 - gen_bitswap_i64(ret, ret, 0x0f0f0f0full);
1876 - tcg_gen_bswap32_i64(ret, ret, flags | TCG_BSWAP_IZ);
1884 + if (tcg_op_supported(INDEX_op_revbit32, TCG_TYPE_I64, 0)) {
1885 + tcg_gen_op3i_i64(INDEX_op_revbit32, ret, arg, flags);
1886 + } else if (tcg_op_supported(INDEX_op_revbit64, TCG_TYPE_I64, 0)) {
1887 + tcg_gen_op2_i64(INDEX_op_revbit64, ret, arg);
1888 + if (flags & TCG_BSWAP_OS) {
1889 + tcg_gen_sari_i64(ret, ret, 32);
1890 + } else {
1891 + tcg_gen_shri_i64(ret, ret, 32);
1892 + }
1893 + } else {
1894 + if (tcg_op_supported(INDEX_op_revbit8, TCG_TYPE_I64, 0)) {
1895 + tcg_gen_op2_i64(INDEX_op_revbit8, ret, arg);
1896 + } else {
1897 + gen_bitswap_i64(ret, arg, 0x55555555ull);
1898 + gen_bitswap_i64(ret, ret, 0x33333333ull);
1899 + gen_bitswap_i64(ret, ret, 0x0f0f0f0full);
1900 + flags |= TCG_BSWAP_IZ;
1901 + }
1902 + tcg_gen_bswap32_i64(ret, ret, flags);
1903 + }
1904 }
1905
1906 void tcg_gen_revbit8_i64(TCGv_i64 ret, TCGv_i64 arg)
1907 {
1881 - gen_bitswap_i64(ret, arg, 0x5555555555555555ull);
1882 - gen_bitswap_i64(ret, ret, 0x3333333333333333ull);
1883 - gen_bitswap_i64(ret, ret, 0x0f0f0f0f0f0f0f0full);
1908 + if (tcg_op_supported(INDEX_op_revbit8, TCG_TYPE_I64, 0)) {
1909 + tcg_gen_op2_i64(INDEX_op_revbit8, ret, arg);
1910 + } else if (tcg_op_supported(INDEX_op_revbit64, TCG_TYPE_I64, 0)) {
1911 + tcg_gen_op2_i64(INDEX_op_revbit64, ret, arg);
1912 + tcg_gen_bswap64_i64(ret, ret);
1913 + } else {
1914 + gen_bitswap_i64(ret, arg, 0x5555555555555555ull);
1915 + gen_bitswap_i64(ret, ret, 0x3333333333333333ull);
1916 + gen_bitswap_i64(ret, ret, 0x0f0f0f0f0f0f0f0full);
1917 + }
1918 }
1919
1920 void tcg_gen_revbit64_i64(TCGv_i64 ret, TCGv_i64 arg)
1921 {
1888 - tcg_gen_revbit8_i64(ret, arg);
1889 - tcg_gen_bswap64_i64(ret, ret);
1922 + if (tcg_op_supported(INDEX_op_revbit64, TCG_TYPE_I64, 0)) {
1923 + tcg_gen_op2_i64(INDEX_op_revbit64, ret, arg);
1924 + } else {
1925 + tcg_gen_revbit8_i64(ret, arg);
1926 + tcg_gen_bswap64_i64(ret, ret);
1927 + }
1928 }
1929
1930 void tcg_gen_not_i64(TCGv_i64 ret, TCGv_i64 arg)
tcg/tcg.c
+7
@@ -1203,6 +1203,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = {
1203 OUTOP(INDEX_op_qemu_st2, TCGOutOpQemuLdSt2, outop_qemu_st2),
1204 OUTOP(INDEX_op_rems, TCGOutOpBinary, outop_rems),
1205 OUTOP(INDEX_op_remu, TCGOutOpBinary, outop_remu),
1206 + OUTOP(INDEX_op_revbit32, TCGOutOpBswap, outop_revbit32),
1207 OUTOP(INDEX_op_rotl, TCGOutOpBinary, outop_rotl),
1208 OUTOP(INDEX_op_rotr, TCGOutOpBinary, outop_rotr),
1209 OUTOP(INDEX_op_sar, TCGOutOpBinary, outop_sar),
@@ -1230,6 +1231,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = {
1231 OUTOP(INDEX_op_extrh_i64_i32, TCGOutOpUnary, outop_extrh_i64_i32),
1232 OUTOP(INDEX_op_ld32u, TCGOutOpLoad, outop_ld32u),
1233 OUTOP(INDEX_op_ld32s, TCGOutOpLoad, outop_ld32s),
1234 + OUTOP(INDEX_op_revbit8, TCGOutOpUnary, outop_revbit8),
1235 + OUTOP(INDEX_op_revbit64, TCGOutOpUnary, outop_revbit64),
1236 OUTOP(INDEX_op_st32, TCGOutOpStore, outop_st),
1237 };
1238
@@ -2950,6 +2953,7 @@ void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs)
2953 case INDEX_op_bswap16:
2954 case INDEX_op_bswap32:
2955 case INDEX_op_bswap64:
2956 + case INDEX_op_revbit32:
2957 {
2958 TCGArg flags = op->args[k];
2959 const char *name = NULL;
@@ -5581,6 +5585,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
5585 case INDEX_op_ctpop:
5586 case INDEX_op_neg:
5587 case INDEX_op_not:
5588 + case INDEX_op_revbit8:
5589 + case INDEX_op_revbit64:
5590 {
5591 const TCGOutOpUnary *out =
5592 container_of(all_outop[op->opc], TCGOutOpUnary, base);
@@ -5593,6 +5599,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
5599
5600 case INDEX_op_bswap16:
5601 case INDEX_op_bswap32:
5602 + case INDEX_op_revbit32:
5603 {
5604 const TCGOutOpBswap *out =
5605 container_of(all_outop[op->opc], TCGOutOpBswap, base);
tcg/tci/tcg-target.c.inc
+12
@@ -959,6 +959,18 @@ static const TCGOutOpUnary outop_bswap64 = {
959 .out_rr = tgen_bswap64,
960 };
961
962 +static const TCGOutOpUnary outop_revbit8 = {
963 + .base.static_constraint = C_NotImplemented,
964 +};
965 +
966 +static const TCGOutOpBswap outop_revbit32 = {
967 + .base.static_constraint = C_NotImplemented,
968 +};
969 +
970 +static const TCGOutOpUnary outop_revbit64 = {
971 + .base.static_constraint = C_NotImplemented,
972 +};
973 +
974 static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1)
975 {
976 tcg_out_op_rr(s, INDEX_op_neg, a0, a1);
tcg/x86_64/tcg-target.c.inc
+12
@@ -1290,6 +1290,18 @@ static inline void tcg_out_bswap64(TCGContext *s, int reg)
1290 tcg_out_opc(s, OPC_BSWAP + P_REXW + LOWREGMASK(reg), 0, reg, 0);
1291 }
1292
1293 +static const TCGOutOpUnary outop_revbit8 = {
1294 + .base.static_constraint = C_NotImplemented,
1295 +};
1296 +
1297 +static const TCGOutOpBswap outop_revbit32 = {
1298 + .base.static_constraint = C_NotImplemented,
1299 +};
1300 +
1301 +static const TCGOutOpUnary outop_revbit64 = {
1302 + .base.static_constraint = C_NotImplemented,
1303 +};
1304 +
1305 static void tgen_arithi(TCGContext *s, int c, int r0,
1306 tcg_target_long val, int cf)
1307 {