https://gcc.gnu.org/g:af981ba6b6dfb1a7e15e4472318535ab7d866893
commit r17-3934-gaf981ba6b6dfb1a7e15e4472318535ab7d866893 Author: Jakub Jelinek <[email protected]> Date: Fri Sep 4 19:46:19 2026 +0200 RISC-V: Improve __builtin_bitreverse{8,16,32,64} code generation [PR126671] The following patch attempts to improve code generation for __builtin_bitreverse{8,16,32,64} when ZBKB extension is enabled, by using brev8 a0,a0 or rev8 a0,a0 brev8 t0,a0 srli a0,t0,48 ! 16 for rv32 or (bitreversesi2 if rv64) rev8 a0,a0 brev8 t0,a0 srai a0,t0,32 or (bitreversesi2 if rv32 or bitreversedi2 if rv64) rev8 a0,a0 brev8 a0,a0 Only tested in a cross on a testcase with the 4 builtins, hope CI will pick this up when posted with RISC-V in the subject. The bswaphi2 change is not strictly necessary, just weird to limit it only to TARGET_ZBB when bswap<word_mode>2 is also TARGET_ZBKB. 2026-09-04 Jakub Jelinek <[email protected]> PR target/126671 * config/riscv/bitmanip.md (bswaphi2): Use TARGET_ZBB || TARGET_ZBKB condition instead of just TARGET_ZBB. (bitreverse<mode>2): New expander. * gcc.target/riscv/bitreverse-1-zbkb.c: New test. * gcc.target/riscv/bitreverse-2-zbkb.c: New test. * gcc.target/riscv/bitreverse-3-zbkb.c: New test. Reviewed-by: Jeff Law <[email protected]> Diff: --- gcc/config/riscv/bitmanip.md | 37 ++++++++++- gcc/testsuite/gcc.target/riscv/bitreverse-1-zbkb.c | 6 ++ gcc/testsuite/gcc.target/riscv/bitreverse-2-zbkb.c | 73 ++++++++++++++++++++++ gcc/testsuite/gcc.target/riscv/bitreverse-3-zbkb.c | 59 +++++++++++++++++ 4 files changed, 174 insertions(+), 1 deletion(-) diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md index 1f0b3ec3d506..a9fc5af5a0e0 100644 --- a/gcc/config/riscv/bitmanip.md +++ b/gcc/config/riscv/bitmanip.md @@ -549,7 +549,7 @@ (define_expand "bswaphi2" [(set (match_operand:HI 0 "register_operand" "=r") (bswap:HI (match_operand:HI 1 "register_operand" "r")))] - "TARGET_ZBB" + "TARGET_ZBB || TARGET_ZBKB" { rtx tmp = gen_reg_rtx (word_mode); rtx newop1 = gen_lowpart (word_mode, operands[1]); @@ -566,6 +566,41 @@ DONE; }) +(define_expand "bitreverse<mode>2" + [(match_operand:ANYI 0 "register_operand") + (match_operand:ANYI 1 "register_operand")] + "TARGET_ZBKB" +{ + rtx newop1 = gen_lowpart (word_mode, operands[1]); + rtx tmp = newop1, tmp2; + if (<MODE>mode != QImode) + { + tmp = gen_reg_rtx (word_mode); + if (TARGET_64BIT) + emit_insn (gen_bswapdi2 (tmp, newop1)); + else + emit_insn (gen_bswapsi2 (tmp, newop1)); + } + tmp2 = gen_reg_rtx (word_mode); + if (TARGET_64BIT) + emit_insn (gen_riscv_brev8_di (tmp2, tmp)); + else + emit_insn (gen_riscv_brev8_si (tmp2, tmp)); + tmp = tmp2; + if (<MODE>mode != word_mode && <MODE>mode != QImode) + { + tmp = gen_reg_rtx (word_mode); + if (TARGET_64BIT) + emit_insn (gen_lshrdi3 (tmp, tmp2, + GEN_INT (64 - GET_MODE_BITSIZE (<MODE>mode)))); + else + emit_insn (gen_lshrsi3 (tmp, tmp2, + GEN_INT (32 - GET_MODE_BITSIZE (<MODE>mode)))); + } + emit_move_insn (operands[0], gen_lowpart (<MODE>mode, tmp)); + DONE; +}) + (define_expand "<bitmanip_optab>di3" [(set (match_operand:DI 0 "register_operand" "=r") (bitmanip_minmax:DI (match_operand:DI 1 "register_operand" "r") diff --git a/gcc/testsuite/gcc.target/riscv/bitreverse-1-zbkb.c b/gcc/testsuite/gcc.target/riscv/bitreverse-1-zbkb.c new file mode 100644 index 000000000000..02d445cf6c0b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/bitreverse-1-zbkb.c @@ -0,0 +1,6 @@ +/* { dg-do run { target riscv_zbkb } } */ +/* { dg-options "-march=rv64gc_zbkb" { target { rv64 } } } */ +/* { dg-options "-march=rv32gc_zbkb" { target { rv32 } } } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Os" "-Oz" "-Og" "-flto"} } */ + +#include "../../gcc.dg/builtin-bitreverse-1.c" diff --git a/gcc/testsuite/gcc.target/riscv/bitreverse-2-zbkb.c b/gcc/testsuite/gcc.target/riscv/bitreverse-2-zbkb.c new file mode 100644 index 000000000000..12e4dc8345ee --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/bitreverse-2-zbkb.c @@ -0,0 +1,73 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_zbkb -O2 -mabi=lp64" } */ +/* { dg-skip-if "needs -O2" { *-*-* } { "-O0" "-O1" "-O3" "-Og" "-Os" "-Oz" "-flto" } { "" } } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +/* +** br8: +** brev8 a0,a0 +** andi a0,a0,0xff +** ret +** ... +*/ +unsigned char +br8 (unsigned char x) +{ + return __builtin_bitreverse8 (x); +} + +/* +** br16: +** rev8 a0,a0 +** brev8 t0,a0 +** srli a0,t0,48 +** ret +** ... +*/ +unsigned short +br16 (unsigned short x) +{ + return __builtin_bitreverse16 (x); +} + +/* +** br32: +** rev8 a0,a0 +** brev8 t0,a0 +** srai a0,t0,32 +** ret +** ... +*/ +unsigned +br32 (unsigned x) +{ + return __builtin_bitreverse32 (x); +} + +/* +** br64: +** rev8 a0,a0 +** brev8 a0,a0 +** ret +** ... +*/ +unsigned long long +br64 (unsigned long long x) +{ + return __builtin_bitreverse64 (x); +} + +/* +** br128: +** rev8 a5,a0 +** rev8 a0,a1 +** brev8 a0,a0 +** brev8 a1,a5 +** ret +** ... +*/ +unsigned __int128 +br128 (unsigned __int128 x) +{ + return __builtin_bitreverse128 (x); +} diff --git a/gcc/testsuite/gcc.target/riscv/bitreverse-3-zbkb.c b/gcc/testsuite/gcc.target/riscv/bitreverse-3-zbkb.c new file mode 100644 index 000000000000..9aee7af57d64 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/bitreverse-3-zbkb.c @@ -0,0 +1,59 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv32gc_zbkb -O2 -mabi=ilp32" } */ +/* { dg-skip-if "needs -O2" { *-*-* } { "-O0" "-O1" "-O3" "-Og" "-Os" "-Oz" "-flto" } { "" } } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +/* +** br8: +** brev8 a0,a0 +** andi a0,a0,0xff +** ret +** ... +*/ +unsigned char +br8 (unsigned char x) +{ + return __builtin_bitreverse8 (x); +} + +/* +** br16: +** rev8 a0,a0 +** brev8 t0,a0 +** srli a0,t0,16 +** ret +** ... +*/ +unsigned short +br16 (unsigned short x) +{ + return __builtin_bitreverse16 (x); +} + +/* +** br32: +** rev8 a0,a0 +** brev8 a0,a0 +** ret +** ... +*/ +unsigned +br32 (unsigned x) +{ + return __builtin_bitreverse32 (x); +} + +/* +** br64: +** rev8 a5,a0 +** rev8 a0,a1 +** brev8 a0,a0 +** brev8 a1,a5 +** ret +** ... +*/ +unsigned long long +br64 (unsigned long long x) +{ + return __builtin_bitreverse64 (x); +}
