re PR rtl-optimization/49095 (Horrible code generation for trivial decrement with...
authorJakub Jelinek <jakub@redhat.com>
Sun, 29 May 2011 18:51:48 +0000 (20:51 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Sun, 29 May 2011 18:51:48 +0000 (20:51 +0200)
PR rtl-optimization/49095
* config/i386/predicates.md (plusminuslogic_operator): New predicate.
* config/i386/i386.md: Add peepholes for mem {+,-,&,|,^}= x; mem != 0.

* gcc.target/i386/pr49095.c: New test.

From-SVN: r174413

gcc/ChangeLog
gcc/config/i386/i386.md
gcc/config/i386/predicates.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/i386/pr49095.c [new file with mode: 0644]

index 6f99232021e9dabb570363e6ab5b08ffa731ca89..eaa7f6438b9668bc7158620735fc794c2cf0689c 100644 (file)
@@ -1,3 +1,9 @@
+2011-05-29  Jakub Jelinek  <jakub@redhat.com>
+
+       PR rtl-optimization/49095
+       * config/i386/predicates.md (plusminuslogic_operator): New predicate.
+       * config/i386/i386.md: Add peepholes for mem {+,-,&,|,^}= x; mem != 0.
+
 2011-05-29  Richard Sandiford  <rdsandiford@googlemail.com>
 
        PR target/43995
index 2e7633dfc7de9afdf193b8def5c5837abfdeca75..73dc7e891ff4d31a6b497bd20dace646a356354b 100644 (file)
               (clobber (reg:CC FLAGS_REG))])
    (set (match_dup 0) (match_dup 2))])
 
