@@ -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")))
@@ -38,18 +38,41 @@
[(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")))
@@ -98,14 +121,15 @@
[(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)"))])
@@ -130,7 +154,7 @@
[(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")))
@@ -149,7 +173,7 @@
[(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")))
@@ -183,7 +207,7 @@
[(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))]
@@ -134,6 +134,39 @@
(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.
@@ -23,18 +23,18 @@
""
"#"
"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"
new file mode 100644
@@ -0,0 +1,5 @@
+/* { dg-do compile } */
+/* { dg-options "-ms -mint32 -O2" } */
+/* { dg-final { scan-assembler-not "cmp" } } */
+
+#include "add.c"
new file mode 100644
@@ -0,0 +1,5 @@
+/* { dg-do compile } */
+/* { dg-options "-msx -mint32 -O2" } */
+/* { dg-final { scan-assembler-not "cmp" } } */
+
+#include "add.c"
new file mode 100644
@@ -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)
+
new file mode 100644
@@ -0,0 +1,5 @@
+/* { dg-do compile } */
+/* { dg-options "-ms -mint32 -O2" } */
+/* { dg-final { scan-assembler-not "cmp" } } */
+
+#include "sub.c"
new file mode 100644
@@ -0,0 +1,5 @@
+/* { dg-do compile } */
+/* { dg-options "-msx -mint32 -O2" } */
+/* { dg-final { scan-assembler-not "cmp" } } */
+
+#include "sub.c"
new file mode 100644
@@ -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)
+