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
{