Use add/sub/neg insns to eliminate compare/test insns on H8
authorJeff Law <law@redhat.com>
Wed, 2 Dec 2020 04:48:10 +0000 (21:48 -0700)
committerJeff Law <law@redhat.com>
Wed, 2 Dec 2020 04:49:10 +0000 (21:49 -0700)
gcc/

* config/h8300/addsub.md (addqi3_clobber_flags): Rename to
addqi3_flags and annotate with a <cczn> for define_subst.
(addhi3_h8sx_clobber_flags): Likewise.
(subqi3_clobber_flags, sub<mode>3_clobber_flags): Likewise.
(neg<mode2>_clobber_flags): Similarly.
(addsi3_clobber_flags): Similarly.  Update last argument to
output_plussi to distinguish when we need flags or do not need
flags.
(addhi3_clobber_flags): Similarly.  Twiddle code for cases
+-1, +-2 and +-4.
* config/h8300/h8300.md: Define iterators, mode attributes and
substitutions for use in compare/test elimination.
* config/h8300/jumpcall.md (branch, branch_1): Use H8cc mode
iterator to cover the different modes for the CC register.
(branch_1_false): Likewise.

gcc/testsuite
* gcc.target/h8300/add.c: New test.
* gcc.target/h8300/add-2.c: New test.
* gcc.target/h8300/add-3.c: New test.
* gcc.target/h8300/sub.c: New test.
* gcc.target/h8300/sub-2.c: New test.
* gcc.target/h8300/sub-3.c: New test.

gcc/config/h8300/addsub.md
gcc/config/h8300/h8300.md
gcc/config/h8300/jumpcall.md
gcc/testsuite/gcc.target/h8300/add-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/h8300/add-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/h8300/add.c [new file with mode: 0644]
gcc/testsuite/gcc.target/h8300/sub-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/h8300/sub-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/h8300/sub.c [new file with mode: 0644]

index d0877c008bf05203646a99c21c176128716c34b8..3585bffa9fc5808f517209d1cd701b823cf281dd 100644 (file)
@@ -19,7 +19,7 @@
   [(parallel [(set (match_dup 0) (plus:QI (match_dup 1) (match_dup 2)))
              (clobber (reg:CC CC_REG))])])
 
-(define_insn "*addqi3_clobber_flags"
+(define_insn "*addqi3_flags<cczn>"
   [(set (match_operand:QI 0 "h8300_dst_operand" "=rQ")
        (plus:QI (match_operand:QI 1 "h8300_dst_operand" "%0")
                 (match_operand:QI 2 "h8300_src_operand" "rQi")))
   [(parallel [(set (match_dup 0) (plus:HI (match_dup 1) (match_dup 2)))
              (clobber (reg:CC CC_REG))])])
 
-(define_insn "*addhi3_clobber_flags"
+(define_insn "*addhi3_flags<cczn>"
   [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r")
        (plus:HI (match_operand:HI 1 "register_operand" "%0,0,0,0,0")
-                (match_operand:HI 2 "h8300_src_operand" "L,N,J,n,r")))
+                (match_operand:HI 2 "h8300_src_operand" "M,O,J,n,r")))
    (clobber (reg:CC CC_REG))]
   "reload_completed && !TARGET_H8300SX"
-  "@
-   adds        %2,%S0
-   subs        %G2,%S0
-   add.b       %t2,%t0
-   add.w       %T2,%T0
-   add.w       %T2,%T0"
+  "*
+  {
+    switch (which_alternative)
+      {
+      case 0:
+       return \"inc %T2,%T0\";
+      case 1:
+       return \"dec %G2,%T0\";
+      case 2:
+       return \"add.b  %t2,%t0\";
+      case 3:
+       {
+         /* If the constant is 4 or -4 and we do not need the
+            flags, then we can use adds/subs which is two bytes
+            shorter.  */
+         rtx x = XVECEXP (PATTERN (insn), 0, 1);
+         bool clobber = GET_CODE (x) == CLOBBER;
+         if (clobber && INTVAL (operands[2]) == 4)
+           return \"adds       %2,%S0\";
+         if (clobber && INTVAL (operands[2]) == -4)
+           return \"subs       %G2,%S0\";
+         return \"add.w        %T2,%T0\";
+       }
+      case 4:
+       return \"add.w  %T2,%T0\";
+      default:
+       gcc_unreachable ();
+      }
+  }"
   [(set_attr "length" "2,2,2,4,2")])
 
 (define_insn_and_split "*addhi3_h8sx"
@@ -62,7 +85,7 @@
   [(parallel [(set (match_dup 0) (plus:HI (match_dup 1) (match_dup 2)))
              (clobber (reg:CC CC_REG))])])
 