+;; Attempt to use arith or logical operations with memory outputs with
+;; setting of flags.
+(define_peephole2
+  [(set (match_operand:SWI 0 "register_operand" "")
+       (match_operand:SWI 1 "memory_operand" ""))
+   (parallel [(set (match_dup 0)
+                  (match_operator:SWI 3 "plusminuslogic_operator"
+                    [(match_dup 0)
+                     (match_operand:SWI 2 "<nonmemory_operand>" "")]))
+             (clobber (reg:CC FLAGS_REG))])
+   (set (match_dup 1) (match_dup 0))
+   (set (reg FLAGS_REG) (compare (match_dup 0) (const_int 0)))]
+  "(TARGET_READ_MODIFY_WRITE || optimize_insn_for_size_p ())
+   && peep2_reg_dead_p (4, operands[0])
+   && !reg_overlap_mentioned_p (operands[0], operands[1])
+   && ix86_match_ccmode (peep2_next_insn (3),
+                        (GET_CODE (operands[3]) == PLUS
+                         || GET_CODE (operands[3]) == MINUS)
+                        ? CCGOCmode : CCNOmode)"
+  [(parallel [(set (match_dup 4) (match_dup 5))
+             (set (match_dup 1) (match_op_dup 3 [(match_dup 1)
+                                                 (match_dup 2)]))])]
+  "operands[4] = SET_DEST (PATTERN (peep2_next_insn (3)));
+   operands[5] = gen_rtx_fmt_ee (GET_CODE (operands[3]), <MODE>mode,
+                                copy_rtx (operands[1]),
+                                copy_rtx (operands[2]));
+   operands[5] = gen_rtx_COMPARE (GET_MODE (operands[4]),
+                                 operands[5], const0_rtx);")
+
+(define_peephole2
+  [(parallel [(set (match_operand:SWI 0 "register_operand" "")
+                  (match_operator:SWI 2 "plusminuslogic_operator"
+                    [(match_dup 0)
+                     (match_operand:SWI 1 "memory_operand" "")]))
+             (clobber (reg:CC FLAGS_REG))])
+   (set (match_dup 1) (match_dup 0))
+   (set (reg FLAGS_REG) (compare (match_dup 0) (const_int 0)))]
+  "(TARGET_READ_MODIFY_WRITE || optimize_insn_for_size_p ())
+   && GET_CODE (operands[2]) != MINUS
+   && peep2_reg_dead_p (3, operands[0])
+   && !reg_overlap_mentioned_p (operands[0], operands[1])
+   && ix86_match_ccmode (peep2_next_insn (2),
+                        GET_CODE (operands[2]) == PLUS
+                        ? CCGOCmode : CCNOmode)"
+  [(parallel [(set (match_dup 3) (match_dup 4))
+             (set (match_dup 1) (match_op_dup 2 [(match_dup 1)
+                                                 (match_dup 0)]))])]
+  "operands[3] = SET_DEST (PATTERN (peep2_next_insn (2)));
+   operands[4] = gen_rtx_fmt_ee (GET_CODE (operands[2]), <MODE>mode,
+                                copy_rtx (operands[1]),
+                                copy_rtx (operands[0]));
+   operands[4] = gen_rtx_COMPARE (GET_MODE (operands[3]),
+                                 operands[4], const0_rtx);")
+
+(define_peephole2
+  [(set (match_operand:SWI12 0 "register_operand" "")
+       (match_operand:SWI12 1 "memory_operand" ""))
+   (parallel [(set (match_operand:SI 4 "register_operand" "")
+                  (match_operator:SI 3 "plusminuslogic_operator"
+                    [(match_dup 4)
+                     (match_operand:SI 2 "nonmemory_operand" "")]))
+             (clobber (reg:CC FLAGS_REG))])
+   (set (match_dup 1) (match_dup 0))
+   (set (reg FLAGS_REG) (compare (match_dup 0) (const_int 0)))]
+  "(TARGET_READ_MODIFY_WRITE || optimize_insn_for_size_p ())
+   && REG_P (operands[0]) && REG_P (operands[4])
+   && REGNO (operands[0]) == REGNO (operands[4])
+   && peep2_reg_dead_p (4, operands[0])
+   && !reg_overlap_mentioned_p (operands[0], operands[1])
+   && ix86_match_ccmode (peep2_next_insn (3),
+                        (GET_CODE (operands[3]) == PLUS
+                         || GET_CODE (operands[3]) == MINUS)
+                        ? CCGOCmode : CCNOmode)"
+  [(parallel [(set (match_dup 4) (match_dup 5))
+             (set (match_dup 1) (match_dup 6))])]
+  "operands[2] = gen_lowpart (<MODE>mode, operands[2]);
+   operands[4] = SET_DEST (PATTERN (peep2_next_insn (3)));
+   operands[5] = gen_rtx_fmt_ee (GET_CODE (operands[3]), <MODE>mode,
+                                copy_rtx (operands[1]), operands[2]);
+   operands[5] = gen_rtx_COMPARE (GET_MODE (operands[4]),
+                                 operands[5], const0_rtx);
+   operands[6] = gen_rtx_fmt_ee (GET_CODE (operands[3]), <MODE>mode,
+                                copy_rtx (operands[1]),
+                                copy_rtx (operands[2]));")
+
 ;; Attempt to always use XOR for zeroing registers.
 (define_peephole2
   [(set (match_operand 0 "register_operand" "")
index 1471f5a22820cc9a545553e2481b93a988f1c8be..358d04f6532bc5c206173a7de96aa930044ef7c7 100644 (file)
@@ -1,5 +1,5 @@
 ;; Predicate definitions for IA-32 and x86-64.
-;; Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010
+;; Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
 ;; Free Software Foundation, Inc.
 ;;
 ;; This file is part of GCC.
 (define_predicate "div_operator"
   (match_code "div"))
 
+;; Return true if this is a plus, minus, and, ior or xor operation.
+(define_predicate "plusminuslogic_operator"
+  (match_code "plus,minus,and,ior,xor"))
+
 ;; Return true if this is a float extend operation.
 (define_predicate "float_operator"
   (match_code "float"))
index c416d1aea3086d4fa1a4cf27e366f87726afb991..0f2b1dc1fe2540fe3ac835c7fc5272454769a99c 100644 (file)
@@ -1,3 +1,8 @@
+2011-05-29  Jakub Jelinek  <jakub@redhat.com>
+
+       PR rtl-optimization/49095
+       * gcc.target/i386/pr49095.c: New test.
+
 2011-05-29  Tobias Burnus  <burnus@net-b.de>
 
        PR fortran/18918
diff --git a/gcc/testsuite/gcc.target/i386/pr49095.c b/gcc/testsuite/gcc.target/i386/pr49095.c
new file mode 100644 (file)
index 0000000..bc82020
--- /dev/null
@@ -0,0 +1,73 @@
+/* PR rtl-optimization/49095 */
+/* { dg-do compile } */
+/* { dg-options "-Os" } */
+/* { dg-options "-Os -mregparm=2" { target ilp32 } } */
+
+void foo (void *);
+
+int *
+f1 (int *x)
+{
+  if (!--*x)
+    foo (x);
+  return x;
+}
+
+int
+g1 (int x)
+{
+  if (!--x)
+    foo ((void *) 0);
+  return x;
+}
+
+#define F(T, OP, OPN) \
+T *                    \
+f##T##OPN (T *x, T y)  \
+{                      \
+  *x OP y;             \
+  if (!*x)             \
+    foo (x);           \
+  return x;            \
+}                      \
+                       \
+T                      \
+g##T##OPN (T x, T y)   \
+{                      \
+  x OP y;              \
+  if (!x)              \
+    foo ((void *) 0);  \
+  return x;            \
+}                      \
+                       \
+T *                    \
+h##T##OPN (T *x)       \
+{                      \
+  *x OP 24;            \
+  if (!*x)             \
+    foo (x);           \
+  return x;            \
+}                      \
+                       \
+T                      \
+i##T##OPN (T x, T y)   \
+{                      \
+  x OP 24;             \
+  if (!x)              \
+    foo ((void *) 0);  \
+  return x;            \
+}
+
+#define G(T) \
+F (T, +=, plus)                \
+F (T, -=, minus)       \
+F (T, &=, and)         \
+F (T, |=, or)          \
+F (T, ^=, xor)
+
+G (char)
+G (short)
+G (int)
+G (long)
+
+/* { dg-final { scan-assembler-not "test\[lq\]" } } */