https://gcc.gnu.org/g:60b27d915e14748a627deb1a4616da419b1e24b2
commit r17-2486-g60b27d915e14748a627deb1a4616da419b1e24b2 Author: Uros Bizjak <[email protected]> Date: Fri Jul 17 13:28:16 2026 +0200 i386: Add ROLW %r,8 alternative to bswaphi2 patterns [PR126283] The HImode bswap can be implemented in two ways: using XCHGB %rH,%rL or ROLW %r,8 where the former does not clobber flags. Unfortunately, clobber-less XCHGB form limits available register set to only %ax, %bx, %cx and %dx, where ROLW can use all registers (but clobbers flags reg). It is better to use the form that clobbers flags reg and leave insn selection to the compiler via preferred_for_* machinery. This choice also makes "improve register allocation" peephole2 obsolete. Also, always convert HImode rotate by 8 to bswap pattern, which can also emit MOVBE instruction when available. PR target/126283 gcc/ChangeLog: * config/i386/i386.md (bswaphi2): Add flags reg clobber. (*bswaphi2_movbe): Add flags reg clobber. Add ROLW alternative and update instruction attributes. Add preferred_for_size and preferred_for_speed attributes. (*bswaphi2): Ditto. (*bswaphisi2_lowpart): Ditto. (XCHGB -> ROLW peephole2 patterns): Remove. (ROLW reg,8 -> BSWAP splitter): Update for added flags reg clobber. Always split. * config/i386/i386-expand.cc (ix86_expand_gfni_bitreverse): Update for bswaphi2 change. gcc/testsuite/ChangeLog: * gcc.target/i386/xchg-1.c: Scan for XCHG instead of ROL. * gcc.target/i386/pr126283.c: New test. Diff: --- gcc/config/i386/i386-expand.cc | 7 +- gcc/config/i386/i386.md | 167 +++++++++++++++---------------- gcc/testsuite/gcc.target/i386/pr126283.c | 9 ++ gcc/testsuite/gcc.target/i386/xchg-1.c | 2 +- 4 files changed, 96 insertions(+), 89 deletions(-) diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc index fceb958b7e6a..bdd75067a007 100644 --- a/gcc/config/i386/i386-expand.cc +++ b/gcc/config/i386/i386-expand.cc @@ -28420,8 +28420,11 @@ ix86_expand_gfni_bitreverse (rtx dest, rtx src) return; } if (mode == HImode) - target = lowpart_subreg (mode, target, SImode); - if (mode == SImode) + { + target = lowpart_subreg (mode, target, SImode); + emit_insn (gen_bswaphi2 (dest, target)); + } + else if (mode == SImode) emit_insn (gen_bswapsi2 (dest, target)); else emit_insn (gen_rtx_SET (dest, gen_rtx_BSWAP (mode, target))); diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 3aa8c9260942..fbaf28017bbb 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -19717,12 +19717,14 @@ (set_attr "mode" "<MODE>")]) (define_split - [(set (match_operand:HI 0 "QIreg_operand") + [(set (match_operand:HI 0 "register_operand") (any_rotate:HI (match_dup 0) (const_int 8))) (clobber (reg:CC FLAGS_REG))] - "reload_completed - && (TARGET_USE_XCHGB || optimize_function_for_size_p (cfun))" - [(set (match_dup 0) (bswap:HI (match_dup 0)))]) + "" + [(parallel + [(set (match_dup 0) + (bswap:HI (match_dup 0))) + (clobber (reg:CC FLAGS_REG))])]) ;; Rotations through carry flag (define_insn "rcrsi2" @@ -23656,8 +23658,10 @@ (set_attr "mode" "<MODE>")]) (define_expand "bswaphi2" - [(set (match_operand:HI 0 "register_operand") - (bswap:HI (match_operand:HI 1 "nonimmediate_operand")))] + [(parallel + [(set (match_operand:HI 0 "register_operand") + (bswap:HI (match_operand:HI 1 "nonimmediate_operand"))) + (clobber (reg:CC FLAGS_REG))])] "" { if (!TARGET_MOVBE) @@ -23665,100 +23669,91 @@ }) (define_insn "*bswaphi2_movbe" - [(set (match_operand:HI 0 "nonimmediate_operand" "=Q,r,m") - (bswap:HI (match_operand:HI 1 "nonimmediate_operand" "0,m,r")))] + [(set (match_operand:HI 0 "nonimmediate_operand" "=Q,r,r,m") + (bswap:HI (match_operand:HI 1 "nonimmediate_operand" "0,0,m,r"))) + (clobber (reg:CC FLAGS_REG))] "TARGET_MOVBE && !(MEM_P (operands[0]) && MEM_P (operands[1]))" "@ xchg{b}\t{%h0, %b0|%b0, %h0} + rol{w}\t{$8, %0|%0, 8} movbe{w}\t{%1, %0|%0, %1} movbe{w}\t{%1, %0|%0, %1}" - [(set_attr "type" "imov") - (set_attr "modrm" "*,1,1") - (set_attr "prefix_0f" "*,1,1") - (set_attr "prefix_extra" "*,1,1") - (set_attr "pent_pair" "np,*,*") - (set_attr "athlon_decode" "vector,*,*") - (set_attr "amdfam10_decode" "double,*,*") - (set_attr "c86_decode" "vector,*,*") - (set_attr "bdver1_decode" "double,*,*") - (set_attr "mode" "QI,HI,HI")]) + [(set_attr "type" "imov,rotate1,imov,imov") + (set_attr "modrm" "*,*,1,1") + (set_attr "prefix_0f" "*,*,1,1") + (set_attr "prefix_extra" "*,*,1,1") + (set_attr "pent_pair" "np,*,*,*") + (set_attr "athlon_decode" "vector,*,*,*") + (set_attr "amdfam10_decode" "double,*,*,*") + (set_attr "c86_decode" "vector,*,*,*") + (set_attr "bdver1_decode" "double,*,*,*") + (set_attr "mode" "QI,HI,HI,HI") + (set (attr "preferred_for_size") + (cond [(eq_attr "alternative" "1") + (symbol_ref "false") + ] + (symbol_ref "true"))) + (set (attr "preferred_for_speed") + (cond [(eq_attr "alternative" "1") + (symbol_ref "!TARGET_USE_XCHGB") + ] + (symbol_ref "true")))]) (define_insn "*bswaphi2" - [(set (match_operand:HI 0 "register_operand" "=Q") - (bswap:HI (match_operand:HI 1 "register_operand" "0")))] + [(set (match_operand:HI 0 "register_operand" "=Q,r") + (bswap:HI (match_operand:HI 1 "register_operand" "0,0"))) + (clobber (reg:CC FLAGS_REG))] "!TARGET_MOVBE" - "xchg{b}\t{%h0, %b0|%b0, %h0}" - [(set_attr "type" "imov") - (set_attr "pent_pair" "np") - (set_attr "athlon_decode" "vector") - (set_attr "amdfam10_decode" "double") - (set_attr "c86_decode" "vector") - (set_attr "bdver1_decode" "double") - (set_attr "mode" "QI")]) - -(define_peephole2 - [(set (match_operand:HI 0 "general_reg_operand") - (bswap:HI (match_dup 0)))] - "!(TARGET_USE_XCHGB || - TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) - && peep2_regno_dead_p (0, FLAGS_REG)" - [(parallel [(set (match_dup 0) (rotate:HI (match_dup 0) (const_int 8))) - (clobber (reg:CC FLAGS_REG))])]) + "@ + xchg{b}\t{%h0, %b0|%b0, %h0} + rol{w}\t{$8, %0|%0, 8}" + [(set_attr "type" "imov,rotate1") + (set_attr "pent_pair" "np,*") + (set_attr "athlon_decode" "vector,*") + (set_attr "amdfam10_decode" "double,*") + (set_attr "c86_decode" "vector,*") + (set_attr "bdver1_decode" "double,*") + (set_attr "mode" "QI,HI") + (set (attr "preferred_for_size") + (cond [(eq_attr "alternative" "1") + (symbol_ref "false") + ] + (symbol_ref "true"))) + (set (attr "preferred_for_speed") + (cond [(eq_attr "alternative" "1") + (symbol_ref "!TARGET_USE_XCHGB") + ] + (symbol_ref "true")))]) (define_insn "bswaphisi2_lowpart" - [(set (match_operand:SI 0 "register_operand" "=Q") - (ior:SI (and:SI (match_operand:SI 1 "register_operand" "0") + [(set (match_operand:SI 0 "register_operand" "=Q,r") + (ior:SI (and:SI (match_operand:SI 1 "register_operand" "0,0") (const_int -65536)) (lshiftrt:SI (bswap:SI (match_dup 1)) - (const_int 16))))] - "" - "xchg{b}\t{%h0, %b0|%b0, %h0}" - [(set_attr "type" "imov") - (set_attr "pent_pair" "np") - (set_attr "athlon_decode" "vector") - (set_attr "amdfam10_decode" "double") - (set_attr "c86_decode" "vector") - (set_attr "bdver1_decode" "double") - (set_attr "mode" "QI")]) - -(define_peephole2 - [(set (match_operand:SI 0 "general_reg_operand") - (ior:SI (and:SI (match_dup 0) - (const_int -65536)) - (lshiftrt:SI (bswap:SI (match_dup 0)) - (const_int 16))))] - "!(TARGET_USE_XCHGB || - TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) - && peep2_regno_dead_p (0, FLAGS_REG)" - [(parallel [(set (strict_low_part (match_dup 0)) - (rotate:HI (match_dup 0) (const_int 8))) - (clobber (reg:CC FLAGS_REG))])] - "operands[0] = gen_lowpart (HImode, operands[0]);") - -;; Variant of above peephole2 to improve register allocation. -(define_peephole2 - [(set (match_operand:SI 0 "general_reg_operand") - (match_operand:SI 1 "register_operand")) - (set (match_dup 0) - (ior:SI (and:SI (match_dup 0) - (const_int -65536)) - (lshiftrt:SI (bswap:SI (match_dup 0)) (const_int 16)))) - (set (match_operand:SI 2 "general_reg_operand") (match_dup 0))] - "!(TARGET_USE_XCHGB || - TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) - && peep2_regno_dead_p (0, FLAGS_REG) - && peep2_reg_dead_p(3, operands[0])" - [(parallel - [(set (strict_low_part (match_dup 3)) - (rotate:HI (match_dup 3) (const_int 8))) - (clobber (reg:CC FLAGS_REG))])] -{ - if (!rtx_equal_p (operands[1], operands[2])) - emit_move_insn (operands[2], operands[1]); - operands[3] = gen_lowpart (HImode, operands[2]); -}) + (clobber (reg:CC FLAGS_REG))] + "" + "@ + xchg{b}\t{%h0, %b0|%b0, %h0} + rol{w}\t{$8, %0|%0, 8}" + [(set_attr "type" "imov,rotate1") + (set_attr "pent_pair" "np,*") + (set_attr "athlon_decode" "vector,*") + (set_attr "amdfam10_decode" "double,*") + (set_attr "c86_decode" "vector,*") + (set_attr "bdver1_decode" "double,*") + (set_attr "mode" "QI,HI") + (set (attr "preferred_for_size") + (cond [(eq_attr "alternative" "1") + (symbol_ref "false") + ] + (symbol_ref "true"))) + (set (attr "preferred_for_speed") + (cond [(eq_attr "alternative" "1") + (symbol_ref "!TARGET_USE_XCHGB") + ] + (symbol_ref "true")))]) (define_expand "bitreverse<mode>2" [(set (match_operand:SWIDWI 0 "register_operand") diff --git a/gcc/testsuite/gcc.target/i386/pr126283.c b/gcc/testsuite/gcc.target/i386/pr126283.c new file mode 100644 index 000000000000..5f9a03225e25 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr126283.c @@ -0,0 +1,9 @@ +/* PR target/126283 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -masm=att" } */ +/* { dg-additional-options "-mregparm=1" { target ia32 } } */ +/* { dg-final { scan-assembler-not "movl\[\\t \]+" } } */ + +int f (short x) { + return __builtin_bswap16(x); +} diff --git a/gcc/testsuite/gcc.target/i386/xchg-1.c b/gcc/testsuite/gcc.target/i386/xchg-1.c index e81fe49cd0b1..ea9fc7a8b14e 100644 --- a/gcc/testsuite/gcc.target/i386/xchg-1.c +++ b/gcc/testsuite/gcc.target/i386/xchg-1.c @@ -6,4 +6,4 @@ unsigned short good(unsigned short a) return (a >> 8 | a << 8); } -/* { dg-final { scan-assembler "rol" } } */ +/* { dg-final { scan-assembler "\[ \t\]xchg" } } */
