OSDN Git Service

* h8300/h8300.h (SP_AND_G_REGS): Renamed from SP_AND_G_REG.
authordje <dje@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 11 Mar 1996 21:05:49 +0000 (21:05 +0000)
committerdje <dje@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 11 Mar 1996 21:05:49 +0000 (21:05 +0000)
(CC_DONE_CBIT): Delete.
(CC_OVERFLOW_0,CC_OVERFLOW_UNUSABLE,CC_NO_CARRY): Define.
* h8300/h8300.c (cond_string): Delete CC_DONE_CBIT handling.
(notice_update_cc): Delete CC_CBIT, CC_WHOOPS.  Add CC_SET_ZN_C0.
(restore_compare_p): New function.
(shift_one): Use shll instead of shal so overflow bit is usable.
Set cc_valid bits to cc_status.flags values.
(emit_a_shift): Set cc_status.flags.
* h8300/h8300.md (attr cc): Delete whoops,cbit.  Add set_zn_c0.
(all patterns) Update cc attr setting.
(tstqi,tsthi,tstsi): Delete CC_DONE_CBIT handling.
(addhi3,subhi3): Change define_expand to define_insn.
(branch_true,branch_false): Check if compare needs to be restored.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@11514 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/config/h8300/h8300.c
gcc/config/h8300/h8300.h
gcc/config/h8300/h8300.md

index 5d2f2b4..cadff01 100644 (file)
@@ -757,12 +757,8 @@ cond_string (code)
   switch (code)
     {
     case NE:
-      if (cc_prev_status.flags & CC_DONE_CBIT)
-       return "cs";
       return "ne";
     case EQ:
-      if (cc_prev_status.flags & CC_DONE_CBIT)
-       return "cc";
       return "eq";
     case GE:
       return "ge";
@@ -800,8 +796,7 @@ print_operand (file, x, code)
   /* This is used for communication between the 'P' and 'U' codes.  */
   static char *last_p;
 
-  /* This is used for communication between the 'Z' and 'Y' codes.  */
-  /* ??? 'V' and 'W' use it too.  */
+  /* This is used for communication between codes V,W,Z and Y.  */
   static int bitint;
 
   switch (code)
@@ -1081,7 +1076,7 @@ print_operand (file, x, code)
          switch (GET_MODE (x))
            {
            case QImode:
-#if 0                          /* Is it asm ("mov.b %0,r2l", ...) */
+#if 0 /* Is it asm ("mov.b %0,r2l", ...) */
              fprintf (file, "%s", byte_reg (x, 0));
 #else /* ... or is it asm ("mov.b %0l,r2l", ...) */
              fprintf (file, "%s", names_big[REGNO (x)]);
@@ -1271,49 +1266,89 @@ notice_update_cc (body, insn)
   switch (get_attr_cc (insn))
     {
     case CC_NONE:
-      /* Insn does not affect the CC at all */
+      /* Insn does not affect CC at all.  */
       break;
 
     case CC_NONE_0HIT:
-      /* Insn does not change the CC, but the 0't operand has been changed.  */
-
+      /* Insn does not change CC, but the 0'th operand has been changed.  */
       if (cc_status.value1 != 0
          && reg_overlap_mentioned_p (recog_operand[0], cc_status.value1))
        cc_status.value1 = 0;
-
+      /* ??? Is value2 ever set?.  */
       if (cc_status.value2 != 0
          && reg_overlap_mentioned_p (recog_operand[0], cc_status.value2))
        cc_status.value2 = 0;
-
       break;
 
     case CC_SET:
-      /* Insn sets CC to recog_operand[0], but overflow is impossible.  */
+      /* Insn sets the Z,N flags of CC to recog_operand[0].
+        V is always set to 0.  C may or may not be set to 0 but that's ok
+        because alter_cond will change tests to use EQ/NE.  */
       CC_STATUS_INIT;
-      cc_status.flags |= CC_NO_OVERFLOW;
+      cc_status.flags |= CC_OVERFLOW_0 | CC_NO_CARRY;
       cc_status.value1 = recog_operand[0];
       break;
 
-    case CC_COMPARE:
-      /* The insn is a compare instruction */
+    case CC_SET_ZN_C0:
+      /* Insn sets the Z,N flags of CC to recog_operand[0].
+        The V flag is unusable.  The C flag may or may not be known but
+        that's ok because alter_cond will change tests to use EQ/NE.  */
       CC_STATUS_INIT;
-      cc_status.value1 = SET_SRC (body);
+      cc_status.flags |= CC_OVERFLOW_UNUSABLE | CC_NO_CARRY;
+      cc_status.value1 = recog_operand[0];
       break;
 
-    case CC_CBIT:
+    case CC_COMPARE:
+      /* The insn is a compare instruction.  */
       CC_STATUS_INIT;
-      cc_status.flags |= CC_DONE_CBIT;
-      cc_status.value1 = 0;
+      cc_status.value1 = SET_SRC (body);
       break;
 
-    case CC_WHOOPS:
     case CC_CLOBBER:
-      /* Insn clobbers CC. */
+      /* Insn doesn't leave CC in a usable state.  */
       CC_STATUS_INIT;
       break;
     }
 }
 
+/* Return 1 if a previous compare needs to be re-issued.  This will happen
+   if the compare was deleted because the previous insn set it, but the
+   branch needs CC flags not set.
+
+   OP is the comparison being performed.  */
+
+int
+restore_compare_p (op)
+     rtx op;
+{
+  switch (GET_CODE (op))
+    {
+    case EQ:
+    case NE:
+      break;
+    case LT:
+    case LE:
+    case GT:
+    case GE:
+      if (cc_status.flags & CC_OVERFLOW_UNUSABLE)
+       return 1;
+      break;
+    case LTU:
+    case LEU:
+    case GTU:
+    case GEU:
+      /* If the carry flag isn't usable, the test should have been changed
+        by alter_cond.  */
+      if (cc_status.flags & CC_NO_CARRY)
+       abort ();
+      break;
+    default:
+      abort ();
+    }
+
+  return 0;
+}
+
 /* Recognize valid operators for bit instructions */
 
 int
@@ -1486,8 +1521,9 @@ enum shift_mode
     QIshift, HIshift, SIshift
   };
 
