Add missing AArch64 bitreverse expanders so __builtin_bitreverse* can lower to existing rbit patterns.
For QI and HI modes we widen to SI, apply rbit, then shift right by 24 or 16 respectively. Unlike Clang, this emits an and for the zero-extend; I am not entirely sure how to avoid this. gcc/testsuite/ChangeLog: - * gcc.target/aarch64/bitreverse.c: New test. gcc/ChangeLog: - * config/aarch64/aarch64.md (bitreverse<mode>2, bitreverseqi2, bitreversehi2): New expanders. - * config/aarch64/aarch64-simd.md (bitreverse<mode>2): New expander. Signed-off-by: Disservin <[email protected]> --- gcc/config/aarch64/aarch64-simd.md | 7 ++- gcc/config/aarch64/aarch64.md | 32 ++++++++++++ gcc/testsuite/gcc.target/aarch64/bitreverse.c | 50 +++++++++++++++++++ 3 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.target/aarch64/bitreverse.c diff --git a/gcc/config/aarch64/aarch64-simd.md b/gcc/config/aarch64/aarch64-simd.md index 2e142b1e1ee..da66bd36fe9 100644 --- a/gcc/config/aarch64/aarch64-simd.md +++ b/gcc/config/aarch64/aarch64-simd.md @@ -400,6 +400,12 @@ [(set_attr "type" "neon_rev<q>")] ) +(define_expand "bitreverse<mode>2" + [(set (match_operand:VB 0 "register_operand") + (bitreverse:VB (match_operand:VB 1 "register_operand")))] + "TARGET_SIMD" + "") + (define_insn "aarch64_rbit<mode><vczle><vczbe>" [(set (match_operand:VB 0 "register_operand" "=w") (bitreverse:VB (match_operand:VB 1 "register_operand" "w")))] @@ -10697,4 +10703,3 @@ [ w , 0 , w , w ] <insn>\t%0.<Vtype>, %2.16b, %3.16b } ) - diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md index 0ef01e889a6..a69317f747f 100644 --- a/gcc/config/aarch64/aarch64.md +++ b/gcc/config/aarch64/aarch64.md @@ -5786,6 +5786,38 @@ [(set_attr "type" "rbit")] ) +(define_expand "bitreverse<mode>2" + [(set (match_operand:GPI 0 "register_operand") + (bitreverse:GPI (match_operand:GPI 1 "register_operand")))] + "" + "") + +(define_expand "bitreverseqi2" + [(set (match_operand:QI 0 "register_operand") + (bitreverse:QI (match_operand:QI 1 "register_operand")))] + "" + { + rtx t = gen_reg_rtx (SImode); + emit_insn (gen_aarch64_rbitsi (t, gen_lowpart (SImode, operands[1]))); + t = expand_simple_binop (SImode, LSHIFTRT, t, GEN_INT (24), + NULL_RTX, false, OPTAB_DIRECT); + emit_move_insn (operands[0], gen_lowpart (QImode, t)); + DONE; + }) + +(define_expand "bitreversehi2" + [(set (match_operand:HI 0 "register_operand") + (bitreverse:HI (match_operand:HI 1 "register_operand")))] + "" + { + rtx t = gen_reg_rtx (SImode); + emit_insn (gen_aarch64_rbitsi (t, gen_lowpart (SImode, operands[1]))); + t = expand_simple_binop (SImode, LSHIFTRT, t, GEN_INT (16), + NULL_RTX, false, OPTAB_DIRECT); + emit_move_insn (operands[0], gen_lowpart (HImode, t)); + DONE; + }) + (define_expand "ffs<mode>2" [(match_operand:GPI 0 "register_operand") (match_operand:GPI 1 "register_operand")] diff --git a/gcc/testsuite/gcc.target/aarch64/bitreverse.c b/gcc/testsuite/gcc.target/aarch64/bitreverse.c new file mode 100644 index 00000000000..5dbec3a5011 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/bitreverse.c @@ -0,0 +1,50 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +/* +** br8: +** and w0, w0, 255 +** rbit w0, w0 +** lsr w0, w0, 24 +** ret +*/ +[[gnu::noipa]] unsigned char +br8 (unsigned char x) +{ + return __builtin_bitreverse8 (x); +} + +/* +** br16: +** and w0, w0, 65535 +** rbit w0, w0 +** lsr w0, w0, 16 +** ret +*/ +[[gnu::noipa]] unsigned short +br16 (unsigned short x) +{ + return __builtin_bitreverse16 (x); +} + +/* +** br32: +** rbit w0, w0 +** ret +*/ +[[gnu::noipa]] unsigned int +br32 (unsigned int x) +{ + return __builtin_bitreverse32 (x); +} + +/* +** br64: +** rbit x0, x0 +** ret +*/ +[[gnu::noipa]] unsigned long long +br64 (unsigned long long x) +{ + return __builtin_bitreverse64 (x); +} \ No newline at end of file -- 2.34.1
