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.
Bootstrapped and regression tested on x86_64-linux-gnu {,-m32}.
Uros.
diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc
index fceb958b7e6..bdd75067a00 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 3aa8c926094..fbaf28017bb 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -19717,12 +19717,14 @@ (define_insn_and_split "*<insn><mode>3_1_slp"
(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 @@ (define_insn "*bswap<mode>2"
(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_expand "bswaphi2"
})
(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 00000000000..5f9a03225e2
--- /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 e81fe49cd0b..ea9fc7a8b14 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" } } */