public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r14-5539] i386: Optimize QImode insn with high input registers
@ 2023-11-16 18:12 Uros Bizjak
  0 siblings, 0 replies; only message in thread
From: Uros Bizjak @ 2023-11-16 18:12 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:8ebc7e0b0ddf4679cf09ed6836fac30ca01d3ba0

commit r14-5539-g8ebc7e0b0ddf4679cf09ed6836fac30ca01d3ba0
Author: Uros Bizjak <ubizjak@gmail.com>
Date:   Thu Nov 16 18:07:36 2023 +0100

    i386: Optimize QImode insn with high input registers
    
    Sometimes the compiler emits the following code with <insn>qi_ext<mode>_0:
    
            shrl    $8, %eax
            addb    %bh, %al
    
    Patch introduces new low part QImode insn patterns with both of
    their input arguments extracted from high register.  This invalid
    insn is split after reload to a move from the high register
    and <insn>qi_ext<mode>_0 instruction.  The combine pass is able to
    convert shift to zero/sign-extract sub-RTX, which we split to the
    optimal:
    
            movzbl  %bh, %edx
            addb    %ah, %dl
    
            PR target/78904
    
    gcc/ChangeLog:
    
            * config/i386/i386.md (*addqi_ext2<mode>_0):
            New define_insn_and_split pattern.
            (*subqi_ext2<mode>_0): Ditto.
            (*<code>qi_ext2<mode>_0): Ditto.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.target/i386/pr78904-10.c: New test.
            * gcc.target/i386/pr78904-10a.c: New test.
            * gcc.target/i386/pr78904-10b.c: New test.

Diff:
---
 gcc/config/i386/i386.md                     | 99 +++++++++++++++++++++++++++++
 gcc/testsuite/gcc.target/i386/pr78904-10.c  | 47 ++++++++++++++
 gcc/testsuite/gcc.target/i386/pr78904-10a.c | 46 ++++++++++++++
 gcc/testsuite/gcc.target/i386/pr78904-10b.c | 47 ++++++++++++++
 4 files changed, 239 insertions(+)

diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index f5407ab3054..1b5a794b9e5 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -7069,6 +7069,39 @@
    (set_attr "type" "alu")
    (set_attr "mode" "QI")])
 
