Hi!
The following patch extends the widen_bswap and expand_doubleword_bswap
functions to handle also bitreverse, so that all the backends with
say just bitreversesi2 or bitreverse{s,d}i2 can handle also
bitreverse{q,h}i2 and bitreverse{d,t}i2 easily.
Tested on aarch64-linux with just bitreverse{s,d}i2 on
builtin-bitreverse-1.c, ok for trunk if it passes full bootstrap/regtest?
2026-05-18 Jakub Jelinek <[email protected]>
PR target/50481
* optabs.cc (widen_bswap): Add UNOPTAB argument and use it instead
of hardcoded bswap_optab.
(expand_doubleword_bswap): Likewise.
(expand_bitreverse): Use widen_bswap and expand_doubleword_bswap.
(expand_unop): Adjust widen_bswap and expand_doubleword_bswap callers.
--- gcc/optabs.cc.jj 2026-05-15 09:31:18.383653795 +0200
+++ gcc/optabs.cc 2026-05-18 12:45:19.146458240 +0200
@@ -2895,16 +2895,17 @@ expand_doubleword_parity (scalar_int_mod
/* Try calculating
(bswap:narrow x)
as
- (lshiftrt:wide (bswap:wide x) ((width wide) - (width narrow))). */
+ (lshiftrt:wide (bswap:wide x) ((width wide) - (width narrow)))
+ or similarly for bitreverse. */
static rtx
-widen_bswap (scalar_int_mode mode, rtx op0, rtx target)
+widen_bswap (scalar_int_mode mode, rtx op0, rtx target, optab unoptab)
{
rtx x;
rtx_insn *last;
opt_scalar_int_mode wider_mode_iter;
FOR_EACH_WIDER_MODE (wider_mode_iter, mode)
- if (optab_handler (bswap_optab, wider_mode_iter.require ())
+ if (optab_handler (unoptab, wider_mode_iter.require ())
!= CODE_FOR_nothing)
break;
@@ -2915,7 +2916,7 @@ widen_bswap (scalar_int_mode mode, rtx o
last = get_last_insn ();
x = widen_operand (op0, wider_mode, mode, true, true);
- x = expand_unop (wider_mode, bswap_optab, x, NULL_RTX, true);
+ x = expand_unop (wider_mode, unoptab, x, NULL_RTX, true);
gcc_assert (GET_MODE_PRECISION (wider_mode) == GET_MODE_BITSIZE (wider_mode)
&& GET_MODE_PRECISION (mode) == GET_MODE_BITSIZE (mode));
@@ -2937,16 +2938,17 @@ widen_bswap (scalar_int_mode mode, rtx o
return target;
}
-/* Try calculating bswap as two bswaps of two word-sized operands. */
+/* Try calculating bswap as two bswaps of two word-sized operands.
+ Similarly for bitreverse. */
static rtx
-expand_doubleword_bswap (machine_mode mode, rtx op, rtx target)
+expand_doubleword_bswap (machine_mode mode, rtx op, rtx target, optab unoptab)
{
rtx t0, t1;
- t1 = expand_unop (word_mode, bswap_optab,
+ t1 = expand_unop (word_mode, unoptab,
operand_subword_force (op, 0, mode), NULL_RTX, true);
- t0 = expand_unop (word_mode, bswap_optab,
+ t0 = expand_unop (word_mode, unoptab,
operand_subword_force (op, 1, mode), NULL_RTX, true);
if (target == 0 || !valid_multiword_target_p (target))
@@ -2972,6 +2974,15 @@ expand_bitreverse (scalar_int_mode mode,
if (precision < 4)
return NULL_RTX;
+ if (rtx temp = widen_bswap (mode, op0, target, bitreverse_optab))
+ return temp;
+
+ if (GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD
+ && optab_handler (bitreverse_optab, word_mode) != CODE_FOR_nothing)
+ if (rtx temp = expand_doubleword_bswap (mode, op0, target,
+ bitreverse_optab))
+ return temp;
+
if (target == NULL_RTX
|| target == op0
|| reg_overlap_mentioned_p (target, op0))
@@ -3516,7 +3527,7 @@ expand_unop (machine_mode mode, optab un
if (is_a <scalar_int_mode> (mode, &int_mode))
{
- temp = widen_bswap (int_mode, op0, target);
+ temp = widen_bswap (int_mode, op0, target, unoptab);
if (temp)
return temp;
@@ -3526,7 +3537,7 @@ expand_unop (machine_mode mode, optab un
&& (UNITS_PER_WORD == 8
|| optab_handler (unoptab, word_mode) != CODE_FOR_nothing))
{
- temp = expand_doubleword_bswap (mode, op0, target);
+ temp = expand_doubleword_bswap (mode, op0, target, unoptab);
if (temp)
return temp;
}
Jakub