-/* For single bit shift insns, record assembler and whether the condition code
-   is valid afterwards.  */
+/* For single bit shift insns, record assembler and what bits of the
+   condition code are valid afterwards (represented as various CC_FOO
+   bits, 0 means CC isn't left in a usable state).  */
 
 struct shift_insn
 {
@@ -1507,19 +1543,19 @@ static const struct shift_insn shift_one[2][3][3] =
   {
 /* SHIFT_ASHIFT */
     {
-      { "shal %X0", 1 },
-      { "add.w %T0,%T0\t; shal.w", 1 },
+      { "shll %X0", CC_OVERFLOW_0 | CC_NO_CARRY },
+      { "add.w %T0,%T0\t; shal.w", CC_OVERFLOW_UNUSABLE | CC_NO_CARRY },
       { "add.w %f0,%f0\t; shal.l\n\taddx %y0,%y0\n\taddx %z0,%z0\t; end shal.l", 0 }
     },
 /* SHIFT_LSHIFTRT */
     {
-      { "shlr %X0", 1 },
+      { "shlr %X0", CC_OVERFLOW_0 | CC_NO_CARRY },
       { "shlr %t0\t; shlr.w\n\trotxr %s0\t; end shlr.w", 0 },
       { "shlr %z0\t; shlr.l\n\trotxr %y0\n\trotxr %x0\n\trotxr %w0\t; end shlr.l", 0 }
     },
 /* SHIFT_ASHIFTRT */
     {
-      { "shar %X0", 1 },
+      { "shar %X0", CC_OVERFLOW_UNUSABLE | CC_NO_CARRY },
       { "shar %t0\t; shar.w\n\trotxr %s0\t; end shar.w", 0 },
       { "shar %z0\t; shar.l\n\trotxr %y0\n\trotxr %x0\n\trotxr %w0\t; end shar.l", 0 }
     }
@@ -1528,21 +1564,21 @@ static const struct shift_insn shift_one[2][3][3] =
   {
 /* SHIFT_ASHIFT */
     {
-      { "shal.b %X0", 1 },
-      { "shal.w %T0", 1 },
-      { "shal.l %S0", 1 }
+      { "shll.b %X0", CC_OVERFLOW_0 | CC_NO_CARRY },
+      { "shll.w %T0", CC_OVERFLOW_0 | CC_NO_CARRY },
+      { "shll.l %S0", CC_OVERFLOW_0 | CC_NO_CARRY }
     },
 /* SHIFT_LSHIFTRT */
     {
-      { "shlr.b %X0", 1 },
-      { "shlr.w %T0", 1 },
-      { "shlr.l %S0", 1 }
+      { "shlr.b %X0", CC_OVERFLOW_0 | CC_NO_CARRY },
+      { "shlr.w %T0", CC_OVERFLOW_0 | CC_NO_CARRY },
+      { "shlr.l %S0", CC_OVERFLOW_0 | CC_NO_CARRY }
     },
 /* SHIFT_ASHIFTRT */
     {
-      { "shar.b %X0", 1 },
-      { "shar.w %T0", 1 },
-      { "shar.l %S0", 1 }
+      { "shar.b %X0", CC_OVERFLOW_UNUSABLE | CC_NO_CARRY },
+      { "shar.w %T0", CC_OVERFLOW_UNUSABLE | CC_NO_CARRY },
+      { "shar.l %S0", CC_OVERFLOW_UNUSABLE | CC_NO_CARRY }
     }
   }
 };
@@ -1911,7 +1947,10 @@ emit_a_shift (insn, operands)
          while (--n >= 0)
            output_asm_insn (assembler, operands);
          if (cc_valid)
-           cc_status.value1 = operands[0];
+           {
+             cc_status.value1 = operands[0];
+             cc_status.flags |= cc_valid;
+           }
          return "";
        case SHIFT_ROT_AND:
          {
@@ -1934,6 +1973,7 @@ emit_a_shift (insn, operands)
                    sprintf (insn_buf, "and #%d,%%X0\t; end shift %d via rotate+and",
                             mask, n);
                    cc_status.value1 = operands[0];
+                   cc_status.flags |= CC_OVERFLOW_0 | CC_NO_CARRY;
                    break;
                  case HImode:
                    sprintf (insn_buf, "and #%d,%%s0\n\tand #%d,%%t0\t; end shift %d via rotate+and",
@@ -1949,6 +1989,7 @@ emit_a_shift (insn, operands)
                         "bwl"[shift_mode], mask,
                         mode == QImode ? 'X' : mode == HImode ? 'T' : 'S');
                cc_status.value1 = operands[0];
+               cc_status.flags |= CC_OVERFLOW_0 | CC_NO_CARRY;
              }
            output_asm_insn (insn_buf, operands);
            return "";
index f219575..0babf4a 100644 (file)
@@ -322,14 +322,18 @@ do {                              \
 /* The h8 has only one kind of register, but we mustn't do byte by
    byte operations on the sp, so we keep it as a different class */
 
-enum reg_class { NO_REGS,  LONG_REGS, GENERAL_REGS, SP_REG, SP_AND_G_REG, ALL_REGS, LIM_REG_CLASSES };
+enum reg_class {
+  NO_REGS, LONG_REGS, GENERAL_REGS, SP_REG, SP_AND_G_REGS,
+  ALL_REGS, LIM_REG_CLASSES
+};
 
 #define N_REG_CLASSES (int) LIM_REG_CLASSES
 
 /* Give names of register classes as strings for dump file.   */
 
 #define REG_CLASS_NAMES \
- {"NO_REGS",  "LONG_REGS",  "GENERAL_REGS", "SP_REG", "SP_AND_G_REG", "ALL_REGS", "LIM_REGS" }
+{ "NO_REGS", "LONG_REGS", "GENERAL_REGS", "SP_REG", "SP_AND_G_REGS", \
+  "ALL_REGS", "LIM_REGS" }
 
 /* Define which registers fit in which classes.
    This is an initializer for a vector of HARD_REG_SET
@@ -340,7 +344,7 @@ enum reg_class { NO_REGS,  LONG_REGS, GENERAL_REGS, SP_REG, SP_AND_G_REG, ALL_RE
    0x07f,               /* LONG_REGS    */      \
    0x07f,              /* GENERAL_REGS */      \
    0x080,              /* SP_REG       */      \
-   0x0ff,              /* SP_AND_G_REG */      \
+   0x0ff,              /* SP_AND_G_REGS */     \
    0x1ff,              /* ALL_REGS     */      \
 }
 
@@ -971,14 +975,18 @@ extern int current_function_anonymous_args;
    Do not alter them if the instruction would not alter the cc's.  */
 
 #define NOTICE_UPDATE_CC(EXP, INSN) notice_update_cc(EXP, INSN)
-#define CC_DONE_CBIT 0400
 
-#define OUTPUT_JUMP(NORMAL, FLOAT, NO_OV) \
-{                                      \
-  if (cc_status.flags & CC_NO_OVERFLOW)        \
-    return NO_OV;                      \
-  return NORMAL;                       \
-}
+/* The mov,and,or,xor insns always set V to 0.  */
+#define CC_OVERFLOW_0 0400
+/* The add insns don't set overflow in a usable way.  */
+#define CC_OVERFLOW_UNUSABLE 01000
+/* The mov,and,or,xor insns don't set carry.  That's ok though as the
+   Z bit is all we need when doing unsigned comparisons on the result of
+   these insns (since they're always with 0).  However, conditions.h has
+   CC_NO_OVERFLOW defined for this purpose.  Rename it to something more
+   understandable.  */
+#define CC_NO_CARRY CC_NO_OVERFLOW
+/* ??? Use CC_Z_IN_NOT_C for bld insns?  */
 \f
 /* Control the assembler format that we output.  */
 
index 6ad8616..a68d54c 100644 (file)
@@ -1,5 +1,5 @@
 ;; GCC machine description for Hitachi H8/300
-;; Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+;; Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
 
 ;;   Contributed by Steve Chamberlain (sac@cygnus.com),
 ;;   Jim Wilson (wilson@cygnus.com), and Doug Evans (dje@cygnus.com).
@@ -21,7 +21,6 @@
 ;; the Free Software Foundation, 59 Temple Place - Suite 330,
 ;; Boston, MA 02111-1307, USA.
 
-
 ;; The original PO technology requires these to be ordered by speed,
 ;; so that assigner will pick the fastest.
 
         (eq_attr "type" "call")        (const_int 4)]
        (const_int 200)))
 