+(define_insn_and_split "*addqi_ext2<mode>_0"
+  [(set (match_operand:QI 0 "register_operand" "=&Q")
+	(plus:QI
+	  (subreg:QI
+	    (match_operator:SWI248 3 "extract_operator"
+	      [(match_operand 1 "int248_register_operand" "Q")
+	       (const_int 8)
+	       (const_int 8)]) 0)
+	  (subreg:QI
+	    (match_operator:SWI248 4 "extract_operator"
+	      [(match_operand 2 "int248_register_operand" "Q")
+	       (const_int 8)
+	       (const_int 8)]) 0)))
+   (clobber (reg:CC FLAGS_REG))]
+  ""
+  "#"
+  "&& reload_completed"
+  [(set (match_dup 0)
+	(subreg:QI
+	  (match_op_dup 4
+	    [(match_dup 2) (const_int 8) (const_int 8)]) 0))
+   (parallel
+     [(set (match_dup 0)
+	   (plus:QI
+	     (subreg:QI
+	       (match_op_dup 3
+		 [(match_dup 1) (const_int 8) (const_int 8)]) 0)
+	   (match_dup 0)))
+      (clobber (reg:CC FLAGS_REG))])]
+  ""
+  [(set_attr "type" "alu")
+   (set_attr "mode" "QI")])
+
 (define_expand "addqi_ext_1"
   [(parallel
      [(set (zero_extract:HI (match_operand:HI 0 "register_operand")
@@ -7814,6 +7847,39 @@
    (set_attr "type" "alu")
    (set_attr "mode" "QI")])
 
+(define_insn_and_split "*subqi_ext2<mode>_0"
+  [(set (match_operand:QI 0 "register_operand" "=&Q")
+	(minus:QI
+	  (subreg:QI
+	    (match_operator:SWI248 3 "extract_operator"
+	      [(match_operand 1 "int248_register_operand" "Q")
+	       (const_int 8)
+	       (const_int 8)]) 0)
+	  (subreg:QI
+	    (match_operator:SWI248 4 "extract_operator"
+	      [(match_operand 2 "int248_register_operand" "Q")
+	       (const_int 8)
+	       (const_int 8)]) 0)))
+   (clobber (reg:CC FLAGS_REG))]
+  ""
+  "#"
+  "&& reload_completed"
+  [(set (match_dup 0)
+	(subreg:QI
+	  (match_op_dup 3
+	    [(match_dup 1) (const_int 8) (const_int 8)]) 0))
+   (parallel
+     [(set (match_dup 0)
+	   (minus:QI
+	     (match_dup 0)
+	     (subreg:QI
+	       (match_op_dup 4
+		 [(match_dup 2) (const_int 8) (const_int 8)]) 0)))
+      (clobber (reg:CC FLAGS_REG))])]
+  ""
+  [(set_attr "type" "alu")
+   (set_attr "mode" "QI")])
+
 ;; Alternative 1 is needed to work around LRA limitation, see PR82524.
 (define_insn_and_split "*subqi_ext<mode>_1"
   [(set (zero_extract:SWI248
@@ -11815,6 +11881,39 @@
    (set_attr "type" "alu")
    (set_attr "mode" "QI")])
 
+(define_insn_and_split "*<code>qi_ext2<mode>_0"
+  [(set (match_operand:QI 0 "register_operand" "=&Q")
+	(any_logic:QI
+	  (subreg:QI
+	    (match_operator:SWI248 3 "extract_operator"
+	      [(match_operand 1 "int248_register_operand" "Q")
+	       (const_int 8)
+	       (const_int 8)]) 0)
+	  (subreg:QI
+	    (match_operator:SWI248 4 "extract_operator"
+	      [(match_operand 2 "int248_register_operand" "Q")
+	       (const_int 8)
+	       (const_int 8)]) 0)))
+   (clobber (reg:CC FLAGS_REG))]
+  ""
+  "#"
+  "&& reload_completed"
+  [(set (match_dup 0)
+	(subreg:QI
+	  (match_op_dup 4
+	    [(match_dup 2) (const_int 8) (const_int 8)]) 0))
+   (parallel
+     [(set (match_dup 0)
+	   (any_logic:QI
+	     (subreg:QI
+	       (match_op_dup 3
+		 [(match_dup 1) (const_int 8) (const_int 8)]) 0)
+	   (match_dup 0)))
+      (clobber (reg:CC FLAGS_REG))])]
+  ""
+  [(set_attr "type" "alu")
+   (set_attr "mode" "QI")])
+
 (define_expand "andqi_ext_1"
   [(parallel
      [(set (zero_extract:HI (match_operand:HI 0 "register_operand")
diff --git a/gcc/testsuite/gcc.target/i386/pr78904-10.c b/gcc/testsuite/gcc.target/i386/pr78904-10.c
new file mode 100644
index 00000000000..079629150df
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78904-10.c
@@ -0,0 +1,47 @@
+/* PR target/78904 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -masm=att" } */
+/* { dg-additional-options "-mregparm=3" { target ia32 } } */
+/* { dg-final { scan-assembler-not "shr" } } */
+
+struct S1
+{
+  unsigned char pad1;
+  unsigned char val;
+  unsigned short pad2;
+};
+
+char test_and (struct S1 a, struct S1 b)
+{
+  return a.val & b.val;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]andb" } } */
+
+char test_or (struct S1 a, struct S1 b)
+{
+  return a.val | b.val;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]orb" } } */
+
+char test_xor (struct S1 a, struct S1 b)
+{
+  return a.val ^ b.val;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]xorb" } } */
+
+char test_add (struct S1 a, struct S1 b)
+{
+  return a.val + b.val;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]addb" } } */
+
+char test_sub (struct S1 a, struct S1 b)
+{
+  return a.val - b.val;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]subb" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr78904-10a.c b/gcc/testsuite/gcc.target/i386/pr78904-10a.c
new file mode 100644
index 00000000000..101402867b0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78904-10a.c
@@ -0,0 +1,46 @@
+/* PR target/78904 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -masm=att" } */
+/* { dg-additional-options "-mregparm=3" { target ia32 } } */
+/* { dg-final { scan-assembler-not "shr" } } */
+
+struct S1
+{
+  unsigned char pad1;
+  unsigned char val;
+};
+
+char test_and (struct S1 a, struct S1 b)
+{
+  return a.val & b.val;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]andb" } } */
+
+char test_or (struct S1 a, struct S1 b)
+{
+  return a.val | b.val;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]orb" } } */
+
+char test_xor (struct S1 a, struct S1 b)
+{
+  return a.val ^ b.val;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]xorb" } } */
+
+char test_add (struct S1 a, struct S1 b)
+{
+  return a.val + b.val;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]addb" } } */
+
+char test_sub (struct S1 a, struct S1 b)
+{
+  return a.val - b.val;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]subb" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr78904-10b.c b/gcc/testsuite/gcc.target/i386/pr78904-10b.c
new file mode 100644
index 00000000000..376acf81962
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78904-10b.c
@@ -0,0 +1,47 @@
+/* PR target/78904 */
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2 -masm=att" } */
+/* { dg-final { scan-assembler-not "shr" } } */
+
+struct S1
+{
+  unsigned char pad1;
+  unsigned char val;
+  unsigned short pad2;
+  unsigned int pad3;
+};
+
+char test_and (struct S1 a, struct S1 b)
+{
+  return a.val & b.val;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]andb" } } */
+
+char test_or (struct S1 a, struct S1 b)
+{
+  return a.val | b.val;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]orb" } } */
+
+char test_xor (struct S1 a, struct S1 b)
+{
+  return a.val ^ b.val;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]xorb" } } */
+
+char test_add (struct S1 a, struct S1 b)
+{
+  return a.val + b.val;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]addb" } } */
+
+char test_sub (struct S1 a, struct S1 b)
+{
+  return a.val - b.val;
+}
+
+/* { dg-final { scan-assembler "\[ \t\]subb" } } */

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2023-11-16 18:12 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-11-16 18:12 [gcc r14-5539] i386: Optimize QImode insn with high input registers Uros Bizjak

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).