-(define_insn "*addhi3_h8sx_clobber_flags"
+(define_insn "*addhi3_h8sx_flags<cczn>"
   [(set (match_operand:HI 0 "h8300_dst_operand" "=rU,rU,r,rQ")
        (plus:HI (match_operand:HI 1 "h8300_dst_operand" "%0,0,0,0")
                 (match_operand:HI 2 "h8300_src_operand" "P3>X,P3<X,J,rQi")))
   [(parallel [(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))
              (clobber (reg:CC CC_REG))])])
 
-(define_insn "*addsi_clobber_flags"
+(define_insn "*addsi_flags<cczn>"
   [(set (match_operand:SI 0 "h8300_dst_operand" "=rQ,rQ")
        (plus:SI (match_operand:SI 1 "h8300_dst_operand" "%0,0")
                 (match_operand:SI 2 "h8300_src_operand" "i,rQ")))
    (clobber (reg:CC CC_REG))]
   "reload_completed && h8300_operands_match_p (operands)"
 {
-  return output_plussi (operands, false);
+  rtx x = XVECEXP (PATTERN (insn), 0, 1);
+  return output_plussi (operands, GET_CODE (x) != CLOBBER);
 }
   [(set (attr "length")
        (symbol_ref "compute_plussi_length (operands, false)"))])
   [(parallel [(set (match_dup 0) (minus:QI (match_dup 1) (match_dup 2)))
              (clobber (reg:CC CC_REG))])])
 
-(define_insn "*subqi3_clobber_flags"
+(define_insn "*subqi3_flags<cczn>"
   [(set (match_operand:QI 0 "h8300_dst_operand" "=rQ")
        (minus:QI (match_operand:QI 1 "h8300_dst_operand" "0")
                  (match_operand:QI 2 "h8300_dst_operand" "rQ")))
   [(parallel [(set (match_dup 0) (minus:HSI (match_dup 1) (match_dup 2)))
              (clobber (reg:CC CC_REG))])])
 
-(define_insn "*sub<mode>3_clobber_flags"
+(define_insn "*sub<mode>3_flags<cczn>"
   [(set (match_operand:HSI 0 "h8300_dst_operand" "=rQ,rQ")
        (minus:HSI (match_operand:HSI 1 "h8300_dst_operand" "0,0")
                   (match_operand:HSI 2 "h8300_src_operand" "rQ,i")))
   [(parallel [(set (match_dup 0) (neg:QHSI (match_dup 1)))
              (clobber (reg:CC CC_REG))])])
 
-(define_insn "*neg<mode>2_clobber_flags"
+(define_insn "*neg<mode>2_flags<cczn>"
   [(set (match_operand:QHSI 0 "h8300_dst_operand" "=rQ")
        (neg:QHSI (match_operand:QHSI 1 "h8300_dst_operand" "0")))
    (clobber (reg:CC CC_REG))]
index 7c9cc324f39eaa15417715d11f58f84f5fd69731..932f74eb88fec9254ad821cbf44cfcd8e618025f 100644 (file)
 (define_attr "old_cc" "none,none_0hit,set_znv,set_zn,compare,clobber"
   (const_string "clobber"))
 
+;; So the idea here is to define iterators and substitutions so that we
+;; can easily modify the patterns with CC clobbers into a pattern
+;; which sets appropriate condition codes
+
+;; The modes we're supporting.  This is used when we want to generate
+;; multiple patterns where only the mode differs from a single template
+(define_mode_iterator H8cc [CC CCZN])
+
+;; This is used to generate multiple define_substs from a single
+;; template for the different variants we might have.
+(define_mode_attr cc [(CC "cc") (CCZN "cczn")])
+
+;; The primary substitution pattern.  <cc> is used to create multiple
+;; substitutions based on the CC bits that are set.
+;;
+;; The mode iterator sets the actual mode on the condition code
+;; REG expression.
+(define_subst "subst_<cc>"
+  [(set (match_operand 0 "")
+       (match_operand 1 ""))
+   (clobber (reg:CC CC_REG))]
+  ""
+  [(set (reg:H8cc CC_REG)
+       (compare:H8cc (match_dup 1) (const_int 0)))
+   (set (match_dup 0) (match_dup 1))])
+
+
+;; So when we see <cc> or <cczn> in a define_insn pattern, we'll
+;; apply the subst_cczn or subset_cc define_subst to generate a
+;; new pattern that compare-elim can use
+(define_subst_attr "cczn" "subst_cczn" "" "_cczn")
+(define_subst_attr "cc" "subst_cc" "" "_cc")
+
 ;; Type of delay slot.  NONE means the instruction has no delay slot.
 ;; JUMP means it is an unconditional jump that (if short enough)
 ;; could be implemented using bra/s.
index c07dbaf999c105dc6da936593c03760949644cb6..49d1e4312ca155ee711367bcb21375568d68ce26 100644 (file)
   ""
   "#"
   "reload_completed"
-  [(set (reg:CC CC_REG)
-       (compare:CC (match_dup 1) (match_dup 2)))
+  [(set (reg:H8cc CC_REG)
+       (compare:H8cc (match_dup 1) (match_dup 2)))
    (set (pc)
        (if_then_else (match_op_dup 0
-                      [(reg:CC CC_REG) (const_int 0)])
+                      [(reg:H8cc CC_REG) (const_int 0)])
                      (label_ref (match_dup 3)) (pc)))]
   "")
 
 (define_insn "*branch_1"
   [(set (pc)
        (if_then_else (match_operator 1 "comparison_operator"
-                      [(reg:CC CC_REG) (const_int 0)])
+                      [(reg:H8cc CC_REG) (const_int 0)])
                      (label_ref (match_operand 0 "" ""))
                      (pc)))]
   "reload_completed"
@@ -52,7 +52,7 @@
 (define_insn "*branch_1_false"
   [(set (pc)
        (if_then_else (match_operator 1 "comparison_operator"
-                      [(reg:CC CC_REG) (const_int 0)])
+                      [(reg:H8cc CC_REG) (const_int 0)])
                      (pc)
                      (label_ref (match_operand 0 "" ""))))]
   "reload_completed"
diff --git a/gcc/testsuite/gcc.target/h8300/add-2.c b/gcc/testsuite/gcc.target/h8300/add-2.c
new file mode 100644 (file)
index 0000000..27f9b2f
--- /dev/null
@@ -0,0 +1,5 @@
+/* { dg-do compile }  */
+/* { dg-options "-ms -mint32 -O2" }  */
+/* { dg-final { scan-assembler-not "cmp" } }  */
+
+#include "add.c"
diff --git a/gcc/testsuite/gcc.target/h8300/add-3.c b/gcc/testsuite/gcc.target/h8300/add-3.c
new file mode 100644 (file)
index 0000000..20de647
--- /dev/null
@@ -0,0 +1,5 @@
+/* { dg-do compile }  */
+/* { dg-options "-msx -mint32 -O2" }  */
+/* { dg-final { scan-assembler-not "cmp" } }  */
+
+#include "add.c"
diff --git a/gcc/testsuite/gcc.target/h8300/add.c b/gcc/testsuite/gcc.target/h8300/add.c
new file mode 100644 (file)
index 0000000..ebeea57
--- /dev/null
@@ -0,0 +1,118 @@
+/* { dg-do compile }  */
+/* { dg-options "-mh -mint32 -O2" }  */
+/* { dg-final { scan-assembler-not "cmp" } }  */
+
+typedef unsigned char uchar;
+typedef signed char schar;
+typedef unsigned short ushort;
+typedef unsigned long ulong;
+
+volatile void abort (void);
+
+
+#define ADD(T)\
+T addE##T (T x, T y) { T t = x + y ; if (t == 0) abort (); return t; } \
+T addNE##T (T x, T y) { T t = x + y ; if (t != 0) return t; abort (); } \
+T addGE##T (T x, T y) { T t = x + y ; if (t >= 0) abort (); return t; } \
+T addLT##T (T x, T y) { T t = x + y ; if (t < 0) abort (); return t; }
+
+#define ADDC(T,N)\
+T addEQ##N##T (T a) { T t = a + N; if (t == 0) abort (); return t; } \
+T addNE##N##T (T a) { T t = a + N; if (t != 0) return t; abort (); } \
+T addGE##N##T (T a) { T t = a + N; if (t >= 0) abort (); return t; } \
+T addLT##N##T (T a) { T t = a + N; if (t < 0) abort (); return t; }
+
+#define ADDNC(T,N)\
+T addEQN##N##T (T a) { T t = a + -N; if (t == 0) abort (); return t; } \
+T addNEN##N##T (T a) { T t = a + -N; if (t != 0) return t; abort (); } \
+T addGEN##N##T (T a) { T t = a + -N; if (t >= 0) abort (); return t; } \
+T addLTN##N##T (T a) { T t = a + -N; if (t < 0) abort (); return t; }
+
+
+ADD (schar)
+ADD (short)
+ADD (long)
+ADD (uchar)
+ADD (ushort)
+ADD (ulong)
+
+
+
+ADDC (schar,1)
+ADDC (schar,2)
+ADDC (schar,3)
+ADDC (schar,4)
+ADDC (schar,6)
+ADDC (schar,8)
+ADDNC (schar,1)
+ADDNC (schar,2)
+ADDNC (schar,3)
+ADDNC (schar,4)
+ADDNC (schar,6)
+ADDNC (schar,8)
+
+ADDC (uchar,1)
+ADDC (uchar,2)
+ADDC (uchar,3)
+ADDC (uchar,4)
+ADDC (uchar,6)
+ADDC (uchar,8)
+ADDNC (uchar,1)
+ADDNC (uchar,2)
+ADDNC (uchar,3)
+ADDNC (uchar,4)
+ADDNC (uchar,6)
+ADDNC (uchar,8)
+
+ADDC (short,1)
+ADDC (short,2)
+ADDC (short,3)
+ADDC (short,4)
+ADDC (short,6)
+ADDC (short,8)
+ADDNC (short,1)
+ADDNC (short,2)
+ADDNC (short,3)
+ADDNC (short,4)
+ADDNC (short,6)
+ADDNC (short,8)
+
+ADDC (ushort,1)
+ADDC (ushort,2)
+ADDC (ushort,3)
+ADDC (ushort,4)
+ADDC (ushort,6)
+ADDC (ushort,8)
+ADDNC (ushort,1)
+ADDNC (ushort,2)
+ADDNC (ushort,3)
+ADDNC (ushort,4)
+ADDNC (ushort,6)
+ADDNC (ushort,8)
+
+ADDC (long,1)
+ADDC (long,2)
+ADDC (long,3)
+ADDC (long,4)
+ADDC (long,6)
+ADDC (long,8)
+ADDNC (long,1)
+ADDNC (long,2)
+ADDNC (long,3)
+ADDNC (long,4)
+ADDNC (long,6)
+ADDNC (long,8)
+
+ADDC (ulong,1)
+ADDC (ulong,2)
+ADDC (ulong,3)
+ADDC (ulong,4)
+ADDC (ulong,6)
+ADDC (ulong,8)
+ADDNC (ulong,1)
+ADDNC (ulong,2)
+ADDNC (ulong,3)
+ADDNC (ulong,4)
+ADDNC (ulong,6)
+ADDNC (ulong,8)
+
diff --git a/gcc/testsuite/gcc.target/h8300/sub-2.c b/gcc/testsuite/gcc.target/h8300/sub-2.c
new file mode 100644 (file)
index 0000000..c2914bd
--- /dev/null
@@ -0,0 +1,5 @@
+/* { dg-do compile }  */
+/* { dg-options "-ms -mint32 -O2" }  */
+/* { dg-final { scan-assembler-not "cmp" } }  */
+
+#include "sub.c"
diff --git a/gcc/testsuite/gcc.target/h8300/sub-3.c b/gcc/testsuite/gcc.target/h8300/sub-3.c
new file mode 100644 (file)
index 0000000..72bcf04
--- /dev/null
@@ -0,0 +1,5 @@
+/* { dg-do compile }  */
+/* { dg-options "-msx -mint32 -O2" }  */
+/* { dg-final { scan-assembler-not "cmp" } }  */
+
+#include "sub.c"
diff --git a/gcc/testsuite/gcc.target/h8300/sub.c b/gcc/testsuite/gcc.target/h8300/sub.c
new file mode 100644 (file)
index 0000000..66b63ab
--- /dev/null
@@ -0,0 +1,118 @@
+/* { dg-do compile }  */
+/* { dg-options "-mh -mint32 -O2" }  */
+/* { dg-final { scan-assembler-not "cmp" } }  */
+
+typedef unsigned char uchar;
+typedef signed char schar;
+typedef unsigned short ushort;
+typedef unsigned long ulong;
+
+volatile void abort (void);
+
+
+#define SUB(T)\
+T subE##T (T x, T y) { T t = x - y ; if (t == 0) abort (); return t; } \
+T subNE##T (T x, T y) { T t = x - y ; if (t != 0) return t; abort (); } \
+T subGE##T (T x, T y) { T t = x - y ; if (t >= 0) abort (); return t; } \
+T subLT##T (T x, T y) { T t = x - y ; if (t < 0) abort (); return t; }
+
+#define SUBC(T,N)\
+T subEQ##N##T (T a) { T t = a - N; if (t == 0) abort (); return t; } \
+T subNE##N##T (T a) { T t = a - N; if (t != 0) return t; abort (); } \
+T subGE##N##T (T a) { T t = a - N; if (t >= 0) abort (); return t; } \
+T subLT##N##T (T a) { T t = a - N; if (t < 0) abort (); return t; }
+
+#define SUBNC(T,N)\
+T subEQN##N##T (T a) { T t = a - -N; if (t == 0) abort (); return t; } \
+T subNEN##N##T (T a) { T t = a - -N; if (t != 0) return t; abort (); } \
+T subGEN##N##T (T a) { T t = a - -N; if (t >= 0) abort (); return t; } \
+T subLTN##N##T (T a) { T t = a - -N; if (t < 0) abort (); return t; }
+
+
+SUB (schar)
+SUB (short)
+SUB (long)
+SUB (uchar)
+SUB (ushort)
+SUB (ulong)
+
+
+
+SUBC (schar,1)
+SUBC (schar,2)
+SUBC (schar,3)
+SUBC (schar,4)
+SUBC (schar,6)
+SUBC (schar,8)
+SUBNC (schar,1)
+SUBNC (schar,2)
+SUBNC (schar,3)
+SUBNC (schar,4)
+SUBNC (schar,6)
+SUBNC (schar,8)
+
+SUBC (uchar,1)
+SUBC (uchar,2)
+SUBC (uchar,3)
+SUBC (uchar,4)
+SUBC (uchar,6)
+SUBC (uchar,8)
+SUBNC (uchar,1)
+SUBNC (uchar,2)
+SUBNC (uchar,3)
+SUBNC (uchar,4)
+SUBNC (uchar,6)
+SUBNC (uchar,8)
+
+SUBC (short,1)
+SUBC (short,2)
+SUBC (short,3)
+SUBC (short,4)
+SUBC (short,6)
+SUBC (short,8)
+SUBNC (short,1)
+SUBNC (short,2)
+SUBNC (short,3)
+SUBNC (short,4)
+SUBNC (short,6)
+SUBNC (short,8)
+
+SUBC (ushort,1)
+SUBC (ushort,2)
+SUBC (ushort,3)
+SUBC (ushort,4)
+SUBC (ushort,6)
+SUBC (ushort,8)
+SUBNC (ushort,1)
+SUBNC (ushort,2)
+SUBNC (ushort,3)
+SUBNC (ushort,4)
+SUBNC (ushort,6)
+SUBNC (ushort,8)
+
+SUBC (long,1)
+SUBC (long,2)
+SUBC (long,3)
+SUBC (long,4)
+SUBC (long,6)
+SUBC (long,8)
+SUBNC (long,1)
+SUBNC (long,2)
+SUBNC (long,3)
+SUBNC (long,4)
+SUBNC (long,6)
+SUBNC (long,8)
+
+SUBC (ulong,1)
+SUBC (ulong,2)
+SUBC (ulong,3)
+SUBC (ulong,4)
+SUBC (ulong,6)
+SUBC (ulong,8)
+SUBNC (ulong,1)
+SUBNC (ulong,2)
+SUBNC (ulong,3)
+SUBNC (ulong,4)
+SUBNC (ulong,6)
+SUBNC (ulong,8)
+