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" } } */

Reply via email to