-(define_attr "cc" "none,clobber,none_0hit,set,compare,whoops,cbit" 
-  (const_string "whoops"))
-
+;; Condition code settings.
+;; none - insn does not affect cc
+;; none_0hit - insn does not affect cc but it does modify operand 0
+;;     This attribute is used to keep track of when operand 0 changes.
+;;     See the description of NOTICE_UPDATE_CC for more info.
+;; set - insn sets flags z,n.  v,c are set to 0.
+;;     (c may not really be set to 0 but that's ok, we don't need it anyway).
+;; set_zn_c0 - insn sets z,n to usable values.  v is unknown.  c may or may not
+;;     be known (if it isn't that's ok, we don't need it anyway).
+;; compare - compare instruction
+;; clobber - value of cc is unknown
+(define_attr "cc" "none,none_0hit,set,set_zn_c0,compare,clobber"
+  (const_string "clobber"))
+\f
 ;; ----------------------------------------------------------------------
 ;; MOVE INSTRUCTIONS
 ;; ----------------------------------------------------------------------
    (set (attr "length") (if_then_else (eq_attr "cpu" "h8300") (const_int 2) (const_int 4)))
    (set_attr "cc" "set")])
 
+;; ??? Use of the `c' constraint doesn't seem right.
 (define_insn "movqi_internal"
   [(set (match_operand:QI 0 "general_operand_dst" "=r,r,r,o,<,r")
        (match_operand:QI 1 "general_operand_src" "I,r>,io,r,r,c"))]
-  "register_operand (operands[0],QImode) || register_operand (operands[1], QImode)"
+  "register_operand (operands[0],QImode)
+   || register_operand (operands[1], QImode)"
   "@
    sub.b       %X0,%X0
    mov.b       %X1,%X0
       (if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8))
       (if_then_else (eq_attr "cpu" "h8300") (const_int 2) (const_int 4))
       (const_int 4)])
-   (set_attr "cc" "set,set,set,set,set,none")])
+   (set_attr "cc" "set_zn_c0,set,set,set,set,clobber")])
 
 (define_expand "movqi"
   [(set (match_operand:QI 0 "general_operand_dst" "")
       (if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8))
       (if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8))
       (if_then_else (eq_attr "cpu" "h8300") (const_int 2) (const_int 4))])
-   (set_attr "cc" "set")])
+   (set_attr "cc" "set_zn_c0,set,set,set,set")])
    
 ;; movhi
 
       (if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8))
       (if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8))
       (if_then_else (eq_attr "cpu" "h8300") (const_int 2) (const_int 4))])
-   (set_attr "cc" "set")])
+   (set_attr "cc" "set_zn_c0,set,set,set,set")])
 
 (define_expand "movhi"
   [(set (match_operand:HI 0 "general_operand_dst" "")
       (if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8))
       (if_then_else (eq_attr "cpu" "h8300") (const_int 4) (const_int 8))
       (if_then_else (eq_attr "cpu" "h8300") (const_int 2) (const_int 4))])
-   (set_attr "cc" "set")])
+   (set_attr "cc" "set_zn_c0,set,set,set,set")])
 
 ;; movsi
 
    mov.l       %S1,%S0"
   [(set_attr "type" "move")
    (set_attr "length" "2,2,8,8,4,4")
-   (set_attr "cc" "set")])
+   (set_attr "cc" "set_zn_c0,set,set,set,set,set")])
 
 (define_insn "movsf_h8300h"
   [(set (match_operand:SF 0 "general_operand_dst" "=r,r,r,o,<,r")
    mov.l       %S1,%S0"
   [(set_attr "type" "move")
    (set_attr "length" "2,2,8,8,4,4")
-   (set_attr "cc" "set")])
-
+   (set_attr "cc" "set_zn_c0,set,set,set,set,set")])
+\f
 ;; ----------------------------------------------------------------------
 ;; TEST INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 (define_insn "tstqi"
   [(set (cc0) (match_operand:QI 0 "register_operand" "ra"))]
   ""
-  "*
-{
-  /* ??? I don't think this is right.  --Jim */
-  if (cc_prev_status.flags & CC_DONE_CBIT)
-    return \"btst      #0,%X0\";
-  else
-    return \"cmp.b     #0,%X0\";
-}"
+  "cmp.b       #0,%X0"
   [(set_attr "type" "arith")
-   (set_attr "length" "4")
+   (set_attr "length" "2")
    (set_attr "cc" "set")])
 
 (define_insn "tsthi"
   [(set (cc0) (match_operand:HI 0 "general_operand" "ra"))]
   ""
-  "*
-{
-  /* ??? I don't think this is right.  --Jim */
-  if (cc_prev_status.flags & CC_DONE_CBIT)
-    return \"btst      #0,%0l\";
-  else
-    return \"mov.w     %T0,%T0\";
-}"
+  "mov.w       %T0,%T0"
   [(set_attr "type" "arith")
-   (set_attr "length" "4")
+   (set_attr "length" "2")
    (set_attr "cc" "set")])
 
 (define_insn "tstsi"
   [(set (cc0) (match_operand:SI 0 "general_operand" "ra"))]
   "TARGET_H8300H"
-  "*
-{
-  /* ??? I don't think this is right.  --Jim */
-  if (cc_prev_status.flags & CC_DONE_CBIT)
-    return \"btst      #0,%0l\";
-  else
-    return \"mov.l     %S0,%S0\";
-}"
+  "mov.l       %S0,%S0"
   [(set_attr "type" "arith")
-   (set_attr "length" "4")
+   (set_attr "length" "2")
    (set_attr "cc" "set")])
 
 (define_insn "cmpqi"
   [(set_attr "type" "arith")
    (set_attr "length" "2")
    (set_attr "cc" "compare")])
-
+\f
 ;; ----------------------------------------------------------------------
 ;; ADD INSTRUCTIONS
 ;; ----------------------------------------------------------------------
   "add.b       %X2,%X0"
   [(set_attr "type" "arith")
    (set_attr "length" "2")
-   (set_attr "cc" "set")])
+   (set_attr "cc" "set_zn_c0")])
 
-;; ??? adds operates on the 32bit register.  We can use it because we don't
+;; h8300h: adds operates on the 32bit register.  We can use it because we don't
 ;; use the e0-7 registers.
 ;; ??? 4 can be handled in one insn on the 300h.
 
-(define_insn "addhi3_internal"
+(define_insn "addhi3"
   [(set (match_operand:HI 0 "register_operand" "=ra,ra,ra,ra,r,ra")
        (plus:HI (match_operand:HI 1 "register_operand" "%0,0,0,0,0,0")
                 (match_operand:HI 2 "nonmemory_operand" "K,M,L,N,n,ra")))]
    add.w       %T2,%T0"
   [(set_attr "type" "arith,multi,arith,multi,multi,arith")
    (set_attr "length" "2,4,2,4,4,2")
-   (set_attr "cc" "none_0hit,none_0hit,none_0hit,none_0hit,clobber,set")])
-
-;; ??? Why is this here?
-(define_expand "addhi3"
-  [(set (match_operand:HI 0 "register_operand" "")
-       (plus:HI (match_operand:HI 1 "register_operand" "")
-                (match_operand:HI 2 "nonmemory_operand" "")))]
-  ""
-  "")
+   (set_attr "cc" "none_0hit,none_0hit,none_0hit,none_0hit,clobber,set_zn_c0")])
 
 (define_expand "addsi3"
   [(set (match_operand:SI 0 "register_operand" "")
    add.l       %S2,%S0"
   [(set_attr "type" "multi,multi,multi,multi,arith,arith")
    (set_attr "length" "2,4,2,4,6,2")
-   (set_attr "cc" "none_0hit,none_0hit,none_0hit,none_0hit,clobber,clobber")])
+   (set_attr "cc" "none_0hit,none_0hit,none_0hit,none_0hit,set_zn_c0,set_zn_c0")])
 
 ;; ----------------------------------------------------------------------
 ;; SUBTRACT INSTRUCTIONS
    add.b       %G2,%X0"
   [(set_attr "type" "arith")
    (set_attr "length" "2")
-   (set_attr "cc" "set")])
+   (set_attr "cc" "set_zn_c0")])
 
-;; ??? subs operates on the 32bit register.  We can use it because we don't
+;; h8300h: subs operates on the 32bit register.  We can use it because we don't
 ;; use the e0-7 registers.
 ;; ??? 4 can be handled in one insn on the 300h.
 ;; ??? The fourth alternative can use sub.w on the 300h.
 ;; ??? Should the 'n' constraint be an 'i' here?
 
-(define_insn "subhi3_internal"
+(define_insn "subhi3"
   [(set (match_operand:HI 0 "register_operand" "=ra,ra,ra,r")
        (minus:HI (match_operand:HI 1 "general_operand" "0,0,0,0")
                  (match_operand:HI 2 "nonmemory_operand" "K,M,ra,n")))]
    add.b       %E2,%s0\;addx   %F2,%t0 ; -%0"
   [(set_attr "type" "multi")
    (set_attr "length" "2,4,2,4")
-   (set_attr "cc" "none_0hit,none_0hit,set,clobber")])
-
-;; ??? Why is this here?
-(define_expand "subhi3"
-  [(set (match_operand:HI 0 "register_operand" "")
-       (minus:HI (match_operand:HI 1 "register_operand" "")
-                 (match_operand:HI 2 "nonmemory_operand" "")))]
-  ""
-  "")
+   (set_attr "cc" "none_0hit,none_0hit,set_zn_c0,clobber")])
 
 (define_expand "subsi3"
   [(set (match_operand:SI 0 "register_operand" "")
    sub.l       %S2,%S0"
   [(set_attr "type" "multi")
    (set_attr "length" "2,4,2,6")
-   (set_attr "cc" "none_0hit,none_0hit,set,set")])
-
+   (set_attr "cc" "none_0hit,none_0hit,set_zn_c0,set_zn_c0")])
+\f
 ;; ----------------------------------------------------------------------
 ;; MULTIPLY INSTRUCTIONS
 ;; ----------------------------------------------------------------------
   "mulxs.b     %X2,%T0"
   [(set_attr "type" "multi")
    (set_attr "length" "4")
-   (set_attr "cc" "set")])
+   (set_attr "cc" "set_zn_c0")])
 
 (define_insn "mulhisi3"
   [(set (match_operand:SI 0 "register_operand" "=r")
   "mulxs.w     %T2,%S0"
   [(set_attr "type" "multi")
    (set_attr "length" "4")
-   (set_attr "cc" "set")])
+   (set_attr "cc" "set_zn_c0")])
 
 (define_insn "umulqihi3"
   [(set (match_operand:HI 0 "register_operand" "=r")
   [(set_attr "type" "multi")
    (set_attr "length" "6")
    (set_attr "cc" "clobber")])
-
+\f
 ;; ----------------------------------------------------------------------
 ;; AND INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 }")
 
 ;; ??? Should have a bclr case here also.
+;; ??? This should be symmetric with iorhi3.
 
 (define_insn "andhi3"
   [(set (match_operand:HI 0 "register_operand" "=r")
    and %S2,%S0"
   [(set_attr "type" "arith")
    (set_attr "length" "4,6")
-   (set_attr "cc" "clobber")])
+   (set_attr "cc" "set")])
 
 ;; ----------------------------------------------------------------------
 ;; OR INSTRUCTIONS
 }")
 
 ;; ??? Should have a bset case here also.
+;; ??? This should be symmetric with andhi3.
 
 (define_insn "iorhi3"
   [(set (match_operand:HI 0 "general_operand" "=r,r")
     DONE;
 }")
 
+;; ??? This should be symmetric with andhi3.
+
 (define_insn "xorhi3"
   [(set (match_operand:HI 0 "register_operand" "=r")
        (xor:HI (match_operand:HI 1 "general_operand" "%0")
    xor %S2,%S0"
   [(set_attr "type" "arith")
    (set_attr "length" "4,6")
-   (set_attr "cc" "clobber")])
-
+   (set_attr "cc" "set")])
+\f
 ;; ----------------------------------------------------------------------
 ;; NEGATION INSTRUCTIONS
 ;; ----------------------------------------------------------------------
   "neg %X0"
   [(set_attr "type" "arith")
    (set_attr "length" "2")
-   (set_attr "cc" "clobber")])
+   (set_attr "cc" "set_zn_c0")])
 
 (define_expand "neghi2"
   [(set (match_operand:HI 0 "register_operand" "=r")
   "neg %T0"
   [(set_attr "type" "arith")
    (set_attr "length" "2")
-   (set_attr "cc" "clobber")])
+   (set_attr "cc" "set_zn_c0")])
 
 (define_expand "negsi2"
   [(set (match_operand:SI 0 "register_operand" "=r")
   "neg %S0"
   [(set_attr "type" "arith")
    (set_attr "length" "2")
-   (set_attr "cc" "clobber")])
+   (set_attr "cc" "set_zn_c0")])
 
 ;; ----------------------------------------------------------------------
 ;; NOT INSTRUCTIONS
 ;; ??? length is wrong for 300h
    (set_attr "length" "8")
    (set_attr "cc" "clobber")])
-
+\f
 ;; ----------------------------------------------------------------------
 ;; JUMP INSTRUCTIONS
 ;; ----------------------------------------------------------------------
   ""
   "*
 {
+  /* If we erroneously deleted a compare insn (which can happen if we need
+     CC bits set that aren't), emit the compare.  */
+  if (restore_compare_p (operands[1]))
+    return 0;
+
   if (get_attr_length (insn) == 2) 
     return \"b%j1      %l0\";
   else if (get_attr_length (insn) == 4) 
 ;; ??? We don't take advantage of 16 bit relative jumps in the 300h.
   "*
 {
+  /* If we erroneously deleted a compare insn (which can happen if we need
+     CC bits set that aren't), emit the compare.  */
+  if (restore_compare_p (operands[1]))
+    return 0;
+
   if (get_attr_length (insn) == 2) 
     return \"b%k1      %l0\";
   else if (get_attr_length (insn) == 4) 
 
 ;; This is a define expand, because pointers may be either 16 or 32 bits.
 
-;(define_insn "indirect_jump"
-;  [(set (pc) (match_operand:HI 0 "register_operand" "r"))]
-;  ""
-;  "jmp        @%0"
-;  [(set_attr "type" "branch")
-;   (set_attr "cc" "none")
-;   (set_attr "length" "2")])
-
 (define_expand "indirect_jump"
   [(set (pc) (match_operand 0 "jump_address_operand" "Vr"))]
   ""
   [(set_attr "type" "multi")
    (set_attr "cc" "none")
    (set_attr "length" "2")])
-
+\f
 ;; ----------------------------------------------------------------------
 ;; EXTEND INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 }"
   [(set_attr "length" "10")
    (set_attr "cc" "clobber")])
-
+\f
 ;; ----------------------------------------------------------------------
 ;; SHIFTS
 ;; ----------------------------------------------------------------------
 ;; However, for cases that loop or are done in pieces, cc does not contain
 ;; what we want.  Emit_a_shift is free to tweak cc_status as desired.
    (set_attr "cc" "clobber")])
-
+\f
 ;; -----------------------------------------------------------------
 ;; BIT FIELDS
 ;; -----------------------------------------------------------------
 ;; The H8/300 has given 1/8th of its opcode space to bitfield
-;; instructions so let's use them as well as we can
+;; instructions so let's use them as well as we can.
 
 ;; BCC and BCS patterns.
 
       operands[1] = mem;
     }
 }")
-
+\f
 ;; -----------------------------------------------------------------
 ;; STACK POINTER MANIPULATIONS
 ;; -----------------------------------------------------------------
   "mov.w       %T1,%T0\;add.w  %T2,%T0"
   [(set_attr "type" "arith")
    (set_attr "length" "6")
-   (set_attr "cc" "set")])
+   (set_attr "cc" "set_zn_c0")])
 
 
 ;; -------------------------------------------
 
        DONE;   
 }")
-
+\f
 ;; ----------------------------------------------
 ;; Peepholes go at the end.
 ;; ----------------------------------------------
   ""
   "mov.b       %X2,%X0\;bset   %X1,%X0")       
 
-
 (define_insn "fancybclr4"
   [(set (match_operand:QI 0 "general_operand" "=Ur,Ur")
        (and:QI