This patch is a revision of my previous patch to use add_optab in
the expansion of bitreverse and store_fixed_bitfield which improves
code generation on x86, cris, riscv, parisc, sh and possibly other
targets.
https://gcc.gnu.org/pipermail/gcc-patches/2026-August/728199.html
The AVR backend change has been approved by the AVR maintainers,
and a patch committed to avoid issues on AArch64, so all that
remains are the middle-end pieces.
This patch has been tested on x86_64-pc-linux-gnu with make bootstrap
and make -k check, both with and without --target_board=unix{-m32}
with no new failures. Ok for mainline?
2026-09-03 Roger Sayle <[email protected]>
gcc/ChangeLog
* expmed.cc (store_fixed_bit_field_1): Use new aop_optab when
writing a value into a fixed size bitfield of a structure.
* optabs.cc (expand_binop): If target doesn't provide a suitable
aop<mode>3 instruction, intelligently use PLUS or IOR instead.
(expand_binop): For rotations, use aop_optab to select AOP
implementation instead of hard-coding add_optab.
(expand_bitreverse): Likwise, Use aop_optab instead of ior_optab
when composing swapped bits and nibbles (allows use of shift_add).
* optabs.def (aop_optab): New named optab for any_or_plus.
* rtl.def (AOP): New RTX code to capture any_or_plus semantics.
* config/avr/avr.md (aop<mode>3): New define_expand to specify
that IOR should always be used to implement any_or_plus (AOP).
gcc/testsuite/ChangeLog
* gcc.target/i386/builtin-bitreverse-1.c: New test case.
Thanks in advance,
Roger
--
diff --git a/gcc/expmed.cc b/gcc/expmed.cc
index 9c70e48e311..e403ba05693 100644
--- a/gcc/expmed.cc
+++ b/gcc/expmed.cc
@@ -1382,8 +1382,9 @@ store_fixed_bit_field_1 (rtx op0, scalar_int_mode mode,
if (! all_zero)
{
- temp = expand_binop (mode, ior_optab, temp, value,
- NULL_RTX, 1, OPTAB_LIB_WIDEN);
+ /* Use aop_optab if the field has been cleared. */
+ temp = expand_binop (mode, all_one ? ior_optab : aop_optab,
+ temp, value, NULL_RTX, 1, OPTAB_LIB_WIDEN);
temp = force_reg (mode, temp);
}
diff --git a/gcc/optabs.cc b/gcc/optabs.cc
index 012c0e9736e..fb9ecef8bcc 100644
--- a/gcc/optabs.cc
+++ b/gcc/optabs.cc
@@ -1632,6 +1632,16 @@ expand_binop (machine_mode mode, optab binoptab, rtx
op0, rtx op1,
}
}
+ /* If backend's machine description doesn't specify an any_or_plus
+ (AOP) preference, choose for it. */
+ if (binoptab == aop_optab)
+ {
+ binoptab = (mode == word_mode || mode == SImode) ? add_optab
+ : ior_optab;
+ return expand_binop (mode, binoptab, op0, op1,
+ target, unsignedp, methods);
+ }
+
/* If this is a vector shift by a scalar, see if we can do a vector
shift by a vector. If so, broadcast the scalar into a vector. */
if (mclass == MODE_VECTOR_INT)
@@ -1975,7 +1985,7 @@ expand_binop (machine_mode mode, optab binoptab, rtx op0,
rtx op1,
NULL_RTX, unsignedp, next_methods);
if (into_temp1 != 0 && into_temp2 != 0)
- inter = expand_binop (word_mode, add_optab, into_temp1, into_temp2,
+ inter = expand_binop (word_mode, aop_optab, into_temp1, into_temp2,
into_target, unsignedp, next_methods);
else
inter = 0;
@@ -1991,7 +2001,7 @@ expand_binop (machine_mode mode, optab binoptab, rtx op0,
rtx op1,
NULL_RTX, unsignedp, next_methods);
if (inter != 0 && outof_temp1 != 0 && outof_temp2 != 0)
- inter = expand_binop (word_mode, add_optab,
+ inter = expand_binop (word_mode, aop_optab,
outof_temp1, outof_temp2,
outof_target, unsignedp, next_methods);
@@ -3029,7 +3039,7 @@ expand_bitreverse (scalar_int_mode mode, rtx op0, rtx
target)
NULL_RTX, true, OPTAB_LIB_WIDEN);
if (lo == NULL_RTX) goto fail;
- x = expand_binop (mode, ior_optab, hi, lo,
+ x = expand_binop (mode, aop_optab, hi, lo,
NULL_RTX, true, OPTAB_LIB_WIDEN);
if (x == NULL_RTX) goto fail;
}
@@ -3056,7 +3066,7 @@ expand_bitreverse (scalar_int_mode mode, rtx op0, rtx
target)
NULL_RTX, true, OPTAB_LIB_WIDEN);
if (lo == NULL_RTX) goto fail;
- x = expand_binop (mode, ior_optab, hi, lo,
+ x = expand_binop (mode, aop_optab, hi, lo,
NULL_RTX, true, OPTAB_LIB_WIDEN);
if (x == NULL_RTX) goto fail;
}
@@ -3084,7 +3094,7 @@ expand_bitreverse (scalar_int_mode mode, rtx op0, rtx
target)
NULL_RTX, true, OPTAB_LIB_WIDEN);
if (lo == NULL_RTX) goto fail;
- x = expand_binop (mode, ior_optab, hi, lo,
+ x = expand_binop (mode, aop_optab, hi, lo,
target, true, OPTAB_LIB_WIDEN);
if (x == NULL_RTX) goto fail;
}
diff --git a/gcc/optabs.def b/gcc/optabs.def
index 327e3efaf8a..0868187c544 100644
--- a/gcc/optabs.def
+++ b/gcc/optabs.def
@@ -573,3 +573,4 @@ OPTAB_D (mask_len_strided_load_optab,
"mask_len_strided_load_$a")
OPTAB_D (mask_len_strided_store_optab, "mask_len_strided_store_$a")
OPTAB_D (andn_optab, "andn$a3")
OPTAB_D (iorn_optab, "iorn$a3")
+OPTAB_DC (aop_optab, "aop$a3", AOP)
diff --git a/gcc/rtl.def b/gcc/rtl.def
index ae757929de2..cec11d83207 100644
--- a/gcc/rtl.def
+++ b/gcc/rtl.def
@@ -490,6 +490,7 @@ DEF_RTL_EXPR(UMOD, "umod", "ee", RTX_BIN_ARITH)
DEF_RTL_EXPR(AND, "and", "ee", RTX_COMM_ARITH)
DEF_RTL_EXPR(IOR, "ior", "ee", RTX_COMM_ARITH)
DEF_RTL_EXPR(XOR, "xor", "ee", RTX_COMM_ARITH)
+DEF_RTL_EXPR(AOP, "aop", "ee", RTX_COMM_ARITH)
DEF_RTL_EXPR(NOT, "not", "e", RTX_UNARY)
/* Operand:
diff --git a/gcc/testsuite/gcc.target/i386/builtin-bitreverse-1.c
b/gcc/testsuite/gcc.target/i386/builtin-bitreverse-1.c
new file mode 100644
index 00000000000..797f9018cd6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/builtin-bitreverse-1.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mno-gfni" } */
+
+unsigned int foo(unsigned int x)
+{
+ return __builtin_bitreverse32 (x);
+}
+
+/* { dg-final { scan-assembler-times "leal" 2 } } */
+/* { dg-final { scan-assembler-not "orl" } } */