public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 01/28] mn10300: Better definition of INCOMING_RETURN_ADDR_RTX.
  2011-01-10 20:33 [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Richard Henderson
@ 2011-01-10 20:32 ` Richard Henderson
  2011-01-11 14:45   ` Jeff Law
  2011-01-10 20:32 ` [PATCH 04/28] mn10300: Emit the movm stores in the correct order Richard Henderson
                   ` (28 subsequent siblings)
  29 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-10 20:32 UTC (permalink / raw)
  To: gcc-patches; +Cc: nickc, law, Richard Henderson

From: Richard Henderson <rth@twiddle.net>

The new definition is more useful to the unwinder.
---
 gcc/config/mn10300/mn10300.h |    5 ++++-
 1 files changed, 4 insertions(+), 1 deletions(-)

diff --git a/gcc/config/mn10300/mn10300.h b/gcc/config/mn10300/mn10300.h
index 67516b6..edc17f5 100644
--- a/gcc/config/mn10300/mn10300.h
+++ b/gcc/config/mn10300/mn10300.h
@@ -548,7 +548,10 @@ struct cum_arg
    ? gen_rtx_MEM (Pmode, arg_pointer_rtx) \
    : (rtx) 0)
 
-#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (Pmode, MDR_REGNUM)
+/* The return address is saved both in the stack and in MDR.  Using
+   the stack location is handiest for what unwinding needs.  */
+#define INCOMING_RETURN_ADDR_RTX \
+  gen_rtx_MEM (VOIDmode, gen_rtx_REG (VOIDmode, STACK_POINTER_REGNUM))
 \f
 /* Maximum number of registers that can appear in a valid memory address.  */
 
-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 90+ messages in thread

* [PATCH 04/28] mn10300: Emit the movm stores in the correct order.
  2011-01-10 20:33 [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Richard Henderson
  2011-01-10 20:32 ` [PATCH 01/28] mn10300: Better definition of INCOMING_RETURN_ADDR_RTX Richard Henderson
@ 2011-01-10 20:32 ` Richard Henderson
  2011-01-11 14:53   ` Jeff Law
  2011-01-10 20:32 ` [PATCH 13/28] mn10300: cleanup secondary reloads Richard Henderson
                   ` (27 subsequent siblings)
  29 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-10 20:32 UTC (permalink / raw)
  To: gcc-patches; +Cc: nickc, law, Richard Henderson

From: Richard Henderson <rth@twiddle.net>

---
 gcc/config/mn10300/mn10300-protos.h |    1 -
 gcc/config/mn10300/mn10300.c        |  110 ++++++++++++++++++-----------------
 2 files changed, 56 insertions(+), 55 deletions(-)

diff --git a/gcc/config/mn10300/mn10300-protos.h b/gcc/config/mn10300/mn10300-protos.h
index ebf915e..d787dcb 100644
--- a/gcc/config/mn10300/mn10300-protos.h
+++ b/gcc/config/mn10300/mn10300-protos.h
@@ -27,7 +27,6 @@
 extern rtx   mn10300_legitimize_pic_address (rtx, rtx);
 extern int   mn10300_legitimate_pic_operand_p (rtx);
 extern bool  mn10300_function_value_regno_p (const unsigned int);
-extern void  mn10300_gen_multiple_store (int);
 extern int   mn10300_get_live_callee_saved_regs (void);
 extern bool  mn10300_hard_regno_mode_ok (unsigned int, Mmode);
 extern bool  mn10300_legitimate_constant_p (rtx);
diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c
index 23b198a..534ddaf 100644
--- a/gcc/config/mn10300/mn10300.c
+++ b/gcc/config/mn10300/mn10300.c
@@ -689,51 +689,61 @@ F (rtx r)
 	                       (const_int -N*4)))
 	      (reg:SI R1))) */
 
-void
-mn10300_gen_multiple_store (int mask)
+static void
+mn10300_gen_multiple_store (unsigned int mask)
 {
-  if (mask != 0)
+  /* The order in which registers are stored, from SP-4 through SP-N*4.  */
+  static const unsigned int store_order[8] = {
+    /* e2, e3: never saved */
+    FIRST_EXTENDED_REGNUM + 4,
+    FIRST_EXTENDED_REGNUM + 5,
+    FIRST_EXTENDED_REGNUM + 6,
+    FIRST_EXTENDED_REGNUM + 7,
+    /* e0, e1, mdrq, mcrh, mcrl, mcvf: never saved. */
+    FIRST_DATA_REGNUM + 2,
+    FIRST_DATA_REGNUM + 3,
+    FIRST_ADDRESS_REGNUM + 2,
+    FIRST_ADDRESS_REGNUM + 3,
+    /* d0, d1, a0, a1, mdr, lir, lar: never saved.  */
+  };
+
+  rtx x, elts[9];
+  unsigned int i;
+  int count;
+
+  if (mask == 0)
+    return;
+
+  for (i = count = 0; i < ARRAY_SIZE(store_order); ++i)
     {
-      int i;
-      int count;
-      rtx par;
-      int pari;
-
-      /* Count how many registers need to be saved.  */
-      count = 0;
-      for (i = 0; i <= LAST_EXTENDED_REGNUM; i++)
-	if ((mask & (1 << i)) != 0)
-	  count += 1;
-
-      /* We need one PARALLEL element to update the stack pointer and
-	 an additional element for each register that is stored.  */
-      par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count + 1));
-
-      /* Create the instruction that updates the stack pointer.  */
-      XVECEXP (par, 0, 0)
-	= F (gen_rtx_SET (SImode,
-			  stack_pointer_rtx,
-			  gen_rtx_PLUS (SImode,
-					stack_pointer_rtx,
-					GEN_INT (-count * 4))));
-
-      /* Create each store.  */
-      pari = 1;
-      for (i = LAST_EXTENDED_REGNUM; i >= 0; i--)
-	if ((mask & (1 << i)) != 0)
-	  {
-	    rtx address = gen_rtx_PLUS (SImode,
-					stack_pointer_rtx,
-					GEN_INT (-pari * 4));
-	    XVECEXP(par, 0, pari)
-	      = F (gen_rtx_SET (VOIDmode,
-				gen_rtx_MEM (SImode, address),
-				gen_rtx_REG (SImode, i)));
-	    pari += 1;
-	  }
+      unsigned regno = store_order[i];
+
+      if (((mask >> regno) & 1) == 0)
+	continue;
+
+      ++count;
+      x = plus_constant (stack_pointer_rtx, count * -4);
+      x = gen_frame_mem (SImode, x);
+      x = gen_rtx_SET (VOIDmode, x, gen_rtx_REG (SImode, regno));
+      elts[count] = F(x);
 
-      F (emit_insn (par));
+      /* Remove the register from the mask so that... */
+      mask &= ~(1u << regno);
     }
+
+  /* ... we can make sure that we didn't try to use a register
+     not listed in the store order.  */
+  gcc_assert (mask == 0);
+
+  /* Create the instruction that updates the stack pointer.  */
+  x = plus_constant (stack_pointer_rtx, count * -4);
+  x = gen_rtx_SET (VOIDmode, stack_pointer_rtx, x);
+  elts[0] = F(x);
+
+  /* We need one PARALLEL element to update the stack pointer and
+     an additional element for each register that is stored.  */
+  x = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (count + 1, elts));
+  F (emit_insn (x));
 }
 
 void
@@ -1273,27 +1283,19 @@ mn10300_store_multiple_operation (rtx op,
       || INTVAL (XEXP (elt, 1)) != -(count - 1) * 4)
     return 0;
 
-  /* Now go through the rest of the vector elements.  They must be
-     ordered so that the first instruction stores the highest-numbered
-     register to the highest stack slot and that subsequent instructions
-     store a lower-numbered register to the slot below.
-
-     LAST keeps track of the smallest-numbered register stored so far.
-     MASK is the set of stored registers.  */
-  last = LAST_EXTENDED_REGNUM + 1;
   mask = 0;
   for (i = 1; i < count; i++)
     {
-      /* Check that element i is a (set (mem M) R) and that R is valid.  */
+      /* Check that element i is a (set (mem M) R).  */
+      /* ??? Validate the register order a-la mn10300_gen_multiple_store.
+	 Remember: the ordering is *not* monotonic.  */
       elt = XVECEXP (op, 0, i);
       if (GET_CODE (elt) != SET
 	  || (! MEM_P (SET_DEST (elt)))
-	  || (! REG_P (SET_SRC (elt)))
-	  || REGNO (SET_SRC (elt)) >= last)
+	  || (! REG_P (SET_SRC (elt))))
 	return 0;
 
-      /* R was OK, so provisionally add it to MASK.  We return 0 in any
-	 case if the rest of the instruction has a flaw.  */
+      /* Remember which registers are to be saved.  */
       last = REGNO (SET_SRC (elt));
       mask |= (1 << last);
 
-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 90+ messages in thread

* [PATCH 13/28] mn10300: cleanup secondary reloads
  2011-01-10 20:33 [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Richard Henderson
  2011-01-10 20:32 ` [PATCH 01/28] mn10300: Better definition of INCOMING_RETURN_ADDR_RTX Richard Henderson
  2011-01-10 20:32 ` [PATCH 04/28] mn10300: Emit the movm stores in the correct order Richard Henderson
@ 2011-01-10 20:32 ` Richard Henderson
  2011-01-18 17:14   ` Jeff Law
  2011-01-10 20:33 ` [PATCH 20/28] mn10300: Emit clr Richard Henderson
                   ` (26 subsequent siblings)
  29 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-10 20:32 UTC (permalink / raw)
  To: gcc-patches; +Cc: nickc, law, Richard Henderson

From: Richard Henderson <rth@twiddle.net>

Handles output reloads for QI/HImode properly; previously we were
only handing input reloads properly.

Handles reloads involving the stack pointer better; note that the
AM33 allows copying SP to DATA_REGS as well as ADDRESS and EXTENDED.
---
 gcc/config/mn10300/mn10300-protos.h |    1 -
 gcc/config/mn10300/mn10300.c        |  120 +++++++++++++++++++---------------
 gcc/config/mn10300/mn10300.h        |    3 -
 gcc/config/mn10300/mn10300.md       |   60 ++++++++++-------
 4 files changed, 102 insertions(+), 82 deletions(-)

diff --git a/gcc/config/mn10300/mn10300-protos.h b/gcc/config/mn10300/mn10300-protos.h
index d6cf850..37968ff 100644
--- a/gcc/config/mn10300/mn10300-protos.h
+++ b/gcc/config/mn10300/mn10300-protos.h
@@ -35,7 +35,6 @@ extern Cstar mn10300_output_cmp (rtx, rtx);
 extern void  mn10300_print_operand (FILE *, rtx, int);
 extern void  mn10300_print_operand_address (FILE *, rtx);
 extern void  mn10300_print_reg_list (FILE *, int);
-extern Rclas mn10300_secondary_reload_class (Rclas, Mmode, rtx);
 extern Mmode mn10300_select_cc_mode (rtx);
 extern int   mn10300_store_multiple_operation (rtx, Mmode);
 extern int   mn10300_symbolic_operand (rtx, Mmode);
diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c
index 5f2d63b..78b5b5d 100644
--- a/gcc/config/mn10300/mn10300.c
+++ b/gcc/config/mn10300/mn10300.c
@@ -1321,7 +1321,7 @@ static reg_class_t
 mn10300_preferred_reload_class (rtx x, reg_class_t rclass)
 {
   if (x == stack_pointer_rtx && rclass != SP_REGS)
-     return ADDRESS_OR_EXTENDED_REGS;
+    return BASE_REG_CLASS;
   else if (MEM_P (x)
 	   || (REG_P (x) 
 	       && !HARD_REGISTER_P (x))
@@ -1339,72 +1339,83 @@ static reg_class_t
 mn10300_preferred_output_reload_class (rtx x, reg_class_t rclass)
 {
   if (x == stack_pointer_rtx && rclass != SP_REGS)
-    return ADDRESS_OR_EXTENDED_REGS;
-
+    return BASE_REG_CLASS;
   return rclass;
 }
 
-/* What (if any) secondary registers are needed to move IN with mode
-   MODE into a register in register class RCLASS.
-
-   We might be able to simplify this.  */
+/* Implement TARGET_SECONDARY_RELOAD.  */
 
-enum reg_class
-mn10300_secondary_reload_class (enum reg_class rclass, enum machine_mode mode,
-				rtx in)
+static reg_class_t
+mn10300_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i,
+			  enum machine_mode mode, secondary_reload_info *sri)
 {
-  rtx inner = in;
-
-  /* Strip off any SUBREG expressions from IN.  Basically we want
-     to know if IN is a pseudo or (subreg (pseudo)) as those can
-     turn into MEMs during reload.  */
-  while (GET_CODE (inner) == SUBREG)
-    inner = SUBREG_REG (inner);
-
-  /* Memory loads less than a full word wide can't have an
-     address or stack pointer destination.  They must use
-     a data register as an intermediate register.  */
-  if ((MEM_P (in)
-       || (REG_P (inner)
-	   && REGNO (inner) >= FIRST_PSEUDO_REGISTER))
-      && (mode == QImode || mode == HImode)
-      && (rclass == ADDRESS_REGS || rclass == SP_REGS
-	  || rclass == SP_OR_ADDRESS_REGS))
+  enum reg_class rclass = (enum reg_class) rclass_i;
+  enum reg_class xclass = NO_REGS;
+  unsigned int xregno = INVALID_REGNUM;
+
+  if (REG_P (x))
     {
-      if (TARGET_AM33)
-	return DATA_OR_EXTENDED_REGS;
-      return DATA_REGS;
+      xregno = REGNO (x);
+      if (xregno >= FIRST_PSEUDO_REGISTER)
+	xregno = true_regnum (x);
+      if (xregno != INVALID_REGNUM)
+	xclass = REGNO_REG_CLASS (xregno);
+    }
+
+  if (!TARGET_AM33)
+    {
+      /* Memory load/stores less than a full word wide can't have an
+         address or stack pointer destination.  They must use a data
+         register as an intermediate register.  */
+      if (rclass != DATA_REGS
+	  && (mode == QImode || mode == HImode)
+	  && xclass == NO_REGS)
+	return DATA_REGS;
+
+      /* We can only move SP to/from an address register.  */
+      if (in_p
+	  && rclass == SP_REGS
+	  && xclass != ADDRESS_REGS)
+	return ADDRESS_REGS;
+      if (!in_p
+	  && xclass == SP_REGS
+	  && rclass != ADDRESS_REGS
+	  && rclass != SP_OR_ADDRESS_REGS)
+	return ADDRESS_REGS;
     }
 
-  /* We can't directly load sp + const_int into a data register;
-     we must use an address register as an intermediate.  */
-  if (rclass != SP_REGS
-      && rclass != ADDRESS_REGS
+  /* We can't directly load sp + const_int into a register;
+     we must use an address register as an scratch.  */
+  if (in_p
+      && rclass != SP_REGS
       && rclass != SP_OR_ADDRESS_REGS
       && rclass != SP_OR_EXTENDED_REGS
-      && rclass != ADDRESS_OR_EXTENDED_REGS
       && rclass != SP_OR_ADDRESS_OR_EXTENDED_REGS
-      && (in == stack_pointer_rtx
-	  || (GET_CODE (in) == PLUS
-	      && (XEXP (in, 0) == stack_pointer_rtx
-		  || XEXP (in, 1) == stack_pointer_rtx))))
-    return ADDRESS_REGS;
+      && GET_CODE (x) == PLUS
+      && (XEXP (x, 0) == stack_pointer_rtx
+	  || XEXP (x, 1) == stack_pointer_rtx))
+    {
+      sri->icode = CODE_FOR_reload_plus_sp_const;
+      return NO_REGS;
+    }
 
+  /* We can't load/store an FP register from a constant address.  */
   if (TARGET_AM33_2
-      && rclass == FP_REGS)
+      && (rclass == FP_REGS || xclass == FP_REGS)
+      && (xclass == NO_REGS || rclass == NO_REGS))
     {
-      /* We can't load directly into an FP register from a	
-	 constant address.  */
-      if (MEM_P (in)
-	  && CONSTANT_ADDRESS_P (XEXP (in, 0)))
-	return DATA_OR_EXTENDED_REGS;
+      rtx addr = NULL;
+
+      if (xregno >= FIRST_PSEUDO_REGISTER && xregno != INVALID_REGNUM)
+	{
+	  addr = reg_equiv_mem [xregno];
+	  if (addr)
+	    addr = XEXP (addr, 0);
+	}
+      else if (MEM_P (x))
+	addr = XEXP (x, 0);
 
-      /* Handle case were a pseudo may not get a hard register
-	 but has an equivalent memory location defined.  */
-      if (REG_P (inner)
-	  && REGNO (inner) >= FIRST_PSEUDO_REGISTER
-	  && reg_equiv_mem [REGNO (inner)]
-	  && CONSTANT_ADDRESS_P (XEXP (reg_equiv_mem [REGNO (inner)], 0)))
+      if (addr && CONSTANT_ADDRESS_P (addr))
 	return DATA_OR_EXTENDED_REGS;
     }
 
@@ -2720,7 +2731,10 @@ mn10300_conditional_register_usage (void)
 #undef  TARGET_PREFERRED_RELOAD_CLASS
 #define TARGET_PREFERRED_RELOAD_CLASS mn10300_preferred_reload_class
 #undef  TARGET_PREFERRED_OUTPUT_RELOAD_CLASS
-#define TARGET_PREFERRED_OUTPUT_RELOAD_CLASS mn10300_preferred_output_reload_class
+#define TARGET_PREFERRED_OUTPUT_RELOAD_CLASS \
+  mn10300_preferred_output_reload_class
+#undef  TARGET_SECONDARY_RELOAD
+#define TARGET_SECONDARY_RELOAD  mn10300_secondary_reload
 
 #undef  TARGET_TRAMPOLINE_INIT
 #define TARGET_TRAMPOLINE_INIT mn10300_trampoline_init
diff --git a/gcc/config/mn10300/mn10300.h b/gcc/config/mn10300/mn10300.h
index f5f6416..4fe0c48 100644
--- a/gcc/config/mn10300/mn10300.h
+++ b/gcc/config/mn10300/mn10300.h
@@ -416,9 +416,6 @@ enum reg_class
 #define LIMIT_RELOAD_CLASS(MODE, CLASS) \
   (!TARGET_AM33 && (MODE == QImode || MODE == HImode) ? DATA_REGS : CLASS)
 
-#define SECONDARY_RELOAD_CLASS(CLASS,MODE,IN) \
-  mn10300_secondary_reload_class(CLASS,MODE,IN)
-
 /* Return the maximum number of consecutive registers
    needed to represent mode MODE in a register of class CLASS.  */
 
diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md
index 6e0e1a2..457b17a 100644
--- a/gcc/config/mn10300/mn10300.md
+++ b/gcc/config/mn10300/mn10300.md
@@ -274,42 +274,52 @@
 ;; We use this to handle addition of two values when one operand is the
 ;; stack pointer and the other is a memory reference of some kind.  Reload
 ;; does not handle them correctly without this expander.
-(define_expand "reload_insi"
-  [(set (match_operand:SI     0 "register_operand" "=a")
+(define_expand "reload_plus_sp_const"
+  [(set (match_operand:SI     0 "register_operand" "=r")
 	(match_operand:SI     1 "impossible_plus_operand" ""))
-   (clobber (match_operand:SI 2 "register_operand" "=&r"))]
+   (clobber (match_operand:SI 2 "register_operand" "=&A"))]
   ""
   "
 {
-  gcc_assert (REGNO (operands[0]) != REGNO (operands[2]));
+  rtx dest, scratch, other;
 
-  if (XEXP (operands[1], 0) == stack_pointer_rtx)
+  dest = operands[0];
+  scratch = operands[2];
+
+  other = XEXP (operands[1], 1);
+  if (other == stack_pointer_rtx)
+    other = XEXP (operands[1], 0);
+
+  if (true_regnum (other) == true_regnum (dest))
     {
-      if (GET_CODE (XEXP (operands[1], 1)) == SUBREG
-	  && (GET_MODE_SIZE (GET_MODE (XEXP (operands[1], 1)))
-	      > GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (operands[1], 1))))))
-	emit_move_insn (operands[2],
-			gen_rtx_ZERO_EXTEND
-			(GET_MODE (XEXP (operands[1], 1)),
-			 SUBREG_REG (XEXP (operands[1], 1))));
-      else
-	emit_move_insn (operands[2], XEXP (operands[1], 1));
-      emit_move_insn (operands[0], XEXP (operands[1], 0));
+      gcc_assert (true_regnum (scratch) != true_regnum (dest));
+      emit_move_insn (scratch, stack_pointer_rtx);
+      emit_insn (gen_addsi3 (dest, dest, scratch));
+    }
+  else if (TARGET_AM33 || REGNO_REG_CLASS (true_regnum (dest)) == ADDRESS_REGS)
+    {
+      emit_move_insn (dest, stack_pointer_rtx);
+      if (other == stack_pointer_rtx)
+        emit_insn (gen_addsi3 (dest, dest, dest));
+      else if (other != const0_rtx)
+        emit_insn (gen_addsi3 (dest, dest, other));
     }
   else
     {
-      if (GET_CODE (XEXP (operands[1], 0)) == SUBREG
-	  && (GET_MODE_SIZE (GET_MODE (XEXP (operands[1], 0)))
-	      > GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (operands[1], 0))))))
-	emit_move_insn (operands[2],
-			gen_rtx_ZERO_EXTEND
-			(GET_MODE (XEXP (operands[1], 0)),
-			 SUBREG_REG (XEXP (operands[1], 0))));
+      emit_move_insn (scratch, stack_pointer_rtx);
+      if (other == stack_pointer_rtx)
+	{
+	  emit_move_insn (dest, scratch);
+          emit_insn (gen_addsi3 (dest, dest, dest));
+	}
+      else if (other != const0_rtx)
+	{
+	  emit_move_insn (dest, other);
+          emit_insn (gen_addsi3 (dest, dest, scratch));
+	}
       else
-	emit_move_insn (operands[2], XEXP (operands[1], 0));
-      emit_move_insn (operands[0], XEXP (operands[1], 1));
+	emit_move_insn (dest, scratch);
     }
-  emit_insn (gen_addsi3 (operands[0], operands[0], operands[2]));
   DONE;
 }")
 
-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 90+ messages in thread

* [PATCH 27/28] mn10300: Add support in longlong.h.
  2011-01-10 20:33 [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Richard Henderson
                   ` (4 preceding siblings ...)
  2011-01-10 20:33 ` [PATCH 02/28] mn10300: disable test tree-ssa/vrp47.c Richard Henderson
@ 2011-01-10 20:33 ` Richard Henderson
  2011-01-12 14:31   ` Jeff Law
  2011-01-10 20:33 ` [PATCH 12/28] mn10300: Re-write move patterns Richard Henderson
                   ` (23 subsequent siblings)
  29 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-10 20:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: nickc, law, Richard Henderson

From: Richard Henderson <rth@twiddle.net>

This greatly helps out the DImode division, and to a lesser
extent the DImode multiplication routines in libgcc2.c.
---
 gcc/longlong.h |   37 +++++++++++++++++++++++++++++++++++++
 1 files changed, 37 insertions(+), 0 deletions(-)

diff --git a/gcc/longlong.h b/gcc/longlong.h
index bb916ae..5937a48 100644
--- a/gcc/longlong.h
+++ b/gcc/longlong.h
@@ -718,6 +718,43 @@ UDItype __umulsidi3 (USItype, USItype);
 #endif /* __mc88110__ */
 #endif /* __m88000__ */
 
+#if defined (__mn10300__)
+# if defined (__AM33__)
+#  define count_leading_zeros(COUNT,X)	((COUNT) = __builtin_clz (X))
+#  define umul_ppmm(w1, w0, u, v)		\
+    asm("mulu %3,%2,%1,%0" : "=r"(w0), "=r"(w1) : "r"(u), "r"(v))
+#  define smul_ppmm(w1, w0, u, v)		\
+    asm("mul %3,%2,%1,%0" : "=r"(w0), "=r"(w1) : "r"(u), "r"(v))
+# else
+#  define umul_ppmm(w1, w0, u, v)		\
+    asm("nop; nop; mulu %3,%0" : "=d"(w0), "=z"(w1) : "%0"(u), "d"(v))
+#  define smul_ppmm(w1, w0, u, v)		\
+    asm("nop; nop; mul %3,%0" : "=d"(w0), "=z"(w1) : "%0"(u), "d"(v))
+# endif
+# define add_ssaaaa(sh, sl, ah, al, bh, bl)	\
+  do {						\
+    DWunion __s, __a, __b;			\
+    __a.s.low = (al); __a.s.high = (ah);	\
+    __b.s.low = (bl); __b.s.high = (bh);	\
+    __s.ll = __a.ll + __b.ll;			\
+    (sl) = __s.s.low; (sh) = __s.s.high;	\
+  } while (0)
+# define sub_ddmmss(sh, sl, ah, al, bh, bl)	\
+  do {						\
+    DWunion __s, __a, __b;			\
+    __a.s.low = (al); __a.s.high = (ah);	\
+    __b.s.low = (bl); __b.s.high = (bh);	\
+    __s.ll = __a.ll - __b.ll;			\
+    (sl) = __s.s.low; (sh) = __s.s.high;	\
+  } while (0)
+# define udiv_qrnnd(q, r, nh, nl, d)		\
+  asm("divu %2,%0" : "=D"(q), "=z"(r) : "D"(d), "0"(nl), "1"(nh))
+# define sdiv_qrnnd(q, r, nh, nl, d)		\
+  asm("div %2,%0" : "=D"(q), "=z"(r) : "D"(d), "0"(nl), "1"(nh))
+# define UMUL_TIME 3
+# define UDIV_TIME 38
+#endif
+
 #if defined (__mips__) && W_TYPE_SIZE == 32
 #define umul_ppmm(w1, w0, u, v)						\
   do {									\
-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 90+ messages in thread

* [PATCH 23/28] mn10300: Add delegitimize_address hook.
  2011-01-10 20:33 [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Richard Henderson
                   ` (11 preceding siblings ...)
  2011-01-10 20:33 ` [PATCH 25/28] mn10300: Use reg_or_am33_const_operand in mulsi3 Richard Henderson
@ 2011-01-10 20:33 ` Richard Henderson
  2011-01-12 14:06   ` Jeff Law
  2011-01-10 20:34 ` [PATCH 05/28] mn10300: Fix debug offsets into the stack frame Richard Henderson
                   ` (16 subsequent siblings)
  29 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-10 20:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: nickc, law, Richard Henderson

From: Richard Henderson <rth@twiddle.net>

This suppresses warnings generated by the dwarf2 output
routines about uninterpretable addresses.
---
 gcc/config/mn10300/mn10300.c |   62 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 62 insertions(+), 0 deletions(-)

diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c
index c56b896..17e58fe 100644
--- a/gcc/config/mn10300/mn10300.c
+++ b/gcc/config/mn10300/mn10300.c
@@ -2080,6 +2080,66 @@ mn10300_legitimate_constant_p (rtx x)
   return true;
 }
 
+/* Undo pic address legitimization for the benefit of debug info.  */
+
+static rtx
+mn10300_delegitimize_address (rtx orig_x)
+{
+  rtx x = orig_x, ret, addend = NULL;
+  bool need_mem;
+
+  if (MEM_P (x))
+    x = XEXP (x, 0);
+  if (GET_CODE (x) != PLUS || GET_MODE (x) != Pmode)
+    return orig_x;
+
+  if (XEXP (x, 0) == pic_offset_table_rtx)
+    ;
+  /* With the REG+REG addressing of AM33, var-tracking can re-assemble
+     some odd-looking "addresses" that were never valid in the first place.
+     We need to look harder to avoid warnings being emitted.  */
+  else if (GET_CODE (XEXP (x, 0)) == PLUS)
+    {
+      rtx x0 = XEXP (x, 0);
+      rtx x00 = XEXP (x0, 0);
+      rtx x01 = XEXP (x0, 1);
+
+      if (x00 == pic_offset_table_rtx)
+	addend = x01;
+      else if (x01 == pic_offset_table_rtx)
+	addend = x00;
+      else
+	return orig_x;
+
+    }
+  else
+    return orig_x;
+  x = XEXP (x, 1);
+
+  if (GET_CODE (x) != CONST)
+    return orig_x;
+  x = XEXP (x, 0);
+  if (GET_CODE (x) != UNSPEC)
+    return orig_x;
+
+  ret = XVECEXP (x, 0, 0);
+  if (XINT (x, 1) == UNSPEC_GOTOFF)
+    need_mem = false;
+  else if (XINT (x, 1) == UNSPEC_GOT)
+    need_mem = true;
+  else
+    return orig_x;
+
+  gcc_assert (GET_CODE (ret) == SYMBOL_REF);
+  if (need_mem != MEM_P (orig_x))
+    return orig_x;
+  if (need_mem && addend)
+    return orig_x;
+  if (addend)
+    ret = gen_rtx_PLUS (Pmode, addend, ret);
+  return ret;
+}
+
 /* For addresses, costs are relative to "MOV (Rm),Rn".  For AM33 this is
    the 3-byte fully general instruction; for MN103 this is the 2-byte form
    with an address register.  */
@@ -2915,6 +2975,8 @@ mn10300_split_and_operand_count (rtx op)
 
 #undef  TARGET_LEGITIMATE_ADDRESS_P
 #define TARGET_LEGITIMATE_ADDRESS_P	mn10300_legitimate_address_p
+#undef  TARGET_DELEGITIMIZE_ADDRESS
+#define TARGET_DELEGITIMIZE_ADDRESS	mn10300_delegitimize_address
 
 #undef  TARGET_PREFERRED_RELOAD_CLASS
 #define TARGET_PREFERRED_RELOAD_CLASS mn10300_preferred_reload_class
-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 90+ messages in thread

* [PATCH 00/28] mn10300 cleanup + compare-elim, v2
@ 2011-01-10 20:33 Richard Henderson
  2011-01-10 20:32 ` [PATCH 01/28] mn10300: Better definition of INCOMING_RETURN_ADDR_RTX Richard Henderson
                   ` (29 more replies)
  0 siblings, 30 replies; 90+ messages in thread
From: Richard Henderson @ 2011-01-10 20:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: nickc, law, Richard Henderson

From: Richard Henderson <rth@twiddle.net>

Aka, how I spent my xmas vacation.  ;-)

It may now be too late for the inclusion of the compare-elim
pass in 4.6, but I thought I'd post it anyway.  Some of the
target cleanup work might still go in, and I certainly don't
want Nick to duplicate work if he gets back to work on the port.

All patches except the last are totally port-specific.  Even
the last is mostly port-specific, since one has to define a
target hook in order to get the new pass to run.  About half
of these patches just fix errors in the port.

Comments appreciated.


r~


Richard Henderson (28):
  mn10300: Better definition of INCOMING_RETURN_ADDR_RTX.
  mn10300: disable test tree-ssa/vrp47.c
  mn10300: delete ASM_PN_FORMAT
  mn10300: Emit the movm stores in the correct order.
  mn10300: Fix debug offsets into the stack frame
  mn10300: fp insn cleanup
  mn10300: Add attribute enabled.
  mn10300: Define the A and D constraints.
  mn10300: Remove bset/bclr patterns.
  mn10300: Clean up trampoline handling
  mn10300: Clean up costing.
  mn10300: Re-write move patterns.
  mn10300: cleanup secondary reloads
  mn10300: Cleanup legitimate addresses
  mn10300: Force lower-subreg pass to run.
  mn10300: Expose the MDR register to register allocation.
  mn10300: Explicitly represent MDR in multiply and divide.
  mn10300: Cleanup all arithmetic.
  mn10300: tidy pic address loading
  mn10300: Emit clr.
  mn10300: Add clzsi2.
  mn10300: Emit retf instruction
  mn10300: Add delegitimize_address hook.
  mn10300: Implement adddi3, subdi3.
  mn10300: Use reg_or_am33_const_operand in mulsi3.
  mn10300: Auto-clobber the flags in asms.
  mn10300: Add support in longlong.h.
  New -fcompare-elim pass.

 gcc/Makefile.in                       |    4 +
 gcc/common.opt                        |    4 +
 gcc/compare-elim.c                    |  519 +++++
 gcc/config/mn10300/constraints.md     |   37 +-
 gcc/config/mn10300/mn10300-modes.def  |    2 +
 gcc/config/mn10300/mn10300-protos.h   |   17 +-
 gcc/config/mn10300/mn10300.c          | 1624 ++++++++++------
 gcc/config/mn10300/mn10300.h          |  185 +-
 gcc/config/mn10300/mn10300.md         | 3419 +++++++++++----------------------
 gcc/config/mn10300/predicates.md      |   33 +-
 gcc/doc/invoke.texi                   |   15 +-
 gcc/doc/tm.texi                       |    4 +
 gcc/doc/tm.texi.in                    |    2 +
 gcc/longlong.h                        |   37 +
 gcc/opts.c                            |    1 +
 gcc/passes.c                          |    1 +
 gcc/recog.h                           |    5 +
 gcc/target.def                        |    9 +
 gcc/testsuite/gcc.dg/tree-ssa/vrp47.c |    2 +-
 gcc/tree-pass.h                       |    1 +
 20 files changed, 2914 insertions(+), 3007 deletions(-)
 create mode 100644 gcc/compare-elim.c

-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 90+ messages in thread

* [PATCH 06/28] mn10300: fp insn cleanup
  2011-01-10 20:33 [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Richard Henderson
                   ` (9 preceding siblings ...)
  2011-01-10 20:33 ` [PATCH 10/28] mn10300: Clean up trampoline handling Richard Henderson
@ 2011-01-10 20:33 ` Richard Henderson
  2011-01-11 14:46   ` Jeff Law
  2011-01-10 20:33 ` [PATCH 25/28] mn10300: Use reg_or_am33_const_operand in mulsi3 Richard Henderson
                   ` (18 subsequent siblings)
  29 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-10 20:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: nickc, law, Richard Henderson

From: Richard Henderson <rth@twiddle.net>

Delete integer-mode abssf2, negsf2; these will be handled
by the middle-end now.  Delete unnecessary expanders.
---
 gcc/config/mn10300/mn10300.md |  212 ++++------------------------------------
 1 files changed, 22 insertions(+), 190 deletions(-)

diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md
index 3fad021..3a266960 100644
--- a/gcc/config/mn10300/mn10300.md
+++ b/gcc/config/mn10300/mn10300.md
@@ -2577,74 +2577,8 @@
 ;; ----------------------------------------------------------------------
 ;; FP INSTRUCTIONS
 ;; ----------------------------------------------------------------------
-;;
-;; The mn103 series does not have floating point instructions, but since
-;; FP values are held in integer regs, we can clear the high bit easily
-;; which gives us an efficient inline floating point absolute value.
-;;
-;; Similarly for negation of a FP value.
-;;
-
-(define_expand "absdf2"
-  [(set (match_operand:DF         0 "register_operand")
-        (abs:DF (match_operand:DF 1 "register_operand")))]
-  ""
-  "
-{
-  rtx target, result, insns;
-
-  start_sequence ();
-  target = operand_subword (operands[0], 1, 1, DFmode);
-  result = expand_binop (SImode, and_optab,
-			 operand_subword_force (operands[1], 1, DFmode),
-			 GEN_INT (0x7fffffff), target, 0, OPTAB_WIDEN);
-
-  gcc_assert (result);
-
-  if (result != target)
-    emit_move_insn (result, target);
-
-  emit_move_insn (operand_subword (operands[0], 0, 1, DFmode),
-		  operand_subword_force (operands[1], 0, DFmode));
-
-  insns = get_insns ();
-  end_sequence ();
-
-  emit_insn (insns);
-  DONE;
-}")
-
-(define_expand "abssf2"
-  [(set (match_operand:SF         0 "register_operand")
-        (abs:SF (match_operand:SF 1 "register_operand")))]
-  ""
-  "
-{
-  rtx result;
-  rtx target;
-
-  if (TARGET_AM33_2)
-    {
-      emit_insn (gen_abssf2_am33_2 (operands[0], operands[1]));
-      DONE;
-    }
-
-  target = operand_subword_force (operands[0], 0, SFmode);
-  result = expand_binop (SImode, and_optab,
-			 operand_subword_force (operands[1], 0, SFmode),
-			 GEN_INT (0x7fffffff), target, 0, OPTAB_WIDEN);
-  gcc_assert (result);
 
-  if (result != target)
-    emit_move_insn (result, target);
-
-  /* Make a place for REG_EQUAL.  */
-  emit_move_insn (operands[0], operands[0]);
-  DONE;
-}")
-
-
-(define_insn "abssf2_am33_2"
+(define_insn "abssf2"
   [(set (match_operand:SF         0 "register_operand" "=f,f")
 	(abs:SF (match_operand:SF 1 "register_operand" "0,?f")))]
   "TARGET_AM33_2"
@@ -2655,67 +2589,7 @@
 				       (const_int 17) (const_int 14)))]
 )
 
-(define_expand "negdf2"
-  [(set (match_operand:DF         0 "register_operand")
-        (neg:DF (match_operand:DF 1 "register_operand")))]
-  ""
-  "
-{
-  rtx target, result, insns;
-
-  start_sequence ();
-  target = operand_subword (operands[0], 1, 1, DFmode);
-  result = expand_binop (SImode, xor_optab,
-			 operand_subword_force (operands[1], 1, DFmode),
-			 GEN_INT (trunc_int_for_mode (0x80000000, SImode)),
-			 target, 0, OPTAB_WIDEN);
-
-  gcc_assert (result);
-
-  if (result != target)
-    emit_move_insn (result, target);
-
-  emit_move_insn (operand_subword (operands[0], 0, 1, DFmode),
-		  operand_subword_force (operands[1], 0, DFmode));
-
-  insns = get_insns ();
-  end_sequence ();
-
-  emit_insn (insns);
-  DONE;
-}")
-
-(define_expand "negsf2"
-  [(set (match_operand:SF         0 "register_operand")
-        (neg:SF (match_operand:SF 1 "register_operand")))]
-  ""
-  "
-{
-  rtx result;
-  rtx target;
-
-  if (TARGET_AM33_2)
-    {
-      emit_insn (gen_negsf2_am33_2 (operands[0], operands[1]));
-      DONE;
-    }
-
-  target = operand_subword_force (operands[0], 0, SFmode);
-  result = expand_binop (SImode, xor_optab,
-			 operand_subword_force (operands[1], 0, SFmode),
-			 GEN_INT (trunc_int_for_mode (0x80000000, SImode)),
-			 target, 0, OPTAB_WIDEN);
-  gcc_assert (result);
-
-  if (result != target)
-    emit_move_insn (result, target);
-
-  /* Make a place for REG_EQUAL.  */
-  emit_move_insn (operands[0], operands[0]);
-  DONE;
-}")
-
-(define_insn "negsf2_am33_2"
+(define_insn "negsf2"
   [(set (match_operand:SF         0 "register_operand" "=f,f")
 	(neg:SF (match_operand:SF 1 "register_operand" "0,?f")))]
   "TARGET_AM33_2"
@@ -2727,27 +2601,22 @@
 )
 
 (define_expand "sqrtsf2"
-  [(parallel [(set (match_operand:SF          0 "register_operand" "")
-		   (sqrt:SF (match_operand:SF 1 "register_operand" "")))
-	      (clobber (reg:CC_FLOAT CC_REG))
-	     ])
-  ]
+  [(set (match_operand:SF 0 "register_operand" "")
+	(sqrt:SF (match_operand:SF 1 "register_operand" "")))]
   "TARGET_AM33_2 && flag_unsafe_math_optimizations"
-  "
-  {
-    rtx scratch = gen_reg_rtx (SFmode);
-    emit_insn (gen_rsqrtsf2 (scratch, operands[1], CONST1_RTX (SFmode)));
-    emit_insn (gen_divsf3 (operands[0], force_reg (SFmode, CONST1_RTX (SFmode)),
-			   scratch));
-    DONE;
-  }")
+{
+  rtx scratch = gen_reg_rtx (SFmode);
+  emit_insn (gen_rsqrtsf2 (scratch, operands[1], CONST1_RTX (SFmode)));
+  emit_insn (gen_divsf3 (operands[0], force_reg (SFmode, CONST1_RTX (SFmode)),
+			 scratch));
+  DONE;
+})
 
 (define_insn "rsqrtsf2"
   [(set (match_operand:SF                  0 "register_operand" "=f,f")
 	(div:SF (match_operand:SF          2 "const_1f_operand" "F,F")
 		(sqrt:SF (match_operand:SF 1 "register_operand" "0,?f"))))
-   (clobber (reg:CC_FLOAT CC_REG))
-  ]
+   (clobber (reg:CC_FLOAT CC_REG))]
   "TARGET_AM33_2"
   "@
    frsqrt %0
@@ -2756,22 +2625,11 @@
 				       (const_int 4753) (const_int 2327)))]
 )
 
-(define_expand "addsf3"
-  [(parallel [(set (match_operand:SF          0 "register_operand")
-		   (plus:SF (match_operand:SF 1 "register_operand")
-			    (match_operand:SF 2 "nonmemory_operand")))
-	      (clobber (reg:CC_FLOAT CC_REG))])
-  ]
-  "TARGET_AM33_2"
-  ""
-)
-
-(define_insn "*addsf3_internal"
+(define_insn "addsf3"
   [(set (match_operand:SF          0 "register_operand" "=f,f")
 	(plus:SF (match_operand:SF 1 "register_operand" "%0,f")
 		 (match_operand:SF 2 "nonmemory_operand" "f,?fF")))
-   (clobber (reg:CC_FLOAT CC_REG))
-  ]
+   (clobber (reg:CC_FLOAT CC_REG))]
   "TARGET_AM33_2"
   "@
    fadd %2, %0
@@ -2781,26 +2639,14 @@
 					(const_int 17) (const_int 14))
 			  (if_then_else (eq_attr "cpu" "am34")
 					(const_int 17) (const_int 25))
-			 ])
-  ]
-)
-
-(define_expand "subsf3"
-  [(parallel [(set (match_operand:SF           0 "register_operand")
-		   (minus:SF (match_operand:SF 1 "register_operand")
-			     (match_operand:SF 2 "nonmemory_operand")))
-	      (clobber (reg:CC_FLOAT CC_REG))])
-  ]
-  "TARGET_AM33_2"
-  ""
+			 ])]
 )
 
-(define_insn "*subsf3_internal"
+(define_insn "subsf3"
   [(set (match_operand:SF           0 "register_operand" "=f,f")
 	(minus:SF (match_operand:SF 1 "register_operand" "0,f")
 		  (match_operand:SF 2 "nonmemory_operand" "f,?fF")))
-   (clobber (reg:CC_FLOAT CC_REG))
-  ]
+   (clobber (reg:CC_FLOAT CC_REG))]
   "TARGET_AM33_2"
   "@
    fsub %2, %0
@@ -2810,21 +2656,10 @@
 					(const_int 17) (const_int 14))
 			  (if_then_else (eq_attr "cpu" "am34")
 					(const_int 17) (const_int 25))
-			 ])
-  ]
+			 ])]
 )
 
-(define_expand "mulsf3"
-  [(parallel [(set (match_operand:SF          0 "register_operand")
-		   (mult:SF (match_operand:SF 1 "register_operand")
-			    (match_operand:SF 2 "nonmemory_operand")))
-	      (clobber (reg:CC_FLOAT CC_REG))])
-  ]
-  "TARGET_AM33_2"
-  ""
-)
-
-(define_insn "*mulsf3_internal"
+(define_insn "mulsf3"
   [(set (match_operand:SF          0 "register_operand" "=f,f")
 	(mult:SF (match_operand:SF 1 "register_operand" "%0,f")
 		 (match_operand:SF 2 "nonmemory_operand" "f,?fF")))
@@ -2839,16 +2674,14 @@
 					(const_int 17) (const_int 14))
 			  (if_then_else (eq_attr "cpu" "am34")
 					(const_int 17) (const_int 25))
-			 ])
-  ]
+			 ])]
 )
 
 (define_insn "divsf3"
   [(set (match_operand:SF         0 "register_operand" "=f,f")
 	(div:SF (match_operand:SF 1 "register_operand"  "0,f")
 		(match_operand:SF 2 "nonmemory_operand" "f,?fF")))
-   (clobber (reg:CC_FLOAT CC_REG))
-  ]
+   (clobber (reg:CC_FLOAT CC_REG))]
   "TARGET_AM33_2"
   "@
    fdiv %2, %0
@@ -2858,8 +2691,7 @@
 					(const_int 2531) (const_int 1216))
 			  (if_then_else (eq_attr "cpu" "am34")
 					(const_int 2531) (const_int 1317))
-			 ])
-  ]
+			 ])]
 )
 
 (define_insn "fmasf4"
-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 90+ messages in thread

* [PATCH 12/28] mn10300: Re-write move patterns.
  2011-01-10 20:33 [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Richard Henderson
                   ` (5 preceding siblings ...)
  2011-01-10 20:33 ` [PATCH 27/28] mn10300: Add support in longlong.h Richard Henderson
@ 2011-01-10 20:33 ` Richard Henderson
  2011-01-18 17:12   ` Jeff Law
  2011-01-10 20:33 ` [PATCH 15/28] mn10300: Force lower-subreg pass to run Richard Henderson
                   ` (22 subsequent siblings)
  29 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-10 20:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: nickc, law, Richard Henderson

From: Richard Henderson <rth@twiddle.net>

Use the "D" and "A" constraints, and the enabled attribute to
unify all ofthe integer move patterns.  Delete the fake double
word move patterns; let the middle-end generate subregs as required.

Unfortunately, this somehow exposes a register pressure problem
with the udivmod pattern.  This is properly fixed with subsequent
patches that expose the MDR register.

In the meantime it is highly desirable to to preserve bisect-ability
of the patch series, so disable this pattern for AM30.
---
 gcc/config/mn10300/mn10300.md |  930 ++++++++---------------------------------
 1 files changed, 166 insertions(+), 764 deletions(-)

diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md
index 04ec1b1..6e0e1a2 100644
--- a/gcc/config/mn10300/mn10300.md
+++ b/gcc/config/mn10300/mn10300.md
@@ -181,107 +181,42 @@
   [(set (match_operand:QI 0 "nonimmediate_operand")
 	(match_operand:QI 1 "general_operand"))]
   ""
-  "
 {
   /* One of the ops has to be in a register.  */
   if (!register_operand (operand0, QImode)
       && !register_operand (operand1, QImode))
-    operands[1] = copy_to_mode_reg (QImode, operand1);
-}")
-
-(define_insn "*am33_movqi"
-  [(set (match_operand:QI 0 "nonimmediate_operand"
-			  ;; 0       1      2      3     4       5
-			  "=d*x*a*f, d*x*a, d*x*a, m,   *f,      d*x*a")
-	(match_operand:QI 1 "general_operand"
-			   "0,       d*xai, m,     d*xa, d*xa*f, *f"))]
-  "TARGET_AM33
-   && (register_operand (operands[0], QImode)
-       || register_operand (operands[1], QImode))"
-  "*
-  {
-    switch (which_alternative)
-      {
-      case 0:
-        return \"nop\";
-      case 1:
-        gcc_assert (! CONST_DOUBLE_P (operands[1]));
-
-        if (REGNO_REG_CLASS (true_regnum (operands[0])) == EXTENDED_REGS
-	    && CONST_INT_P (operands[1]))
-	  {
-	    HOST_WIDE_INT val = INTVAL (operands[1]);
-
-	    if (((val & 0x80) && ! (val & 0xffffff00))
-	        || ((val & 0x800000) && ! (val & 0xff000000)))
-	      return \"movu %1,%0\";
-	  }
-        return \"mov %1,%0\";
-      case 2:
-      case 3:
-        return \"movbu %1,%0\";
-      case 4:
-      case 5:
-        return \"fmov %1,%0\";
-      default:
-        gcc_unreachable ();
-      }
-  }"
-  [(set_attr_alternative "timings"
-			 [(const_int 11)
-			  (if_then_else (eq_attr "cpu" "am34")
-					(const_int 11) (const_int 22))
-			  (if_then_else (eq_attr "cpu" "am34")
-					(const_int 13) (const_int 24))
-			  (if_then_else (eq_attr "cpu" "am34")
-					(const_int 13) (const_int 24))
-			  (if_then_else (eq_attr "cpu" "am34")
-					(const_int 47) (const_int 25))
-			  (if_then_else (eq_attr "cpu" "am34")
-					(const_int 47) (const_int 25))
-			 ])
-  ]
-)
+    operands[1] = force_reg (QImode, operand1);
+})
 
-(define_insn "*mn10300_movqi"
-  [(set (match_operand:QI 0 "nonimmediate_operand" "=d*a,d,d,!*a,d*a,d,m")
-	(match_operand:QI 1 "general_operand"       "0,  I,i,i,  da, m,d"))]
-  "register_operand (operands[0], QImode)
-   || register_operand (operands[1], QImode)"
-  "*
+(define_insn "*movqi_internal"
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=*r,D*r,D*r,D,m")
+	(match_operand:QI 1 "general_operand"      "  0,D*r,  i,m,D"))]
+  "(register_operand (operands[0], QImode)
+    || register_operand (operands[1], QImode))"
 {
   switch (which_alternative)
     {
     case 0:
-      return \"nop\";
+      return "";
     case 1:
     case 2:
+      return "mov %1,%0";
     case 3:
     case 4:
-      gcc_assert (! CONST_DOUBLE_P (operands[1]));
-      return \"mov %1,%0\";
-    case 5:
-    case 6:
-      return \"movbu %1,%0\";
+      return "movbu %1,%0";
     default:
       gcc_unreachable ();
     }
-}"
+}
   [(set_attr_alternative "timings"
-			 [(const_int 11)
-			  (const_int 11)
-			  (if_then_else (eq_attr "cpu" "am34")
-			  		(const_int 11) (const_int 22))
-			  (if_then_else (eq_attr "cpu" "am34")
-			  		(const_int 11) (const_int 22))
-			  (if_then_else (eq_attr "cpu" "am34")
-			  		(const_int 11) (const_int 22))
-			  (if_then_else (eq_attr "cpu" "am34")
-			  		(const_int 13) (const_int 24))
-			  (if_then_else (eq_attr "cpu" "am34")
-			  		(const_int 13) (const_int 24))
-			 ])
-  ]
+	 [(const_int 11)
+	  (const_int 11)
+	  (const_int 11)
+	  (if_then_else (eq_attr "cpu" "am34")
+			(const_int 13) (const_int 24))
+	  (if_then_else (eq_attr "cpu" "am34")
+			(const_int 11) (const_int 22))
+	 ])]
 )
 
 ;; movhi
@@ -290,107 +225,48 @@
   [(set (match_operand:HI 0 "nonimmediate_operand")
 	(match_operand:HI 1 "general_operand"))]
   ""
-  "
 {
   /* One of the ops has to be in a register.  */
   if (!register_operand (operand1, HImode)
       && !register_operand (operand0, HImode))
-    operands[1] = copy_to_mode_reg (HImode, operand1);
-}")
-
-(define_insn "*am33_movhi"
-  [(set (match_operand:HI 0 "nonimmediate_operand"
-			  ;; 0       1       2      3     4         5
-			  "=d*x*a*f, d*x*a,  d*x*a, m,    *f,       d*x*a")
-	(match_operand:HI 1 "general_operand"
-			  "0,        d*x*ai, m,     d*x*a, d*x*a*f, *f"))]
-  "TARGET_AM33
-   && (register_operand (operands[0], HImode)
-       || register_operand (operands[1], HImode))"
-  "*
-{
-  switch (which_alternative)
-    {
-    case 0:
-      return \"nop\";
-    case 1:
-      gcc_assert (! CONST_DOUBLE_P (operands[1]));
-
-      if (REGNO_REG_CLASS (true_regnum (operands[0])) == EXTENDED_REGS
-	  && CONST_INT_P (operands[1]))
-	{
-	  HOST_WIDE_INT val = INTVAL (operands[1]);
-
-	  if (((val & 0x80) && ! (val & 0xffffff00))
-	      || ((val & 0x800000) && ! (val & 0xff000000)))
-	    return \"movu %1,%0\";
-	}
-      return \"mov %1,%0\";
-    case 2:
-    case 3:
-      return \"movhu %1,%0\";
-    case 4:
-    case 5:
-      return \"fmov %1,%0\";
-    default:
-      gcc_unreachable ();
-    }
-}"
-  [(set_attr_alternative "timings"
-			 [(const_int 11)
-			  (if_then_else (eq_attr "cpu" "am34")
-			  		(const_int 11) (const_int 22))
-			  (if_then_else (eq_attr "cpu" "am34")
-			  		(const_int 13) (const_int 24))
-			  (if_then_else (eq_attr "cpu" "am34")
-			  		(const_int 13) (const_int 24))
-			  (if_then_else (eq_attr "cpu" "am34")
-			  		(const_int 47) (const_int 25))
-			  (if_then_else (eq_attr "cpu" "am34")
-			  		(const_int 47) (const_int 25))
-			 ])
-  ]
-)
+    operands[1] = force_reg (HImode, operand1);
+})
 
-(define_insn "*mn10300_movhi"
-  [(set (match_operand:HI 0 "nonimmediate_operand" "=d*a,d,d,!*a,d*a,d,m")
-	(match_operand:HI 1 "general_operand"       "0,  I,i,i,  da, m,d"))]
-  "register_operand (operands[0], HImode)
-   || register_operand (operands[1], HImode)"
-  "*
+(define_insn "*movhi_internal"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=*r,D*r,D*r,D,m")
+	(match_operand:HI 1 "general_operand"      "  0,  i,D*r,m,D"))]
+  "(register_operand (operands[0], HImode)
+    || register_operand (operands[1], HImode))"
 {
   switch (which_alternative)
     {
     case 0:
-      return \"nop\";
+      return "";
     case 1:
+      if (TARGET_AM33
+	  && CONST_INT_P (operands[1])
+	  && IN_RANGE (INTVAL (operands[1]), 0x80, 0xff))
+	return "movu %1,%0";
+      /* FALLTHRU */
     case 2:
+      return "mov %1,%0";
     case 3:
     case 4:
-      gcc_assert (! CONST_DOUBLE_P (operands[1]));
-      return \"mov %1,%0\";
-    case 5:
-    case 6:
-      return \"movhu %1,%0\";
+      return "movhu %1,%0";
     default:
       gcc_unreachable ();
     }
-}"
+}
   [(set_attr_alternative "timings"
-			 [(const_int 11)
-			  (const_int 11)
-			  (if_then_else (eq_attr "cpu" "am34")
-			  		(const_int 11) (const_int 22))
-			  (if_then_else (eq_attr "cpu" "am34")
-			  		(const_int 11) (const_int 22))
-			  (if_then_else (eq_attr "cpu" "am34")
-			  		(const_int 11) (const_int 22))
-			  (if_then_else (eq_attr "cpu" "am34")
-			  		(const_int 13) (const_int 24))
-			  (if_then_else (eq_attr "cpu" "am34")
-			  		(const_int 13) (const_int 24))
-			 ])
-  ]
+	 [(const_int 11)
+	  (const_int 11)
+	  (if_then_else (eq_attr "cpu" "am34")
+	  		(const_int 11) (const_int 22))
+	  (if_then_else (eq_attr "cpu" "am34")
+	  		(const_int 13) (const_int 24))
+	  (if_then_else (eq_attr "cpu" "am34")
+	  		(const_int 11) (const_int 22))
+	 ])]
 )
 
 ;; movsi and helpers
@@ -450,12 +326,11 @@
   [(set (match_operand:SI 0 "nonimmediate_operand")
 	(match_operand:SI 1 "general_operand"))]
   ""
-  "
 {
   /* One of the ops has to be in a register.  */
   if (!register_operand (operand1, SImode)
       && !register_operand (operand0, SImode))
-    operands[1] = copy_to_mode_reg (SImode, operand1);
+    operands[1] = force_reg (SImode, operand1);
   if (flag_pic)
     {
       rtx temp;
@@ -486,594 +361,118 @@
 				      0, OPTAB_LIB_WIDEN);
 	}
     }
-}")
+})
 
 (define_insn "*movsi_internal"
   [(set (match_operand:SI 0 "nonimmediate_operand"
-			  "=dax, dax,  m,   dax, ax,!*y")
+			  "=r,r,r,m,r, A,*y,*y")
 	(match_operand:SI 1 "general_operand"
-			  "0,    Idax, dax, im, !*y, ax"))
-  ]
+			  " 0,i,r,r,m,*y, A, i"))]
   "register_operand (operands[0], SImode)
    || register_operand (operands[1], SImode)"
-  "*
-  {
-    if (which_alternative == 0)
-      return \"nop\";
-
-    gcc_assert (! CONST_DOUBLE_P (operands[1]));
-
-    if (REGNO_REG_CLASS (true_regnum (operands[0])) == EXTENDED_REGS
-        && CONST_INT_P (operands[1]))
-      {
-        HOST_WIDE_INT val = INTVAL (operands[1]);
-
-        if (((val & 0x80) && ! (val & 0xffffff00))
-            || ((val & 0x800000) && ! (val & 0xff000000)))
-          return \"movu %1, %0\";
-      }
-
-    return \"mov %1, %0\";
-  }"
-  [(set_attr_alternative "timings"
-			 [(const_int 11)
-			  (if_then_else (eq_attr "cpu" "am34")
-					(const_int 13) (const_int 24))
-			  (if_then_else (eq_attr "cpu" "am34")
-					(const_int 13) (const_int 24))
-			  (if_then_else (eq_attr "cpu" "am34")
-					(const_int 13) (const_int 24))
-			  (if_then_else (eq_attr "cpu" "am34")
-					(const_int 13) (const_int 24))
-			  (if_then_else (eq_attr "cpu" "am34")
-					(const_int 13) (const_int 24))
-			 ])
-  ]
+{
+  switch (which_alternative)
+    {
+    case 0:
+      return "";
+    case 1: /* imm-reg*/
+      if (TARGET_AM33 && CONST_INT_P (operands[1]))
+	{
+	  HOST_WIDE_INT val = INTVAL (operands[1]);
+	  if (IN_RANGE (val, 0x80, 0xff)
+	      || IN_RANGE (val, 0x800000, 0xffffff))
+	    return "movu %1,%0";
+	}
+      /* FALLTHRU */
+    case 2:  /* reg-reg */
+    case 3:  /* reg-mem */
+    case 4:  /* mem-reg */
+    case 5:  /* sp-reg */
+    case 6:  /* reg-sp */
+    case 7:  /* imm-sp */
+      return "mov %1,%0";
+    default:
+      gcc_unreachable ();
+    }
+}
+  [(set_attr "isa" "*,*,*,*,*,*,*,am33")
+   (set_attr_alternative "timings"
+	 [(const_int 11)
+	  (const_int 22)
+	  (const_int 11)
+	  (if_then_else (eq_attr "cpu" "am34")
+			(const_int 11) (const_int 22))
+	  (if_then_else (eq_attr "cpu" "am34")
+			(const_int 13) (const_int 24))
+	  (if_then_else (eq_attr "cpu" "am34")
+			(const_int 11) (const_int 22))
+	  (if_then_else (eq_attr "cpu" "am34")
+			(const_int 13) (const_int 24))
+	  (const_int 11)
+	 ])]
 )
 
 (define_expand "movsf"
   [(set (match_operand:SF 0 "nonimmediate_operand")
 	(match_operand:SF 1 "general_operand"))]
-  ""
-  "
+  "TARGET_AM33_2"
 {
   /* One of the ops has to be in a register.  */
   if (!register_operand (operand1, SFmode)
       && !register_operand (operand0, SFmode))
-    operands[1] = copy_to_mode_reg (SFmode, operand1);
-}")
+    operands[1] = force_reg (SFmode, operand1);
+})
 
 (define_insn "*movsf_internal"
-  [(set (match_operand:SF 0 "nonimmediate_operand"
-			  ;; 0    1    2       3     4     5
-			  "=fdxa, dxa, f,      dxaQ, daxm, dax")
-	(match_operand:SF 1 "general_operand"
-			  " 0,    G,   fdxaQF, f,    dax,  daxFm"))
-  ]
-  "register_operand (operands[0], SFmode)
-   || register_operand (operands[1], SFmode)"
-  "*
-  {
-    switch (which_alternative)
-      {
-      case 0:
-        return \"nop\";
-      /* case 1: below.  */
-      case 2:
-      case 3:
-        return \"fmov %1, %0\";
-      case 1:
-      case 4:
-      case 5:
-        if (REGNO_REG_CLASS (true_regnum (operands[0])) == EXTENDED_REGS
-	    && CONST_INT_P (operands[1]))
-	  {
-	    HOST_WIDE_INT val = INTVAL (operands[1]);
-
-	    if (((val & 0x80) && ! (val & 0xffffff00))
-	        || ((val & 0x800000) && ! (val & 0xff000000)))
-	      return \"movu %1, %0\";
-	  }
-        return \"mov %1, %0\";
-      default:
-        gcc_unreachable ();
-      }
-  }"
-  [(set_attr_alternative "timings"
-			 [(const_int 11)
-			  (if_then_else (eq_attr "cpu" "am34")
-					(const_int 13) (const_int 24))
-			  (if_then_else (eq_attr "cpu" "am34")
-					(const_int 47) (const_int 25))
-			  (if_then_else (eq_attr "cpu" "am34")
-					(const_int 47) (const_int 25))
-			  (if_then_else (eq_attr "cpu" "am34")
-					(const_int 13) (const_int 24))
-			  (if_then_else (eq_attr "cpu" "am34")
-					(const_int 13) (const_int 24))
-			 ])
-  ]
-)
-
-(define_expand "movdi"
-  [(set (match_operand:DI 0 "nonimmediate_operand")
-	(match_operand:DI 1 "general_operand"))]
-  ""
-  "
-{
-  /* One of the ops has to be in a register.  */
-  if (!register_operand (operand1, DImode)
-      && !register_operand (operand0, DImode))
-    operands[1] = copy_to_mode_reg (DImode, operand1);
-}")
-
-
-(define_insn "*movdi_internal"                   ;;   0 1  2  3 4   5   6  7 8  9
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=dx,ax,dx,a,dxm,dxm,a, a,dx,a")
-	(match_operand:DI 1 "general_operand"        "0,0, I, I,dx, a,  dx,a,im,im"))]
-  "register_operand (operands[0], DImode)
-   || register_operand (operands[1], DImode)"
-  "*
+  [(set (match_operand:SF 0 "nonimmediate_operand" "=rf,r,f,r,f,r,f,r,m,f,Q")
+	(match_operand:SF 1 "general_operand"	   "  0,F,F,r,f,f,r,m,r,Q,f"))]
+  "TARGET_AM33_2
+   && (register_operand (operands[0], SFmode)
+       || register_operand (operands[1], SFmode))"
 {
-  long val[2];
-  REAL_VALUE_TYPE rv;
-
   switch (which_alternative)
     {
-      case 0:
-      case 1:
-	return \"nop\";
-
-      case 2:
-	return \"mov 0, %L0\;mov 0, %H0\";
-
-      case 3:
-	if (rtx_equal_p (operands[0], operands[1]))
-	  return \"sub %L1,%L0\;mov %L0,%H0\";
-	else
-	  return \"mov %1,%L0\;mov %L0,%H0\";
-      case 4:
-      case 5:
-      case 6:
-      case 7:
-      case 8:
-      case 9:
-	if (CONST_INT_P (operands[1]))
-	  {
-	    rtx low, high;
-	    split_double (operands[1], &low, &high);
-	    val[0] = INTVAL (low);
-	    val[1] = INTVAL (high);
-	  }
-	if (CONST_DOUBLE_P (operands[1]))
-	  {
-	    if (GET_MODE (operands[1]) == DFmode)
-	      {
-		REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
-		REAL_VALUE_TO_TARGET_DOUBLE (rv, val);
-	      }
-	    else if (GET_MODE (operands[1]) == VOIDmode
-		     || GET_MODE (operands[1]) == DImode)
-	      {
-		val[0] = CONST_DOUBLE_LOW (operands[1]);
-		val[1] = CONST_DOUBLE_HIGH (operands[1]);
-	      }
-	  }
-
-	if (MEM_P (operands[1])
-	    && reg_overlap_mentioned_p (operands[0], XEXP (operands[1], 0)))
-	  {
-	    rtx temp = operands[0];
-
-	    while (GET_CODE (temp) == SUBREG)
-	      temp = SUBREG_REG (temp);
-
-	    gcc_assert (REG_P (temp));
-
-	    if (reg_overlap_mentioned_p (gen_rtx_REG (SImode, REGNO (temp)),
-					 XEXP (operands[1], 0)))
-	      return \"mov %H1,%H0\;mov %L1,%L0\";
-	    else
-	      return \"mov %L1,%L0\;mov %H1,%H0\";
-
-	  }
-	else if (MEM_P (operands[1])
-		 && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))
-		 && REGNO_REG_CLASS (REGNO (operands[0])) == ADDRESS_REGS)
-	  {
-	    rtx xoperands[2];
-
-	    xoperands[0] = operands[0];
-	    xoperands[1] = XEXP (operands[1], 0);
-
-	    output_asm_insn (\"mov %1,%L0\;mov (4,%L0),%H0\;mov (%L0),%L0\",
-			     xoperands);
-	    return \"\";
-	  }
-	else
-	  {
-	    if ((CONST_INT_P (operands[1])
-		 || CONST_DOUBLE_P (operands[1]))
-		&& val[0] == 0)
-	      {
-		if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
-		  output_asm_insn (\"mov 0, %L0\", operands);
-		else
-		  output_asm_insn (\"mov %L1,%L0\", operands);
-	      }
-	    else if ((CONST_INT_P (operands[1])
-		      || CONST_DOUBLE_P (operands[1]))
-		     && (REGNO_REG_CLASS (true_regnum (operands[0]))
-			 == EXTENDED_REGS)
-		     && (((val[0] & 0x80) && ! (val[0] & 0xffffff00))
-			 || ((val[0] & 0x800000) && ! (val[0] & 0xff000000))))
-	      output_asm_insn (\"movu %L1,%L0\", operands);
-	    else
-	      output_asm_insn (\"mov %L1,%L0\", operands);
-
-	    if ((CONST_INT_P (operands[1])
-		 || CONST_DOUBLE_P (operands[1]))
-		&& val[1] == 0)
-	      {
-		if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
-		  output_asm_insn (\"mov 0, %H0\", operands);
-		else
-		  output_asm_insn (\"mov %H1,%H0\", operands);
-	      }
-	    else if ((CONST_INT_P (operands[1])
-		      || CONST_DOUBLE_P (operands[1]))
-		     && val[0] == val[1])
-	      output_asm_insn (\"mov %L0,%H0\", operands);
-	    else if ((CONST_INT_P (operands[1])
-		      || CONST_DOUBLE_P (operands[1]))
-		     && (REGNO_REG_CLASS (true_regnum (operands[0]))
-			 == EXTENDED_REGS)
-		     && (((val[1] & 0x80) && ! (val[1] & 0xffffff00))
-			 || ((val[1] & 0x800000) && ! (val[1] & 0xff000000))))
-	      output_asm_insn (\"movu %H1,%H0\", operands);
-	    else
-	      output_asm_insn (\"mov %H1,%H0\", operands);
-	    return \"\";
-	  }
-    default:
-      gcc_unreachable ();
-    }
-  }"
-  ;; The timing of "37" is an approximation of the worst case sceanario.
-  [(set_attr_alternative "timings"
-			 [(const_int 11)
-			  (const_int 11)
-			  (const_int 22)
-			  (const_int 22)
-			  (const_int 37)
-			  (const_int 37)
-			  (const_int 37)
-			  (const_int 37)
-			  (const_int 37)
-			  (const_int 37)
-			 ])
-  ]
-)
-
-(define_expand "movdf"
-  [(set (match_operand:DF 0 "nonimmediate_operand")
-	(match_operand:DF 1 "general_operand"))]
-  ""
-  "
-{
-  /* One of the ops has to be in a register.  */
-  if (!register_operand (operand1, DFmode)
-      && !register_operand (operand0, DFmode))
-    operands[1] = copy_to_mode_reg (DFmode, operand1);
-}")
-
-(define_insn "*am33_2_movdf"
-  [(set (match_operand:DF 0 "nonimmediate_operand"
-			  ;; 0   1   2    3    4 5 6   7   8  9 10 11
-			  "=fdax,dax,fdxa,f,   f,Q,dxm,dxm,a, a,dx,a")
-	(match_operand:DF 1 "general_operand"
-			  " 0,   G,  f,   dxaF,Q,f,dx, a,  dx,a,Fm,Fm"))]
-  "TARGET_AM33_2
-   && (register_operand (operands[0], DFmode)
-       || register_operand (operands[1], DFmode))"
-  "*
-  {
-    long val[2];
-    REAL_VALUE_TYPE rv;
-
-    switch (which_alternative)
-      {
-      case 0:
-	return \"nop\";
-
-      case 1:
-	return \"mov 0, %L0\; mov 0, %H0\";
-
-      case 2:
-      case 3:
-        return \"fmov %L1, %L0\; fmov %H1, %H0\";
-
-      case 4:
-	if (MEM_P (operands[1])
-	    && CONST_INT_P (XEXP (operands[1], 0))
-	    && (INTVAL (XEXP (operands[1], 0)) & 7) == 0)
-	  return \"fmov %D1, %D0\";
-	else
-          return \"fmov %L1, %L0\; fmov %H1, %H0\";
-
-      case 5:
-	if (MEM_P (operands[0])
-	    && CONST_INT_P (XEXP (operands[0], 0))
-	    && (INTVAL (XEXP (operands[0], 0)) & 7) == 0)
-	  return \"fmov %D1, %D0\";
-	else
-          return \"fmov %L1, %L0\; fmov %H1, %H0\";
-
-      case 6:
-      case 7:
-      case 8:
-      case 9:
-      case 10:
-      case 11:
-	if (CONST_INT_P (operands[1]))
-	  {
-	    rtx low, high;
-	    split_double (operands[1], &low, &high);
-	    val[0] = INTVAL (low);
-	    val[1] = INTVAL (high);
-	  }
-	if (CONST_DOUBLE_P (operands[1]))
-	  {
-	    if (GET_MODE (operands[1]) == DFmode)
-	      {
-		REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
-		REAL_VALUE_TO_TARGET_DOUBLE (rv, val);
-	      }
-	    else if (GET_MODE (operands[1]) == VOIDmode
-		     || GET_MODE (operands[1]) == DImode)
-	      {
-		val[0] = CONST_DOUBLE_LOW (operands[1]);
-		val[1] = CONST_DOUBLE_HIGH (operands[1]);
-	      }
-	  }
-
-	if (MEM_P (operands[1])
-	    && reg_overlap_mentioned_p (operands[0], XEXP (operands[1], 0)))
-	  {
-	    rtx temp = operands[0];
-
-	    while (GET_CODE (temp) == SUBREG)
-	      temp = SUBREG_REG (temp);
-
-	    gcc_assert (REG_P (temp));
-
-	    if (reg_overlap_mentioned_p (gen_rtx_REG (SImode, REGNO (temp)),
-					 XEXP (operands[1], 0)))
-	      return \"mov %H1, %H0\; mov %L1, %L0\";
-	    else
-	      return \"mov %L1, %L0\; mov %H1, %H0\";
-
-	  }
-	else if (MEM_P (operands[1])
-		 && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))
-		 && REGNO_REG_CLASS (REGNO (operands[0])) == ADDRESS_REGS)
-	  {
-	    rtx xoperands[2];
-
-	    xoperands[0] = operands[0];
-	    xoperands[1] = XEXP (operands[1], 0);
-
-	    output_asm_insn (\"mov %1, %L0\; mov (4, %L0), %H0\; mov (%L0), %L0\",
-			     xoperands);
-	    return \"\";
-	  }
-	else
-	  {
-	    if ((CONST_INT_P (operands[1])
-		 || CONST_DOUBLE_P (operands[1]))
-		&& val[0] == 0)
-	      {
-		if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
-		  output_asm_insn (\"mov 0, %L0\", operands);
-		else
-		  output_asm_insn (\"mov %L1,%L0\", operands);
-	      }
-	    else if ((CONST_INT_P (operands[1])
-		      || CONST_DOUBLE_P (operands[1]))
-		     && (REGNO_REG_CLASS (true_regnum (operands[0]))
-			 == EXTENDED_REGS)
-		     && (((val[0] & 0x80) && ! (val[0] & 0xffffff00))
-			 || ((val[0] & 0x800000) && ! (val[0] & 0xff000000))))
-	      output_asm_insn (\"movu %L1, %L0\", operands);
-	    else
-	      output_asm_insn (\"mov %L1, %L0\", operands);
-
-	    if ((CONST_INT_P (operands[1])
-		 || CONST_DOUBLE_P (operands[1]))
-		&& val[1] == 0)
-	      {
-		if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
-		  output_asm_insn (\"mov 0, %H0\", operands);
-		else
-		  output_asm_insn (\"mov %H1, %H0\", operands);
-	      }
-	    else if ((CONST_INT_P (operands[1])
-		      || CONST_DOUBLE_P (operands[1]))
-		     && val[0] == val[1])
-	      output_asm_insn (\"mov %L0,%H0\", operands);
-	    else if ((CONST_INT_P (operands[1])
-		      || CONST_DOUBLE_P (operands[1]))
-		     && (REGNO_REG_CLASS (true_regnum (operands[0]))
-			 == EXTENDED_REGS)
-		     && (((val[1] & 0x80) && ! (val[1] & 0xffffff00))
-			 || ((val[1] & 0x800000) && ! (val[1] & 0xff000000))))
-	      output_asm_insn (\"movu %H1, %H0\", operands);
-	    else
-	      output_asm_insn (\"mov %H1, %H0\", operands);
-	    return \"\";
-	  }
+    case 0:
+      return "";
+    case 1:
+    case 3:
+    case 7:
+    case 8:
+      return "mov %1,%0";
+    case 2:
+    case 4:
+    case 5:
+    case 6:
+    case 9:
+    case 10:
+      return "fmov %1,%0";
     default:
       gcc_unreachable ();
     }
-  }"
-  ;; The timing of "37" is an approximation of the worst case sceanario.
+}
   [(set_attr_alternative "timings"
-			 [(const_int 11)
-			  (const_int 22)
-			  (const_int 22)
-			  (const_int 22)
-			  (const_int 22)
-			  (const_int 37)
-			  (const_int 37)
-			  (const_int 37)
-			  (const_int 37)
-			  (const_int 37)
-			  (const_int 37)
-			  (const_int 37)
-			 ])
-  ]
+		 [(const_int 11)
+		  (const_int 22)
+		  (if_then_else (eq_attr "cpu" "am34")
+				(const_int 47) (const_int 25))
+		  (const_int 11)
+		  (if_then_else (eq_attr "cpu" "am34")
+				(const_int 13) (const_int 14))
+		  (if_then_else (eq_attr "cpu" "am34")
+				(const_int 13) (const_int 12))
+		  (if_then_else (eq_attr "cpu" "am34")
+				(const_int 13) (const_int 14))
+		  (if_then_else (eq_attr "cpu" "am34")
+				(const_int 13) (const_int 24))
+		  (if_then_else (eq_attr "cpu" "am34")
+				(const_int 13) (const_int 24))
+		  (if_then_else (eq_attr "cpu" "am34")
+				(const_int 13) (const_int 24))
+		  (if_then_else (eq_attr "cpu" "am34")
+				(const_int 13) (const_int 24))
+		 ])]
 )
 
-(define_insn "*mn10300_movdf"
-  [(set (match_operand:DF 0 "nonimmediate_operand"
-			  ;;0    1    2    3    4   5  6   7
-			  "=dxa, dax, dxm, dxm, a,  a, dx, a")
-	(match_operand:DF 1 "general_operand"
-			  " 0,   G,   dx,  a,   dx, a, Fm, Fm"))]
-  "register_operand (operands[0], DFmode)
-   || register_operand (operands[1], DFmode)"
-  "*
-  {
-    long val[2];
-    REAL_VALUE_TYPE rv;
-
-    switch (which_alternative)
-      {
-      case 0:
-	return \"nop\";
-
-      case 1:
-	return \"mov 0, %L0\; mov 0, %H0\";
-
-      case 2:
-      case 3:
-      case 4:
-      case 5:
-      case 6:
-      case 7:
-	if (CONST_INT_P (operands[1]))
-	  {
-	    rtx low, high;
-	    split_double (operands[1], &low, &high);
-	    val[0] = INTVAL (low);
-	    val[1] = INTVAL (high);
-	  }
-        if (CONST_DOUBLE_P (operands[1]))
-	  {
-	    if (GET_MODE (operands[1]) == DFmode)
-	      {
-		REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
-		REAL_VALUE_TO_TARGET_DOUBLE (rv, val);
-	      }
-	    else if (GET_MODE (operands[1]) == VOIDmode
-		     || GET_MODE (operands[1]) == DImode)
-	      {
-		val[0] = CONST_DOUBLE_LOW (operands[1]);
-		val[1] = CONST_DOUBLE_HIGH (operands[1]);
-	      }
-	  }
-
-	if (MEM_P (operands[1])
-	    && reg_overlap_mentioned_p (operands[0], XEXP (operands[1], 0)))
-	  {
-	    rtx temp = operands[0];
-
-	    while (GET_CODE (temp) == SUBREG)
-	      temp = SUBREG_REG (temp);
-
-	    gcc_assert (REG_P (temp));
-
-	    if (reg_overlap_mentioned_p (gen_rtx_REG (SImode, REGNO (temp)),
-					 XEXP (operands[1], 0)))
-	      return \"mov %H1, %H0\; mov %L1, %L0\";
-	    else
-	      return \"mov %L1, %L0\; mov %H1, %H0\";
-	  }
-	else if (MEM_P (operands[1])
-		 && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))
-		 && REGNO_REG_CLASS (REGNO (operands[0])) == ADDRESS_REGS)
-	  {
-	    rtx xoperands[2];
-
-	    xoperands[0] = operands[0];
-	    xoperands[1] = XEXP (operands[1], 0);
-
-	    output_asm_insn (\"mov %1, %L0\; mov (4, %L0), %H0\; mov (%L0), %L0\",
-			     xoperands);
-	    return \"\";
-	  }
-	else
-	  {
-	    if ((CONST_INT_P (operands[1])
-		 || CONST_DOUBLE_P (operands[1]))
-		&& val[0] == 0)
-	      {
-		if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
-		  output_asm_insn (\"mov 0, %L0\", operands);
-		else
-		  output_asm_insn (\"mov %L1, %L0\", operands);
-	      }
-	    else if ((CONST_INT_P (operands[1])
-		      || CONST_DOUBLE_P (operands[1]))
-		     && (REGNO_REG_CLASS (true_regnum (operands[0]))
-			 == EXTENDED_REGS)
-		     && (((val[0] & 0x80) && ! (val[0] & 0xffffff00))
-			 || ((val[0] & 0x800000) && ! (val[0] & 0xff000000))))
-	      output_asm_insn (\"movu %L1, %L0\", operands);
-	    else
-	      output_asm_insn (\"mov %L1, %L0\", operands);
-
-	    if ((CONST_INT_P (operands[1])
-		 || CONST_DOUBLE_P (operands[1]))
-		&& val[1] == 0)
-	      {
-		if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
-		  output_asm_insn (\"mov 0, %H0\", operands);
-		else
-		  output_asm_insn (\"mov %H1, %H0\", operands);
-	      }
-	    else if ((CONST_INT_P (operands[1])
-		      || CONST_DOUBLE_P (operands[1]))
-		     && val[0] == val[1])
-	      output_asm_insn (\"mov %L0, %H0\", operands);
-	    else if ((CONST_INT_P (operands[1])
-		      || CONST_DOUBLE_P (operands[1]))
-		     && (REGNO_REG_CLASS (true_regnum (operands[0]))
-			 == EXTENDED_REGS)
-		     && (((val[1] & 0x80) && ! (val[1] & 0xffffff00))
-			 || ((val[1] & 0x800000) && ! (val[1] & 0xff000000))))
-	      output_asm_insn (\"movu %H1, %H0\", operands);
-	    else
-	      output_asm_insn (\"mov %H1, %H0\", operands);
-	    return \"\";
-	  }
-    default:
-      gcc_unreachable ();
-    }
-  }"
-  ;; Timings of "37" is approximation of the worst case sceanario.
-  [(set_attr_alternative "timings"
-			 [(const_int 11)
-			  (const_int 22)
-			  (const_int 37)
-			  (const_int 37)
-			  (const_int 37)
-			  (const_int 37)
-			  (const_int 37)
-			  (const_int 37)
-			 ])
-  ]
-)
 \f
 ;; ----------------------------------------------------------------------
 ;; ADD INSTRUCTIONS
@@ -1363,42 +762,23 @@
   	      		 	       (const_int 24) (const_int 23)))]
 )
 
-(define_expand "udivmodsi4"
-  [(parallel [(set (match_operand:SI          0 "register_operand")
-		   (udiv:SI (match_operand:SI 1 "general_operand")
-			    (match_operand:SI 2 "general_operand")))
-	      (set (match_operand:SI          3 "register_operand")
-		   (umod:SI (match_dup 1) (match_dup 2)))
-	      (clobber (reg:CC CC_REG))
-	     ])
-  ]
-  ""
-  "{
-    if (!register_operand (operands[1], SImode))
-      operands[1] = copy_to_mode_reg (SImode, operands[1]);
-    if (!register_operand (operands[2], SImode))
-      operands[2] = copy_to_mode_reg (SImode, operands[2]);
-   }"
-)
-
-(define_insn "*udivmodsi4"
-  [(set (match_operand:SI          0 "register_operand" "=dx")
+;; ??? This pattern causes too-high register pressure for MN103.
+;; ??? To be fixed by exposing the MDR register properly.
+(define_insn "udivmodsi4"
+  [(set (match_operand:SI          0 "register_operand" "=D")
 	(udiv:SI (match_operand:SI 1 "register_operand" "0")
-		 (match_operand:SI 2 "register_operand" "dx")))
+		 (match_operand:SI 2 "register_operand" "D")))
    (set (match_operand:SI          3 "register_operand" "=&d")
 	(umod:SI (match_dup 1) (match_dup 2)))
-   (clobber (reg:CC CC_REG))
-  ]
-  ""
-  "*
+   (clobber (reg:CC CC_REG))]
+  "TARGET_AM33"
 {
-  output_asm_insn (\"sub %3,%3\;mov %3,mdr\", operands);
-
+  output_asm_insn ("clr %3\;ext %3", operands);
   if (find_reg_note (insn, REG_UNUSED, operands[3]))
-    return \"divu %2,%0\";
+    return "divu %2,%0";
   else
-    return \"divu %2,%0\;mov mdr,%3\";
-}"
+    return "divu %2,%0\;mov mdr,%3";
+}
   ;; Timings:  AM33   AM34
   ;;  SUB       1/1    1/1
   ;;  MOV       1/1    1/1
@@ -1410,6 +790,28 @@
   	      		 	       (const_int 4546) (const_int 4142)))]
 )
 
+;; ??? In the meantime MN103 can use these two patterns,
+;; which reduce the register pressure by one.
+(define_insn "udivsi3"
+  [(set (match_operand:SI          0 "register_operand" "=&d")
+	(udiv:SI (match_operand:SI 1 "register_operand" "d")
+		 (match_operand:SI 2 "register_operand" "d")))
+   (clobber (reg:CC CC_REG))]
+  "!TARGET_AM33"
+  "clr %0\;ext %0\;mov %1,%0\;divu %2,%0"
+  [(set_attr "timings" "4142")]
+)
+
+(define_insn "umodsi3"
+  [(set (match_operand:SI          0 "register_operand" "=&d")
+	(umod:SI (match_operand:SI 1 "register_operand" "d")
+		 (match_operand:SI 2 "register_operand" "d")))
+   (clobber (reg:CC CC_REG))]
+  "!TARGET_AM33"
+  "clr %0\;ext %0\;mov %1,%0\;divu %2,%0\;mov mdr,%0"
+  [(set_attr "timings" "4142")]
+)
+
 (define_insn "divmodsi4"
   [(set (match_operand:SI          0 "register_operand" "=dx")
 	(div:SI (match_operand:SI  1 "register_operand"  "0")
-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 90+ messages in thread

* [PATCH 15/28] mn10300: Force lower-subreg pass to run.
  2011-01-10 20:33 [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Richard Henderson
                   ` (6 preceding siblings ...)
  2011-01-10 20:33 ` [PATCH 12/28] mn10300: Re-write move patterns Richard Henderson
@ 2011-01-10 20:33 ` Richard Henderson
  2011-01-12 14:04   ` Jeff Law
  2011-01-10 20:33 ` [PATCH 21/28] mn10300: Add clzsi2 Richard Henderson
                   ` (21 subsequent siblings)
  29 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-10 20:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: nickc, law, Richard Henderson

From: Richard Henderson <rth@twiddle.net>

There are a number of tests that fail -- generally ones involving
generic vectorization -- at -O0 because we run out of registers.
The lower-subreg pass cleans things up sufficiently to allow these
tests to succeed.
---
 gcc/config/mn10300/mn10300.c |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c
index 32fb57d..f9dab21 100644
--- a/gcc/config/mn10300/mn10300.c
+++ b/gcc/config/mn10300/mn10300.c
@@ -127,6 +127,12 @@ mn10300_option_override (void)
 	 not have timing information available for it.  */
       flag_schedule_insns = 0;
       flag_schedule_insns_after_reload = 0;
+
+      /* Force enable splitting of wide types, as otherwise it is trivial
+	 to run out of registers.  Indeed, this works so well that register
+	 allocation problems are now more common *without* optimization,
+	 when this flag is not enabled by default.  */
+      flag_split_wide_types = 1;
     }
   
   if (mn10300_tune_string)
-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 90+ messages in thread

* [PATCH 20/28] mn10300: Emit clr.
  2011-01-10 20:33 [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Richard Henderson
                   ` (2 preceding siblings ...)
  2011-01-10 20:32 ` [PATCH 13/28] mn10300: cleanup secondary reloads Richard Henderson
@ 2011-01-10 20:33 ` Richard Henderson
  2011-01-12 14:05   ` Jeff Law
  2011-01-10 20:33 ` [PATCH 02/28] mn10300: disable test tree-ssa/vrp47.c Richard Henderson
                   ` (25 subsequent siblings)
  29 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-10 20:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: nickc, law, Richard Henderson

From: Richard Henderson <rth@twiddle.net>

---
 gcc/config/mn10300/mn10300.md |   25 +++++++++++++++++++++++++
 1 files changed, 25 insertions(+), 0 deletions(-)

diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md
index 24c8d11..4f4fdfe 100644
--- a/gcc/config/mn10300/mn10300.md
+++ b/gcc/config/mn10300/mn10300.md
@@ -70,8 +70,13 @@
 	]
 	(const_int 0))
 )
+
+(define_mode_iterator INT [QI HI SI])
+
 \f
+;; ----------------------------------------------------------------------
 ;; Pipeline description.
+;; ----------------------------------------------------------------------
 
 ;; The AM33 only has a single pipeline.  It has five stages (fetch,
 ;; decode, execute, memory access, writeback) each of which normally
@@ -480,6 +485,26 @@
 				(const_int 13) (const_int 24))
 		 ])]
 )
+
+;; If the flags register is not live, generate CLR instead of MOV 0.
+;; For MN103, this is only legal for DATA_REGS; for AM33 this is legal
+;; but not a win for ADDRESS_REGS.
+(define_peephole2
+  [(set (match_operand:INT 0 "register_operand" "") (const_int 0))]
+  "peep2_regno_dead_p (0, CC_REG)
+   && (REGNO_DATA_P (REGNO (operands[0]), 1)
+       || REGNO_EXTENDED_P (REGNO (operands[0]), 1))"
+  [(parallel [(set (match_dup 0) (const_int 0))
+	      (clobber (reg:CC CC_REG))])]
+)
+
+(define_insn "*mov<mode>_clr"
+  [(set (match_operand:INT 0 "register_operand" "=D")
+	(const_int 0))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "clr %0"
+)
 \f
 ;; ----------------------------------------------------------------------
 ;; ADD INSTRUCTIONS
-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 90+ messages in thread

* [PATCH 21/28] mn10300: Add clzsi2.
  2011-01-10 20:33 [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Richard Henderson
                   ` (7 preceding siblings ...)
  2011-01-10 20:33 ` [PATCH 15/28] mn10300: Force lower-subreg pass to run Richard Henderson
@ 2011-01-10 20:33 ` Richard Henderson
  2011-01-12 14:05   ` Jeff Law
  2011-01-10 20:33 ` [PATCH 10/28] mn10300: Clean up trampoline handling Richard Henderson
                   ` (20 subsequent siblings)
  29 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-10 20:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: nickc, law, Richard Henderson

From: Richard Henderson <rth@twiddle.net>

---
 gcc/config/mn10300/mn10300.md |   23 +++++++++++++++++++++++
 1 files changed, 23 insertions(+), 0 deletions(-)

diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md
index 4f4fdfe..0f04a41 100644
--- a/gcc/config/mn10300/mn10300.md
+++ b/gcc/config/mn10300/mn10300.md
@@ -38,6 +38,7 @@
   (UNSPEC_GOTSYM_OFF	5)
 
   (UNSPEC_EXT		6)
+  (UNSPEC_BSCH		7)
 ])
 
 (include "predicates.md")
@@ -1389,6 +1390,28 @@
 )
 
 ;; ----------------------------------------------------------------------
+;; MISCELANEOUS
+;; ----------------------------------------------------------------------
+
+(define_expand "clzsi2"
+  [(parallel [(set (match_operand:SI 0 "register_operand" "")
+		   (unspec:SI [(match_operand:SI 1 "register_operand" "")
+			       (const_int 0)] UNSPEC_BSCH))
+	      (clobber (reg:CC CC_REG))])]
+  "TARGET_AM33"
+)
+
+(define_insn "*bsch"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	(unspec:SI [(match_operand:SI 1 "register_operand" "r")
+		    (match_operand:SI 2 "nonmemory_operand" "0")]
+		   UNSPEC_BSCH))
+   (clobber (reg:CC CC_REG))]
+  "TARGET_AM33"
+  "bsch %1,%0"
+)
+
+;; ----------------------------------------------------------------------
 ;; FP INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 90+ messages in thread

* [PATCH 10/28] mn10300: Clean up trampoline handling
  2011-01-10 20:33 [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Richard Henderson
                   ` (8 preceding siblings ...)
  2011-01-10 20:33 ` [PATCH 21/28] mn10300: Add clzsi2 Richard Henderson
@ 2011-01-10 20:33 ` Richard Henderson
  2011-01-12 14:04   ` Jeff Law
  2011-01-10 20:33 ` [PATCH 06/28] mn10300: fp insn cleanup Richard Henderson
                   ` (19 subsequent siblings)
  29 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-10 20:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: nickc, law, Richard Henderson

From: Richard Henderson <rth@twiddle.net>

The old code was failing in the testsuite.  I didn't try to
debug exactly why, since the existing code was needlessly
complex.
---
 gcc/config/mn10300/mn10300.c |   50 +++++++++++++++++++++---------------------
 gcc/config/mn10300/mn10300.h |    5 +--
 2 files changed, 27 insertions(+), 28 deletions(-)

diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c
index e801c47..7c090aa 100644
--- a/gcc/config/mn10300/mn10300.c
+++ b/gcc/config/mn10300/mn10300.c
@@ -2239,37 +2239,39 @@ mn10300_case_values_threshold (void)
   return 6;
 }
 
-/* Worker function for TARGET_ASM_TRAMPOLINE_TEMPLATE.  */
-
-static void
-mn10300_asm_trampoline_template (FILE *f)
-{
-  fprintf (f, "\tadd -4,sp\n");
-  fprintf (f, "\t.long 0x0004fffa\n");
-  fprintf (f, "\tmov (0,sp),a0\n");
-  fprintf (f, "\tadd 4,sp\n");
-  fprintf (f, "\tmov (13,a0),a1\n");	
-  fprintf (f, "\tmov (17,a0),a0\n");
-  fprintf (f, "\tjmp (a0)\n");
-  fprintf (f, "\t.long 0\n");
-  fprintf (f, "\t.long 0\n");
-}
-
 /* Worker function for TARGET_TRAMPOLINE_INIT.  */
 
 static void
 mn10300_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
 {
-  rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
-  rtx mem;
+  rtx mem, disp, fnaddr = XEXP (DECL_RTL (fndecl), 0);
+
+  /* This is a strict alignment target, which means that we play
+     some games to make sure that the locations at which we need
+     to store <chain> and <disp> wind up at aligned addresses.
+
+	0x28 0x00			add 0,d0
+	          0xfc 0xdd		mov chain,a1
+        <chain>
+	0xf8 0xed 0x00			btst 0,d1
+	               0xdc		jmp fnaddr
+	<disp>
+
+     Note that the two extra insns are effectively nops; they 
+     clobber the flags but do not affect the contents of D0 or D1.  */
 
-  emit_block_move (m_tramp, assemble_trampoline_template (),
-		   GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
+  disp = expand_binop (SImode, sub_optab, fnaddr,
+		       plus_constant (XEXP (m_tramp, 0), 11),
+		       NULL_RTX, 1, OPTAB_DIRECT);
 
-  mem = adjust_address (m_tramp, SImode, 0x14);
+  mem = adjust_address (m_tramp, SImode, 0);
+  emit_move_insn (mem, gen_int_mode (0xddfc0028, SImode));
+  mem = adjust_address (m_tramp, SImode, 4);
   emit_move_insn (mem, chain_value);
-  mem = adjust_address (m_tramp, SImode, 0x18);
-  emit_move_insn (mem, fnaddr);
+  mem = adjust_address (m_tramp, SImode, 8);
+  emit_move_insn (mem, gen_int_mode (0xdc00edf8, SImode));
+  mem = adjust_address (m_tramp, SImode, 12);
+  emit_move_insn (mem, disp);
 }
 
 /* Output the assembler code for a C++ thunk function.
@@ -2558,8 +2560,6 @@ mn10300_conditional_register_usage (void)
 #undef  TARGET_PREFERRED_OUTPUT_RELOAD_CLASS
 #define TARGET_PREFERRED_OUTPUT_RELOAD_CLASS mn10300_preferred_output_reload_class
 
-#undef  TARGET_ASM_TRAMPOLINE_TEMPLATE
-#define TARGET_ASM_TRAMPOLINE_TEMPLATE mn10300_asm_trampoline_template
 #undef  TARGET_TRAMPOLINE_INIT
 #define TARGET_TRAMPOLINE_INIT mn10300_trampoline_init
 
diff --git a/gcc/config/mn10300/mn10300.h b/gcc/config/mn10300/mn10300.h
index 60d7d43..0ee0cd1 100644
--- a/gcc/config/mn10300/mn10300.h
+++ b/gcc/config/mn10300/mn10300.h
@@ -533,9 +533,8 @@ struct cum_arg
 
 /* Length in units of the trampoline for entering a nested function.  */
 
-#define TRAMPOLINE_SIZE 0x1b
-
-#define TRAMPOLINE_ALIGNMENT 32
+#define TRAMPOLINE_SIZE		16
+#define TRAMPOLINE_ALIGNMENT	32
 
 /* A C expression whose value is RTL representing the value of the return
    address for the frame COUNT steps up from the current frame.
-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 90+ messages in thread

* [PATCH 25/28] mn10300: Use reg_or_am33_const_operand in mulsi3.
  2011-01-10 20:33 [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Richard Henderson
                   ` (10 preceding siblings ...)
  2011-01-10 20:33 ` [PATCH 06/28] mn10300: fp insn cleanup Richard Henderson
@ 2011-01-10 20:33 ` Richard Henderson
  2011-01-12 14:06   ` Jeff Law
  2011-01-10 20:33 ` [PATCH 23/28] mn10300: Add delegitimize_address hook Richard Henderson
                   ` (17 subsequent siblings)
  29 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-10 20:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: nickc, law, Richard Henderson

From: Richard Henderson <rth@twiddle.net>

---
 gcc/config/mn10300/mn10300.md |   16 ++++++++--------
 1 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md
index edfdb5d..680d55e 100644
--- a/gcc/config/mn10300/mn10300.md
+++ b/gcc/config/mn10300/mn10300.md
@@ -1004,19 +1004,19 @@
 )
 
 (define_expand "mulsi3"
-  [(parallel [(set (match_operand:SI          0 "register_operand"  "")
-		   (mult:SI (match_operand:SI 1 "register_operand"  "")
-			    (match_operand:SI 2 "nonmemory_operand" "")))
-	      (clobber (match_scratch:SI      3 ""))
+  [(parallel [(set (match_operand:SI          0 "register_operand")
+		   (mult:SI (match_operand:SI 1 "register_operand")
+			    (match_operand:SI 2 "reg_or_am33_const_operand")))
+	      (clobber (match_scratch:SI      3))
 	      (clobber (reg:CC CC_REG))])]
   ""
 )
 
 (define_insn "*mulsi3"
-  [(set (match_operand:SI          0 "register_operand"  "=D, r,r")
-	(mult:SI (match_operand:SI 2 "register_operand"  "%0, 0,r")
-		 (match_operand:SI 3 "nonmemory_operand" " D,ri,r")))
-   (clobber (match_scratch:SI      1                     "=z, z,r"))
+  [(set (match_operand:SI          0 "register_operand"          "=D, r,r")
+	(mult:SI (match_operand:SI 2 "register_operand"          "%0, 0,r")
+		 (match_operand:SI 3 "reg_or_am33_const_operand" " D,ri,r")))
+   (clobber (match_scratch:SI      1                             "=z, z,r"))
    (clobber (reg:CC CC_REG))]
   ""
 {
-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 90+ messages in thread

* [PATCH 02/28] mn10300: disable test tree-ssa/vrp47.c
  2011-01-10 20:33 [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Richard Henderson
                   ` (3 preceding siblings ...)
  2011-01-10 20:33 ` [PATCH 20/28] mn10300: Emit clr Richard Henderson
@ 2011-01-10 20:33 ` Richard Henderson
  2011-01-11 14:46   ` Jeff Law
  2011-01-10 20:33 ` [PATCH 27/28] mn10300: Add support in longlong.h Richard Henderson
                   ` (24 subsequent siblings)
  29 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-10 20:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: nickc, law, Richard Henderson

From: Richard Henderson <rth@twiddle.net>

---
 gcc/testsuite/gcc.dg/tree-ssa/vrp47.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp47.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp47.c
index 25b7720..3def90c 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp47.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp47.c
@@ -3,7 +3,7 @@
 /* Skip on S/390 and avr.  Lower values in BRANCH_COST lead to two conditional
    jumps when evaluating an && condition.  VRP is not able to optimize
    this.  */
-/* { dg-do compile { target { ! "mips*-*-* s390*-*-*  avr-*-*" } } } */
+/* { dg-do compile { target { ! "mips*-*-* s390*-*-*  avr-*-* mn10300-*-*" } } } */
 /* { dg-options "-O2 -fdump-tree-vrp -fdump-tree-dom" } */
 /* { dg-options "-O2 -fdump-tree-vrp -fdump-tree-dom -march=i586" { target { i?86-*-* && ilp32 } } } */
 
-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 90+ messages in thread

* [PATCH 09/28] mn10300: Remove bset/bclr patterns.
  2011-01-10 20:33 [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Richard Henderson
                   ` (14 preceding siblings ...)
  2011-01-10 20:34 ` [PATCH 11/28] mn10300: Clean up costing Richard Henderson
@ 2011-01-10 20:34 ` Richard Henderson
  2011-01-11 14:57   ` Jeff Law
  2011-01-10 20:34 ` [PATCH 28/28] New -fcompare-elim pass Richard Henderson
                   ` (13 subsequent siblings)
  29 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-10 20:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: nickc, law, Richard Henderson

From: Richard Henderson <rth@twiddle.net>

These instructions do not use normal addressing modes and are
incorrectly implemented for that.  Corrections to legitimate
addresses expose problems here.

Delete them for now.  To be re-instated later in the form of
atomic operation builtins.
---
 gcc/config/mn10300/constraints.md   |   23 ---
 gcc/config/mn10300/mn10300-protos.h |    1 -
 gcc/config/mn10300/mn10300.c        |   21 ---
 gcc/config/mn10300/mn10300.md       |  277 +----------------------------------
 gcc/config/mn10300/predicates.md    |   12 --
 5 files changed, 2 insertions(+), 332 deletions(-)

diff --git a/gcc/config/mn10300/constraints.md b/gcc/config/mn10300/constraints.md
index c9863fc..0f7f45b 100644
--- a/gcc/config/mn10300/constraints.md
+++ b/gcc/config/mn10300/constraints.md
@@ -49,29 +49,6 @@
   (and (match_code "mem")
        (match_test "!CONSTANT_ADDRESS_P (XEXP (op, 0))")))
 
-(define_memory_constraint "R"
-  "@internal"
-  (and (match_code "mem")
-       (match_test "mode == QImode")
-       (ior (match_test "CONSTANT_ADDRESS_P (XEXP (op, 0))")
-	    (and (match_test "GET_CODE (XEXP (op, 0)) == REG")
-		 (match_test "REG_OK_FOR_BIT_BASE_P (XEXP (op, 0))")
-		 (match_test "XEXP (op, 0) != stack_pointer_rtx"))
-	    (and (match_test "GET_CODE (XEXP (op, 0)) == PLUS")
-		 (match_test "GET_CODE (XEXP (XEXP (op, 0), 0)) == REG")
-		 (match_test "REG_OK_FOR_BIT_BASE_P (XEXP (XEXP (op, 0), 0))")
-		 (match_test "XEXP (XEXP (op, 0), 0) != stack_pointer_rtx")
-		 (match_test "GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT")
-		 (match_test "INT_8_BITS (INTVAL (XEXP (XEXP (op, 0), 1)))")))))
-
-(define_memory_constraint "T"
-  "@internal"
-  (and (match_code "mem")
-       (match_test "mode == QImode")
-       (and (match_test "GET_CODE (XEXP (op, 0)) == REG")
-	    (match_test "REG_OK_FOR_BIT_BASE_P (XEXP (op, 0))")
-	    (match_test "XEXP (op, 0) != stack_pointer_rtx"))))
-
 (define_constraint "S"
   "@internal"
   (if_then_else (match_test "flag_pic")
diff --git a/gcc/config/mn10300/mn10300-protos.h b/gcc/config/mn10300/mn10300-protos.h
index d787dcb..8979eb4 100644
--- a/gcc/config/mn10300/mn10300-protos.h
+++ b/gcc/config/mn10300/mn10300-protos.h
@@ -46,7 +46,6 @@ extern int   mn10300_can_use_return_insn (void);
 extern void  mn10300_expand_prologue (void);
 extern void  mn10300_expand_epilogue (void);
 extern int   mn10300_initial_offset (int, int);
-extern int   mn10300_mask_ok_for_mem_btst (int, int);
 
 #undef Mmode
 #undef Cstar
diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c
index 534ddaf..e801c47 100644
--- a/gcc/config/mn10300/mn10300.c
+++ b/gcc/config/mn10300/mn10300.c
@@ -1768,27 +1768,6 @@ mn10300_output_cmp (rtx operand, rtx insn)
   return "cmp 0,%0";
 }
 
-/* Similarly, but when using a zero_extract pattern for a btst where
-   the source operand might end up in memory.  */
-int
-mn10300_mask_ok_for_mem_btst (int len, int bit)
-{
-  unsigned int mask = 0;
-
-  while (len > 0)
-    {
-      mask |= (1 << bit);
-      bit++;
-      len--;
-    }
-
-  /* MASK must bit into an 8bit value.  */
-  return (((mask & 0xff) == mask)
-	  || ((mask & 0xff00) == mask)
-	  || ((mask & 0xff0000) == mask)
-	  || ((mask & 0xff000000) == mask));
-}
-
 /* Return 1 if X contains a symbolic expression.  We know these
    expressions will have one of a few well defined forms, so
    we need only check those forms.  */
diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md
index 1773a03..04ec1b1 100644
--- a/gcc/config/mn10300/mn10300.md
+++ b/gcc/config/mn10300/mn10300.md
@@ -490,9 +490,9 @@
 
 (define_insn "*movsi_internal"
   [(set (match_operand:SI 0 "nonimmediate_operand"
-			  "=dax, dax,  m,   dax, axR, !*y")
+			  "=dax, dax,  m,   dax, ax,!*y")
 	(match_operand:SI 1 "general_operand"
-			  "0,    Idax, dax, im,  !*y, axR"))
+			  "0,    Idax, dax, im, !*y, ax"))
   ]
   "register_operand (operands[0], SImode)
    || register_operand (operands[1], SImode)"
@@ -1658,279 +1658,6 @@
   "not %0"
 )
 \f
-;; -----------------------------------------------------------------
-;; BIT FIELDS
-;; -----------------------------------------------------------------
-
-
-;; These set/clear memory in byte sized chunks.
-;;
-;; They are no smaller/faster than loading the value into a register
-;; and storing the register, but they don't need a scratch register
-;; which may allow for better code generation.
-(define_insn "*byte_clear"
-  [(set (match_operand:QI 0 "nonimmediate_operand" "=R,d") (const_int 0))
-   (clobber (reg:CC CC_REG))
-   ]
-  "(! MEM_P (operands[0])) || (! MEM_VOLATILE_P (operands[0])
-                               && GET_CODE (XEXP (operands[0], 0)) != PLUS)"
-  "@
-  bclr 255,%A0
-  clr %0"
-  [(set_attr_alternative "timings"
-			 [(if_then_else (eq_attr "cpu" "am34")
-					(const_int 66) (const_int 77))
-			  (const_int 11)
-			 ])
-  ]
-)
-
-(define_insn "*byte_set"
-  [(set (match_operand:QI 0 "nonimmediate_operand" "=R,d") (const_int -1))
-   (clobber (reg:CC CC_REG))
-  ]
-  "(! MEM_P (operands[0])) || (! MEM_VOLATILE_P (operands[0])
-                               && GET_CODE (XEXP (operands[0], 0)) != PLUS)"
-  "@
-  bset 255,%A0
-  mov -1,%0"
-  [(set_attr_alternative "timings"
-			 [(if_then_else (eq_attr "cpu" "am34")
-					(const_int 66) (const_int 77))
-			  (const_int 11)
-			 ])
-  ]
-)
-
-(define_insn "*bit_clear1"
-  [(set (match_operand:QI 0 "nonimmediate_operand" "+R,d")
-	(subreg:QI
-	  (and:SI (subreg:SI (match_dup 0) 0)
-		  (match_operand:SI 1 "const_int_operand" "i,i")) 0))
-   (clobber (reg:CC CC_REG))
-  ]
-  ""
-  "@
-  bclr %N1,%A0
-  and %1,%0"
-  [(set_attr_alternative "timings"
-			 [(if_then_else (eq_attr "cpu" "am34")
-					(const_int 66) (const_int 77))
-			  (const_int 11)
-			 ])
-  ]
-)
-
-(define_insn "*bit_clear2"
-  [(set (match_operand:QI 0 "memory_operand" "=R,T")
-	(and:QI
-	 (match_dup 0)
-	 (not:QI (match_operand:QI 1 "nonmemory_operand" "i,d"))))
-   (clobber (reg:CC CC_REG))
-  ]
-  ""
-  "@
-  bclr %U1,%A0
-  bclr %1,%0"
-  [(set_attr_alternative "timings"
-			 [(if_then_else (eq_attr "cpu" "am34")
-					(const_int 66) (const_int 77))
-			  (const_int 66)
-			 ])
-  ]
-)
-
-(define_insn "*bit_set"
-  [(set (match_operand:QI 0 "nonimmediate_operand" "+R,d")
-	(subreg:QI
-	  (ior:SI (subreg:SI (match_dup 0) 0)
-		  (match_operand:SI 1 "const_int_operand" "i,i")) 0))
-   (clobber (reg:CC CC_REG))
-  ]
-  ""
-  "@
-  bset %U1,%A0
-  or %1,%0"
-  [(set_attr_alternative "timings"
-			 [(if_then_else (eq_attr "cpu" "am34")
-					(const_int 66) (const_int 77))
-			  (const_int 11)
-			 ])
-  ]
-)
-
-(define_expand "iorqi3"
-  [(parallel [(set (match_operand:QI         0 "nonimmediate_operand")
-		   (ior:QI (match_operand:QI 1 "nonimmediate_operand")
-			   (match_operand:QI 2 "nonmemory_operand")))
-	      (clobber (reg:CC CC_REG))
-	     ])
-  ]
-  ""
-  "")
-
-(define_insn "*am33_iorqi3"
-  [(set (match_operand:QI         0 "nonimmediate_operand" "=R,T,r")
-	(ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0")
-		;; This constraint should really be nonmemory_operand,
-		;; but making it general_operand, along with the
-		;; condition that not both input operands are MEMs,
-		;; helps combine do a better job.
-		(match_operand:QI 2 "general_operand" "i,d,ir")))
-   (clobber (reg:CC CC_REG))
-  ]
-  "TARGET_AM33 && 
-   ((! MEM_P (operands[2])) || (! MEM_P (operands[1])))"
-  "@
-  bset %U2,%A0
-  bset %2,%0
-  or %2,%0"
-  [(set_attr_alternative "timings"
-			 [(if_then_else (eq_attr "cpu" "am34")
-					(const_int 66) (const_int 77))
-			  (const_int 66)
-			  (const_int 11)
-			 ])
-  ]
-)
-
-(define_insn "*mn10300_iorqi3"
-  [(set (match_operand:QI         0 "nonimmediate_operand" "=R,T,d")
-	(ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0")
-		;; This constraint should really be nonmemory_operand,
-		;; but making it general_operand, along with the
-		;; condition that not both input operands are MEMs,
-		;; helps combine do a better job.
-		(match_operand:QI 2 "general_operand" "i,d,id")))
-   (clobber (reg:CC CC_REG))
-  ]
-  "(! MEM_P (operands[2])) || (! MEM_P (operands[1]))"
-  "@
-  bset %U2,%A0
-  bset %2,%0
-  or %2,%0"
-  [(set_attr_alternative "timings"
-			 [(if_then_else (eq_attr "cpu" "am34")
-					(const_int 66) (const_int 77))
-			  (const_int 66)
-			  (const_int 11)
-			 ])
-  ]
-)
-
-(define_insn "*test_int_bitfield"
-  [(set (reg:CC CC_REG)
-     (compare (zero_extract:SI (match_operand:SI 0 "register_operand" "dx")
-			       (match_operand 1 "const_int_operand" "")
-			       (match_operand 2 "const_int_operand" ""))
-	      (const_int 0)))]
-  ""
-  "*
-{
-  int len = INTVAL (operands[1]);
-  int bit = INTVAL (operands[2]);
-  int mask = 0;
-  rtx xoperands[2];
-
-  while (len > 0)
-    {
-      mask |= (1 << bit);
-      bit++;
-      len--;
-    }
-
-  xoperands[0] = operands[0];
-  xoperands[1] = GEN_INT (trunc_int_for_mode (mask, SImode));
-  output_asm_insn (\"btst %1,%0\", xoperands);
-  return \"\";
-}"
-)
-
-(define_insn "*test_byte_bitfield"
-  [(set (reg:CC CC_REG)
-     (compare (zero_extract:SI (match_operand:QI 0 "nonimmediate_operand" "R,dx")
-			       (match_operand 1 "const_int_operand" "")
-			       (match_operand 2 "const_int_operand" ""))
-	      (const_int 0)))]
-  "mn10300_mask_ok_for_mem_btst (INTVAL (operands[1]), INTVAL (operands[2]))"
-  "*
-{
-  int len = INTVAL (operands[1]);
-  int bit = INTVAL (operands[2]);
-  int mask = 0;
-  rtx xoperands[2];
-
-  while (len > 0)
-    {
-      mask |= (1 << bit);
-      bit++;
-      len--;
-    }
-
-  /* If the source operand is not a reg (i.e. it is memory), then extract the
-     bits from mask that we actually want to test.  Note that the mask will
-     never cross a byte boundary.  */
-  if (!REG_P (operands[0]))
-    {
-      if (mask & 0xff)
-	mask = mask & 0xff;
-      else if (mask & 0xff00)
-	mask = (mask >> 8) & 0xff;
-      else if (mask & 0xff0000)
-	mask = (mask >> 16) & 0xff;
-      else if (mask & 0xff000000)
-	mask = (mask >> 24) & 0xff;
-    }
-
-  xoperands[0] = operands[0];
-  xoperands[1] = GEN_INT (trunc_int_for_mode (mask, SImode));
-  if (REG_P (operands[0]))
-    output_asm_insn (\"btst %1,%0\", xoperands);
-  else
-    output_asm_insn (\"btst %U1,%A0\", xoperands);
-  return \"\";
-}"
-  [(set_attr_alternative "timings"
-			 [(if_then_else (eq_attr "cpu" "am34")
-			 		(const_int 11) (const_int 22))
-			  (if_then_else (eq_attr "cpu" "am34")
-			  		(const_int 44) (const_int 55))
-			 ])
-  ]
-)
-
-(define_insn "*bit_test"
-  [(set (reg:CC CC_REG)
-	(compare (and:SI (match_operand:SI 0 "register_operand" "dx")
-			 (match_operand:SI 1 "const_int_operand" ""))
-		 (const_int 0)))
-  ]
-  ""
-  "btst %1,%0"
-  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
-				       (const_int 11) (const_int 22)))]
-)
-
-(define_insn "*subreg_bit_test"
-  [(set (reg:CC CC_REG)
-     (compare (and:SI
-	       (subreg:SI (match_operand:QI 0 "nonimmediate_operand" "R,dx") 0)
-	       (match_operand:SI 1 "const_8bit_operand" ""))
-	      (const_int 0)))]
-  ""
-  "@
-  btst %U1,%A0
-  btst %1,%0"
-  [(set_attr_alternative "timings"
-			 [(if_then_else (eq_attr "cpu" "am34")
-					(const_int 44) (const_int 55))
-			  (if_then_else (eq_attr "cpu" "am34")
-					(const_int 11) (const_int 22))
-			 ])
-  ]
-)
-
-\f
 ;; ----------------------------------------------------------------------
 ;; COMPARE AND BRANCH INSTRUCTIONS
 ;; ----------------------------------------------------------------------
diff --git a/gcc/config/mn10300/predicates.md b/gcc/config/mn10300/predicates.md
index 526ee38..df1b1f4 100644
--- a/gcc/config/mn10300/predicates.md
+++ b/gcc/config/mn10300/predicates.md
@@ -25,18 +25,6 @@
   return (op == CONST1_RTX (SFmode));
 })
 
-;; Return 1 if X is a CONST_INT that is only 8 bits wide.  This is
-;; used for the btst insn which may examine memory or a register (the
-;; memory variant only allows an unsigned 8-bit integer).
-
-(define_predicate "const_8bit_operand"
-  (match_code "const_int")
-{
-  return (GET_CODE (op) == CONST_INT
-	  && INTVAL (op) >= 0
-	  && INTVAL (op) < 256);
-})
-
 ;; Return true if OP is a valid call operand.
 
 (define_predicate "call_address_operand"
-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 90+ messages in thread

* [PATCH 24/28] mn10300: Implement adddi3, subdi3.
  2011-01-10 20:33 [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Richard Henderson
                   ` (17 preceding siblings ...)
  2011-01-10 20:34 ` [PATCH 07/28] mn10300: Add attribute enabled Richard Henderson
@ 2011-01-10 20:34 ` Richard Henderson
  2011-01-19 18:45   ` Jeff Law
  2011-01-10 20:34 ` [PATCH 17/28] mn10300: Explicitly represent MDR in multiply and divide Richard Henderson
                   ` (10 subsequent siblings)
  29 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-10 20:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: nickc, law, Richard Henderson

From: Richard Henderson <rth@twiddle.net>

Via expander, pre- and post-reload patterns.  The pre-reload
pattern is defined to allow lower_subregs totally split the
DImode values.
---
 gcc/config/mn10300/mn10300.md    |  321 ++++++++++++++++++++++++++++++++++++++
 gcc/config/mn10300/predicates.md |    5 +
 2 files changed, 326 insertions(+), 0 deletions(-)

diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md
index fae87e9..edfdb5d 100644
--- a/gcc/config/mn10300/mn10300.md
+++ b/gcc/config/mn10300/mn10300.md
@@ -534,6 +534,172 @@
   [(set_attr "timings" "11,22")]
 )
 
+;; A helper to expand the above, with the CC_MODE filled in.
+(define_expand "addsi3_flags"
+  [(parallel [(set (match_operand:SI 0 "register_operand")
+		   (plus:SI (match_operand:SI 1 "register_operand")
+			    (match_operand:SI 2 "nonmemory_operand")))
+	      (set (reg:CCZNC CC_REG)
+		   (compare:CCZNC (plus:SI (match_dup 1) (match_dup 2))
+				  (const_int 0)))])]
+  ""
+)
+
+(define_insn "addc_internal"
+  [(set (match_operand:SI 0 "register_operand"            "=D,r,r")
+	(plus:SI
+	  (plus:SI
+	    (ltu:SI (reg:CC CC_REG) (const_int 0))
+	    (match_operand:SI 1 "register_operand"        "%0,0,r"))
+	  (match_operand:SI 2 "reg_or_am33_const_operand" " D,i,r")))
+    (clobber (reg:CC CC_REG))]
+  "reload_completed"
+  "@
+   addc %2,%0
+   addc %2,%0
+   addc %2,%1,%0"
+  [(set_attr "isa" "*,am33,am33")]
+)
+
+(define_expand "adddi3"
+  [(set (match_operand:DI 0 "register_operand" "")
+	(plus:DI (match_operand:DI 1 "register_operand" "")
+		 (match_operand:DI 2 "nonmemory_operand" "")))]
+  ""
+{
+  rtx op0l, op0h, op1l, op1h, op2l, op2h;
+
+  op0l = gen_lowpart (SImode, operands[0]);
+  op1l = gen_lowpart (SImode, operands[1]);
+  op2l = gen_lowpart (SImode, operands[2]);
+  op0h = gen_highpart (SImode, operands[0]);
+  op1h = gen_highpart (SImode, operands[1]);
+  op2h = gen_highpart_mode (SImode, DImode, operands[2]);
+
+  if (!reg_or_am33_const_operand (op2h, SImode))
+    op2h = force_reg (SImode, op2h);
+
+  emit_insn (gen_adddi3_internal (op0l, op0h, op1l, op2l, op1h, op2h));
+  DONE;
+})
+
+;; Note that reload only supports one commutative operand.  Thus we cannot
+;; auto-swap both the high and low outputs with their matching constraints.
+;; For MN103, we're strapped for registers but thankfully the alternatives
+;; are few.  For AM33, it becomes much easier to not represent the early
+;; clobber and 6 permutations of immediate and three-operand adds, but
+;; instead allocate a scratch register and do the expansion by hand.
+
+(define_insn_and_split "adddi3_internal"
+  [(set (match_operand:SI          0 "register_operand"   "=r, r, r")
+	(plus:SI (match_operand:SI 2 "register_operand"   "%0, 0, r")
+		 (match_operand:SI 3 "nonmemory_operand"  "ri,ri,ri")))
+   (set (match_operand:SI          1 "register_operand"   "=D, D, r")
+	(plus:SI
+	  (plus:SI
+	    (ltu:SI (plus:SI (match_dup 2) (match_dup 3)) (match_dup 2))
+	    (match_operand:SI      4 "register_operand"   " 1, D, r"))
+	  (match_operand:SI 5 "reg_or_am33_const_operand" " D, 1,ri")))
+   (clobber (match_scratch:SI      6                      "=X, X,&r"))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+{
+  rtx op0l = operands[0];
+  rtx op0h = operands[1];
+  rtx op1l = operands[2];
+  rtx op2l = operands[3];
+  rtx op1h = operands[4];
+  rtx op2h = operands[5];
+  rtx scratch = operands[6];
+  rtx x;
+
+  if (reg_overlap_mentioned_p (op0l, op1h))
+    {
+      emit_move_insn (scratch, op0l);
+      op1h = scratch;
+      if (reg_overlap_mentioned_p (op0l, op2h))
+	op2h = scratch;
+    }
+  else if (reg_overlap_mentioned_p (op0l, op2h))
+    {
+      emit_move_insn (scratch, op0l);
+      op2h = scratch;
+    }
+
+  if (rtx_equal_p (op0l, op1l))
+    ;
+  else if (rtx_equal_p (op0l, op2l))
+    x = op1l, op1l = op2l, op2l = x;
+  else
+    {
+      gcc_assert (TARGET_AM33);
+      if (!REG_P (op2l))
+	{
+	  emit_move_insn (op0l, op2l);
+	  op2l = op1l;
+	  op1l = op0l;
+	}
+    }
+  emit_insn (gen_addsi3_flags (op0l, op1l, op2l));
+
+  if (rtx_equal_p (op0h, op1h))
+    ;
+  else if (rtx_equal_p (op0h, op2h))
+    x = op1h, op1h = op2h, op2h = x;
+  else
+    {
+      gcc_assert (TARGET_AM33);
+      if (!REG_P (op2h))
+	{
+	  emit_move_insn (op0h, op2h);
+	  op2h = op1h;
+	  op1h = op0h;
+	}
+    }
+  emit_insn (gen_addc_internal (op0h, op1h, op2h));
+  DONE;
+}
+  [(set_attr "isa" "*,*,am33")]
+)
+
+;; The following pattern is generated by combine when it proves that one
+;; of the inputs to the low-part of the double-word add is zero, and thus
+;; no carry is generated into the high-part.
+
+(define_insn_and_split "*adddi3_degenerate"
+  [(set (match_operand:SI          0 "register_operand"  "=&r,&r")
+	(match_operand:SI          2 "nonmemory_operand" "  0, 0"))
+   (set (match_operand:SI          1 "register_operand"  "=r , r")
+	(plus:SI (match_operand:SI 3 "register_operand"  "%1 , r")
+		 (match_operand:SI 4 "nonmemory_operand" "ri, r")))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "#"
+  ""
+  [(const_int 0)]
+{
+  rtx scratch = NULL_RTX;
+  if (!rtx_equal_p (operands[0], operands[2]))
+    {
+      gcc_assert (!reg_overlap_mentioned_p (operands[0], operands[1]));
+      if (reg_overlap_mentioned_p (operands[0], operands[3])
+	  || reg_overlap_mentioned_p (operands[0], operands[4]))
+	{
+	  scratch = gen_reg_rtx (SImode);
+	  emit_move_insn (scratch, operands[2]);
+	}
+      else
+	emit_move_insn (operands[0], operands[2]);
+    }
+  emit_insn (gen_addsi3 (operands[1], operands[3], operands[4]));
+  if (scratch)
+    emit_move_insn (operands[0], scratch);
+  DONE;
+})
+
 ;; ----------------------------------------------------------------------
 ;; SUBTRACT INSTRUCTIONS
 ;; ----------------------------------------------------------------------
@@ -566,6 +732,161 @@
    (set_attr "timings" "11,22")]
 )
 
+;; A helper to expand the above, with the CC_MODE filled in.
+(define_expand "subsi3_flags"
+  [(parallel [(set (match_operand:SI 0 "register_operand")
+		   (minus:SI (match_operand:SI 1 "register_operand")
+			     (match_operand:SI 2 "nonmemory_operand")))
+	      (set (reg:CCZNC CC_REG)
+		   (compare:CCZNC (minus:SI (match_dup 1) (match_dup 2))
+				  (const_int 0)))])]
+  ""
+)
+
+(define_insn "subc_internal"
+  [(set (match_operand:SI 0 "register_operand"                      "=D,r,r")
+	(minus:SI
+	  (minus:SI (match_operand:SI 1 "register_operand"          " 0,0,r")
+		    (match_operand:SI 2 "reg_or_am33_const_operand" " D,i,r"))
+	  (geu:SI (reg:CC CC_REG) (const_int 0))))
+   (clobber (reg:CC CC_REG))]
+  "reload_completed"
+  "@
+   subc %2,%0
+   subc %2,%0
+   subc %2,%1,%0"
+  [(set_attr "isa" "*,am33,am33")]
+)
+
+(define_expand "subdi3"
+  [(set (match_operand:DI 0 "register_operand" "")
+        (minus:DI (match_operand:DI 1 "register_operand" "")
+                  (match_operand:DI 2 "nonmemory_operand" "")))]
+  ""
+{
+  rtx op0l, op0h, op1l, op1h, op2l, op2h;
+
+  op0l = gen_lowpart (SImode, operands[0]);
+  op1l = gen_lowpart (SImode, operands[1]);
+  op2l = gen_lowpart (SImode, operands[2]);
+  op0h = gen_highpart (SImode, operands[0]);
+  op1h = gen_highpart (SImode, operands[1]);
+  op2h = gen_highpart_mode (SImode, DImode, operands[2]);
+
+  if (!reg_or_am33_const_operand (op2h, SImode))
+    op2h = force_reg (SImode, op2h);
+
+  emit_insn (gen_subdi3_internal (op0l, op0h, op1l, op1h, op2l, op2h));
+  DONE;
+})
+
+;; As with adddi3, the use of the scratch register helps reduce the 
+;; number of permutations for AM33.
+;; ??? The early clobber on op0 avoids a reload bug wherein both output
+;; registers are set the same.  Consider negate, where both op2 and op3
+;; are 0, are csed to the same input register, and reload fails to undo
+;; the cse when satisfying the matching constraints.
+
+(define_insn_and_split "subdi3_internal"
+  [(set (match_operand:SI     0 "register_operand"         "=&r, r")
+	(minus:SI
+	  (match_operand:SI   2 "register_operand"         "  0, r")
+	  (match_operand:SI   4 "nonmemory_operand"        " ri,ri")))
+   (set (match_operand:SI     1 "register_operand"         "=D , r")
+	(minus:SI
+	  (minus:SI
+	    (match_operand:SI 3 "register_operand"         "  1, r")
+	    (match_operand:SI 5 "reg_or_am33_const_operand" " D,ri"))
+	  (ltu:SI (match_dup 2) (match_dup 4))))
+   (clobber (match_scratch:SI 6                            "=X ,&r"))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+{
+  rtx op0l = operands[0];
+  rtx op0h = operands[1];
+  rtx op1l = operands[2];
+  rtx op1h = operands[3];
+  rtx op2l = operands[4];
+  rtx op2h = operands[5];
+  rtx scratch = operands[6];
+
+  if (reg_overlap_mentioned_p (op0l, op1h))
+    {
+      emit_move_insn (scratch, op0l);
+      op1h = scratch;
+      if (reg_overlap_mentioned_p (op0l, op2h))
+	op2h = scratch;
+    }
+  else if (reg_overlap_mentioned_p (op0l, op2h))
+    {
+      emit_move_insn (scratch, op0l);
+      op2h = scratch;
+    }
+
+  if (!rtx_equal_p (op0l, op1l))
+    {
+      gcc_assert (TARGET_AM33);
+      if (!REG_P (op2l))
+	{
+	  emit_move_insn (op0l, op1l);
+	  op1l = op0l;
+	}
+    }
+  emit_insn (gen_subsi3_flags (op0l, op1l, op2l));
+
+  if (!rtx_equal_p (op0h, op1h))
+    {
+      gcc_assert (TARGET_AM33);
+      if (!REG_P (op2h))
+	{
+	  emit_move_insn (op0h, op1h);
+	  op1h = op0h;
+	}
+    }
+  emit_insn (gen_subc_internal (op0h, op1h, op2h));
+  DONE;
+}
+  [(set_attr "isa" "*,am33")]
+)
+
+;; The following pattern is generated by combine when it proves that one
+;; of the inputs to the low-part of the double-word sub is zero, and thus
+;; no carry is generated into the high-part.
+
+(define_insn_and_split "*subdi3_degenerate"
+  [(set (match_operand:SI          0 "register_operand"   "=&r,&r")
+	(match_operand:SI          2 "nonmemory_operand"  "  0, 0"))
+   (set (match_operand:SI          1 "register_operand"   "=r , r")
+	(minus:SI (match_operand:SI 3 "register_operand"  "  1, r")
+		  (match_operand:SI 4 "nonmemory_operand" " ri, r")))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "#"
+  ""
+  [(const_int 0)]
+{
+  rtx scratch = NULL_RTX;
+  if (!rtx_equal_p (operands[0], operands[2]))
+    {
+      gcc_assert (!reg_overlap_mentioned_p (operands[0], operands[1]));
+      if (reg_overlap_mentioned_p (operands[0], operands[3])
+	  || reg_overlap_mentioned_p (operands[0], operands[4]))
+	{
+	  scratch = gen_reg_rtx (SImode);
+	  emit_move_insn (scratch, operands[2]);
+	}
+      else
+	emit_move_insn (operands[0], operands[2]);
+    }
+  emit_insn (gen_subsi3 (operands[1], operands[3], operands[4]));
+  if (scratch)
+    emit_move_insn (operands[0], scratch);
+  DONE;
+})
+
 (define_insn_and_split "negsi2"
   [(set (match_operand:SI         0 "register_operand"  "=D,&r")
 	(neg:SI (match_operand:SI 1 "register_operand"  " 0, r")))
diff --git a/gcc/config/mn10300/predicates.md b/gcc/config/mn10300/predicates.md
index 4badebb..8316990 100644
--- a/gcc/config/mn10300/predicates.md
+++ b/gcc/config/mn10300/predicates.md
@@ -43,6 +43,11 @@
       || XEXP (op, 1) == stack_pointer_rtx;
 })
 
+(define_predicate "reg_or_am33_const_operand"
+  (ior (match_operand 0 "register_operand")
+       (and (match_test "TARGET_AM33")
+	    (match_operand 0 "immediate_operand"))))
+
 (define_predicate "label_ref_operand"
   (match_code "label_ref"))
 
-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 90+ messages in thread

* [PATCH 03/28] mn10300: delete ASM_PN_FORMAT
  2011-01-10 20:33 [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Richard Henderson
                   ` (19 preceding siblings ...)
  2011-01-10 20:34 ` [PATCH 17/28] mn10300: Explicitly represent MDR in multiply and divide Richard Henderson
@ 2011-01-10 20:34 ` Richard Henderson
  2011-01-11 14:46   ` Jeff Law
  2011-01-10 20:34 ` [PATCH 08/28] mn10300: Define the A and D constraints Richard Henderson
                   ` (8 subsequent siblings)
  29 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-10 20:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: nickc, law, Richard Henderson

From: Richard Henderson <rth@twiddle.net>

Is there any real reason for this?  It causes testsuite failures
because the pattern doesn't match many of the dumps.
---
 gcc/config/mn10300/mn10300.h |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/gcc/config/mn10300/mn10300.h b/gcc/config/mn10300/mn10300.h
index edc17f5..468c031 100644
--- a/gcc/config/mn10300/mn10300.h
+++ b/gcc/config/mn10300/mn10300.h
@@ -656,7 +656,10 @@ struct cum_arg
 #define ASM_OUTPUT_LABELREF(FILE, NAME) \
   asm_fprintf (FILE, "%U%s", (*targetm.strip_name_encoding) (NAME))
 
+/* ??? Is there any real reason for this?  It mucks up pattern matching
+   in the tree-ssa.exp testsuite.
 #define ASM_PN_FORMAT "%s___%lu"
+*/
 
 /* This is how we tell the assembler that two symbols have the same value.  */
 
-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 90+ messages in thread

* [PATCH 28/28] New -fcompare-elim pass.
  2011-01-10 20:33 [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Richard Henderson
                   ` (15 preceding siblings ...)
  2011-01-10 20:34 ` [PATCH 09/28] mn10300: Remove bset/bclr patterns Richard Henderson
@ 2011-01-10 20:34 ` Richard Henderson
  2011-01-11 19:00   ` Nathan Froyd
  2011-01-12  9:07   ` Paolo Bonzini
  2011-01-10 20:34 ` [PATCH 07/28] mn10300: Add attribute enabled Richard Henderson
                   ` (12 subsequent siblings)
  29 siblings, 2 replies; 90+ messages in thread
From: Richard Henderson @ 2011-01-10 20:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: nickc, law, Richard Henderson

From: Richard Henderson <rth@twiddle.net>

Handles arithemetic redundant with compare, as well as compare
redundant with compare.  The later happens very often with the
use of double-word arithmetic.
---
 gcc/Makefile.in              |    4 +
 gcc/common.opt               |    4 +
 gcc/compare-elim.c           |  519 ++++++++++++++++++++++++++++++++++++++++++
 gcc/config/mn10300/mn10300.c |    3 +
 gcc/doc/invoke.texi          |   15 ++-
 gcc/doc/tm.texi              |    4 +
 gcc/doc/tm.texi.in           |    2 +
 gcc/opts.c                   |    1 +
 gcc/passes.c                 |    1 +
 gcc/recog.h                  |    5 +
 gcc/target.def               |    9 +
 gcc/tree-pass.h              |    1 +
 12 files changed, 567 insertions(+), 1 deletions(-)
 create mode 100644 gcc/compare-elim.c

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index de3bde9..f421d5a 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1205,6 +1205,7 @@ OBJS-common = \
 	cfgrtl.o \
 	combine.o \
 	combine-stack-adj.o \
+	compare-elim.o \
 	convert.o \
 	coverage.o \
 	cse.o \
@@ -3352,6 +3353,9 @@ combine-stack-adj.o : combine-stack-adj.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
    $(TM_H) $(RTL_H) insn-config.h $(TIMEVAR_H) $(TREE_PASS_H) \
    $(RECOG_H) output.h $(REGS_H) hard-reg-set.h $(FLAGS_H) $(FUNCTION_H) \
    $(EXPR_H) $(BASIC_BLOCK_H) $(DIAGNOSTIC_CORE_H) $(TM_P_H) $(DF_H) $(EXCEPT_H) reload.h
+compare-elim.o : compare-elim.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+   $(TM_H) $(RTL_H) $(TM_P_H) $(RECOG_H) $(FLAGS_H) $(BASIC_BLOCK_H) \
+   $(TREE_PASS_H) $(DF_H)
 ddg.o : ddg.c $(DDG_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TARGET_H) \
    $(DIAGNOSTIC_CORE_H) $(RTL_H) $(TM_P_H) $(REGS_H) $(FUNCTION_H) \
    $(FLAGS_H) insn-config.h $(INSN_ATTR_H) $(EXCEPT_H) $(RECOG_H) \
diff --git a/gcc/common.opt b/gcc/common.opt
index 32df6fc..5b01363 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -853,6 +853,10 @@ fcompare-debug-second
 Common Driver RejectNegative Var(flag_compare_debug)
 Run only the second compilation of -fcompare-debug
 
+fcompare-elim
+Common Report Var(flag_compare_elim_after_reload) Optimization
+Perform comparison elimination after register allocation has finished
+
 fconserve-stack
 Common Var(flag_conserve_stack) Optimization
 Do not perform optimizations increasing noticeably stack usage
diff --git a/gcc/compare-elim.c b/gcc/compare-elim.c
new file mode 100644
index 0000000..a1d91cc
--- /dev/null
+++ b/gcc/compare-elim.c
@@ -0,0 +1,519 @@
+/* Post-reload compare elimination.
+   Copyright (C) 2010, 2011
+   Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+/* There is a set of targets whose general-purpose move or addition
+   instructions clobber the flags.  These targets cannot split their
+   CBRANCH/CSTORE etc patterns before reload is complete, lest reload
+   itself insert instructions in between the flags setter and user.
+   Because these targets cannot split the compare from the use, they
+   cannot make use of the comparison elimination offered by the combine pass.
+
+   This is a small pass intended to provide comparison elimination similar to
+   what is available via NOTICE_UPDATE_CC for cc0 targets.  This should help
+   encourage cc0 targets to convert to an explicit post-reload representation
+   of the flags.
+
+   This pass assumes:
+
+   (0) CBRANCH/CSTORE etc have been split in pass_split_after_reload.
+
+   (1) All comparison patterns are represented as
+
+	[(set (reg:CC) (compare:CC (reg) (immediate)]
+
+   (2) All insn patterns that modify the flags are represented as
+
+	[(set (reg) (operation)
+	 (clobber (reg:CC))]
+
+   (3) If an insn of form (2) can usefully set the flags, there is
+       another pattern of the form
+
+	[(set (reg) (operation)
+	 (set (reg:CCM) (compare:CCM (operation) (immediate)))]
+
+       The mode CCM will be chosen as if by SELECT_CC_MODE.
+*/
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "rtl.h"
+#include "tm_p.h"
+#include "insn-config.h"
+#include "recog.h"
+#include "flags.h"
+#include "basic-block.h"
+#include "tree-pass.h"
+#include "target.h"
+#include "df.h"
+#include "domwalk.h"
+
+\f
+/* These structures describe a comparison and how it is used.  */
+
+/* The choice of maximum 3 uses comes from wanting to eliminate the two
+   duplicate compares from a three-way branch on the sign of a value.
+   This is also sufficient to eliminate the duplicate compare against the
+   high-part of a double-word comparison.  */
+#define MAX_CMP_USE 3
+
+struct comparison_use
+{
+  /* The instruction in which the result of the compare is used.  */
+  rtx insn;
+  /* The location of the flags register within the use.  */
+  rtx *loc;
+  /* The comparison code applied against the flags register.  */
+  enum rtx_code code;
+};
+
+struct comparison
+{
+  /* The comparison instruction.  */
+  rtx insn;
+
+  /* The two values being compared.  These will be either REGs or
+     constants.  */
+  rtx in_a, in_b;
+
+  /* Information about how this comparison is used.  */
+  struct comparison_use uses[MAX_CMP_USE];
+
+  /* The original CC_MODE for this comparison.  */
+  enum machine_mode orig_mode;
+
+  /* The number of uses identified for this comparison.  */
+  unsigned short n_uses;
+
+  /* True if not all uses of this comparison have been identified.
+     This can happen either for overflowing the array above, or if
+     the flags register is used in some unusual context.  */
+  bool missing_uses;
+};
+  
+typedef struct comparison *comparison_struct_p;
+DEF_VEC_P(comparison_struct_p);
+DEF_VEC_ALLOC_P(comparison_struct_p, heap);
+
+static VEC(comparison_struct_p, heap) *all_compares;
+
+static void
+find_flags_uses_in_bb (struct comparison *cmp,
+		       basic_block bb ATTRIBUTE_UNUSED, rtx insn)
+{
+  df_ref *use_rec, use;
+  struct df_link *chain;
+
+  /* If we've already lost track of uses, don't bother collecting more.  */
+  if (cmp->missing_uses)
+    return;
+
+  /* Find the DEF of the flags register.  It must be there.  */
+  for (use_rec = DF_INSN_DEFS (insn); ; use_rec++)
+    {
+      use = *use_rec;
+      if (DF_REF_TYPE (use) == DF_REF_REG_DEF
+	  && DF_REF_REGNO (use) == targetm.flags_regnum)
+	break;
+    }
+
+  for (chain = DF_REF_CHAIN (use); chain ; chain = chain->next)
+    {
+      rtx x, uinsn, *uloc;
+
+      /* If we've run out of slots to record uses, quit.  */
+      if (cmp->n_uses == MAX_CMP_USE)
+	{
+	  cmp->missing_uses = true;
+	  return;
+	}
+
+      /* Unfortunately, the location of the flags register, while present in
+	 the reference structure, doesn't help.  We need to find the comparison
+	 code that is outer to the actual flags use.  */
+      uinsn = DF_REF_INSN (chain->ref);
+      uloc = DF_REF_LOC (chain->ref);
+      x = PATTERN (uinsn);
+      if (GET_CODE (x) == PARALLEL)
+	x = XVECEXP (x, 0, 0);
+      x = SET_SRC (x);
+      if (GET_CODE (x) == IF_THEN_ELSE)
+	x = XEXP (x, 0);
+      if (COMPARISON_P (x)
+	  && uloc == &XEXP (x, 0)
+	  && XEXP (x, 1) == const0_rtx)
+	{
+	  struct comparison_use *cuse = &cmp->uses[cmp->n_uses++];
+	  cuse->insn = uinsn;
+	  cuse->loc = uloc;
+	  cuse->code = GET_CODE (x);
+	}
+      else
+	{
+	  /* We failed to recognize this use of the flags register.  */
+	  cmp->missing_uses = true;
+	  return;
+	}
+    }
+}
+
+/* Identify comparison instructions within BB.  If the last compare in the BB
+   is valid at the end of the block, install it in BB->AUX.  Called via 
+   walk_dominators_tree.  */
+
+static void
+find_comparisons_in_bb (struct dom_walk_data *data ATTRIBUTE_UNUSED,
+			basic_block bb)
+{
+  struct comparison *last_cmp = NULL;
+  bitmap killed;
+  rtx insn, next;
+
+  killed = BITMAP_ALLOC (NULL);
+
+  /* Propagate the last live comparison throughout the extended basic block.  */
+  if (single_pred_p (bb))
+    last_cmp = (struct comparison *) single_pred (bb)->aux;
+
+  for (insn = BB_HEAD (bb); insn; insn = next)
+    {
+      rtx set, src, dst;
+
+      next = (insn == BB_END (bb) ? NULL_RTX : NEXT_INSN (insn));
+      if (!NONDEBUG_INSN_P (insn))
+	continue;
+
+      if ((set = single_set (insn)) != NULL
+	  && (src = SET_SRC (set), GET_CODE (src) == COMPARE)
+	  && (dst = SET_DEST (set), REG_P (dst))
+	  && REGNO (dst) == targetm.flags_regnum
+	  && REG_P (XEXP (src, 0))
+	  && (REG_P (XEXP (src, 1)) || CONSTANT_P (XEXP (src, 1))))
+	{
+	  /* Eliminate a compare that's redundant with the previous.  */
+	  if (last_cmp
+	      && rtx_equal_p (last_cmp->in_a, XEXP (src, 0))
+	      && rtx_equal_p (last_cmp->in_b, XEXP (src, 1)))
+	    {
+	      find_flags_uses_in_bb (last_cmp, bb, insn);
+	      delete_insn (insn);
+	      continue;
+	    }
+
+          last_cmp = XCNEW (struct comparison);
+	  last_cmp->insn = insn;
+	  last_cmp->in_a = XEXP (src, 0);
+	  last_cmp->in_b = XEXP (src, 1);
+	  last_cmp->orig_mode = GET_MODE (dst);
+	  VEC_safe_push (comparison_struct_p, heap, all_compares, last_cmp);
+
+	  find_flags_uses_in_bb (last_cmp, bb, insn);
+
+	  /* It's unusual, but be prepared for comparison patterns that
+	     also clobber an input, or perhaps a scratch.  */
+	  bitmap_clear (killed);
+	  df_simulate_find_defs (insn, killed);
+	}
+      else if (last_cmp)
+	{
+	  /* Notice if this instruction kills the flags register.  If so,
+	     any comparison we're holding is no longer valid.  */
+	  bitmap_clear (killed);
+	  df_simulate_find_defs (insn, killed);
+	  if (bitmap_bit_p (killed, targetm.flags_regnum))
+	    {
+	      last_cmp = NULL;
+	      continue;
+	    }
+	}
+      else
+	continue;
+
+      /* Notice if any of the inputs to the comparison have changed.  */
+      if (bitmap_bit_p (killed, REGNO (last_cmp->in_a)))
+	last_cmp = NULL;
+      else if (REG_P (last_cmp->in_b)
+	       && bitmap_bit_p (killed, REGNO (last_cmp->in_b)))
+	last_cmp = NULL;
+    }
+
+  BITMAP_FREE (killed);
+
+  /* Remember the live comparison for subsequent members of
+     the extended basic block.  */
+  if (last_cmp)
+    {
+      bb->aux = last_cmp;
+
+      /* Note that df does not create use chains that cross basic blocks.
+	 Therefore, given that we've not yet eliminated duplicate comparisons,
+	 if the flags register is live (in the sense of being used) then we're
+	 not going to be able to find all uses.  Given that this target needed
+	 this pass in the first place, this should be exceedingly rare, caused
+	 by a post-reload splitter creating new basic blocks.  */
+      if (bitmap_bit_p (DF_LR_OUT (bb), targetm.flags_regnum))
+	last_cmp->missing_uses = true;
+    }
+}
+
+/* Find all comparisons in the function.  */
+
+static void
+find_comparisons (void)
+{
+  struct dom_walk_data data;
+
+  memset (&data, 0, sizeof(data));
+  data.dom_direction = CDI_DOMINATORS;
+  data.before_dom_children = find_comparisons_in_bb;
+
+  calculate_dominance_info (CDI_DOMINATORS);
+
+  init_walk_dominator_tree (&data);
+  walk_dominator_tree (&data, ENTRY_BLOCK_PTR);
+  fini_walk_dominator_tree (&data);
+
+  clear_aux_for_blocks ();
+  free_dominance_info (CDI_DOMINATORS);
+}
+
+/* Select an alternate CC_MODE for a comparison insn comparing A and B.
+   Note that inputs are almost certainly different than the IN_A and IN_B
+   stored in CMP -- we're called while attempting to eliminate the compare
+   after all.  Return the new FLAGS rtx if successful, else return NULL.  */
+
+static rtx
+maybe_select_cc_mode (struct comparison *cmp, rtx a, rtx b)
+{
+  enum machine_mode sel_mode;
+  const int n = cmp->n_uses;
+  rtx flags = NULL;
+
+#ifndef SELECT_CC_MODE
+  /* Minimize code differences when this target macro is undefined.  */
+  return NULL;
+#define SELECT_CC_MODE(A,B,C) (gcc_unreachable (), VOIDmode)
+#endif
+
+  /* If we don't have access to all of the uses, we can't validate.  */
+  if (cmp->missing_uses || n == 0)
+    return NULL;
+
+  /* Find a new mode that works for all of the uses.  Special case the
+     common case of exactly one use.  */
+  if (n == 1)
+    {
+      sel_mode = SELECT_CC_MODE (cmp->uses[0].code, a, b);
+      if (sel_mode != cmp->orig_mode)
+	{
+	  flags = gen_rtx_REG (sel_mode, targetm.flags_regnum);
+	  validate_change (cmp->uses[0].insn, cmp->uses[0].loc, flags, true);
+	}
+    }
+  else
+    {
+      int i;
+
+      sel_mode = SELECT_CC_MODE (cmp->uses[0].code, a, b);
+      for (i = 1; i < n; ++i)
+	{
+	  enum machine_mode new_mode;
+	  new_mode = SELECT_CC_MODE (cmp->uses[i].code, a, b);
+	  if (new_mode != sel_mode)
+	    {
+	      sel_mode = targetm.cc_modes_compatible (sel_mode, new_mode);
+	      if (sel_mode == VOIDmode)
+		return NULL;
+	    }
+	}
+      
+      if (sel_mode != cmp->orig_mode)
+	{
+	  flags = gen_rtx_REG (sel_mode, targetm.flags_regnum);
+	  for (i = 0; i < n; ++i)
+	    validate_change (cmp->uses[i].insn, cmp->uses[i].loc, flags, true);
+	}
+    }
+
+  return flags;
+}
+
+/* Attempt to find an instruction prior to CMP that can be used to compute the
+   same flags value as the comparison itself.  Return true if successful.  */
+
+static bool
+try_eliminate_compare (struct comparison *cmp)
+{
+  df_ref *use_rec, use, def;
+  rtx dinsn, dpat, x, flags, cmp_src;
+
+  /* ??? For the moment we don't handle comparisons for which IN_B
+     is a register.  We accepted these during initial comparison 
+     recognition in order to eliminate duplicate compares.
+     An improvement here would be to handle
+	x = a - b; if (a < b)
+     Note that this doesn't follow the USE-DEF chain from X, but
+     since we already have to search for the previous clobber of
+     the flags register, this wouldn't really be a problem.  */
+  if (!CONSTANT_P (cmp->in_b))
+    return false;
+
+  /* The relevant instruction is the definition for the use in the
+     comparison instruction.  */
+  for (use_rec = DF_INSN_USES (cmp->insn); ; use_rec++)
+    {
+      use = *use_rec;
+      if (DF_REF_REGNO (use) == REGNO (cmp->in_a))
+	break;
+    }
+  if (DF_REF_CHAIN (use) == NULL)
+    return false;
+
+  def = DF_REF_CHAIN (use)->ref;
+  gcc_assert (DF_REF_REG_DEF_P (def));
+
+  /* If the defintion comes from a parameter, or such, there's no insn.  */
+  if (DF_REF_IS_ARTIFICIAL (def))
+    return false;
+
+  /* Make sure that the defining instruction is of the proper form.
+     That is, a single set plus a clobber of the flags register.  */
+  dinsn = DF_REF_INSN (def);
+  if (!NONJUMP_INSN_P (dinsn))
+    return false;
+  dpat = PATTERN (dinsn);
+  if (GET_CODE (dpat) != PARALLEL || XVECLEN (dpat, 0) != 2)
+    return false;
+  x = XVECEXP (dpat, 0, 0);
+  if (GET_CODE (x) != SET || DF_REF_LOC (def) != &SET_DEST (x))
+    return false;
+  x = XVECEXP (dpat, 0, 1);
+  if (GET_CODE (x) != CLOBBER)
+    return false;
+  flags = XEXP (x, 0);
+  if (!REG_P (flags) || REGNO (flags) != targetm.flags_regnum)
+    return false;
+
+  /* Make sure that the flags are not clobbered in between the two
+     instructions.  Unfortunately, we don't get DEF-DEF chains, so
+     do this the old fashioned way.  */
+  if (reg_set_between_p (flags, dinsn, cmp->insn))
+    return false;
+
+  /* Determine if we ought to use a different CC_MODE here.  */
+  cmp_src = SET_SRC (XVECEXP (dpat, 0, 0));
+  x = maybe_select_cc_mode (cmp, cmp_src, cmp->in_b);
+  if (x != NULL)
+    flags = x;
+
+  /* Generate a new comparison for installation in the setter.  */
+  x = copy_rtx (cmp_src);
+  x = gen_rtx_COMPARE (GET_MODE (flags), x, cmp->in_b);
+  x = gen_rtx_SET (VOIDmode, flags, x);
+
+  /* Succeed if the new instruction is valid.  */
+  validate_change (dinsn, &XVECEXP (dpat, 0, 1), x, true);
+  if (!apply_change_group ())
+    return false;
+ 
+  /* Success.  Delete the compare insn...  */
+  delete_insn (cmp->insn);
+
+  /* ... and any notes that are now irrelevant due to multi-stores. */
+  x = find_regno_note (dinsn, REG_UNUSED, targetm.flags_regnum);
+  if (x)
+    remove_note (dinsn, x);
+  x = find_reg_note (dinsn, REG_EQUAL, NULL);
+  if (x)
+    remove_note (dinsn, x);
+  x = find_reg_note (dinsn, REG_EQUIV, NULL);
+  if (x)
+    remove_note (dinsn, x);
+
+  return true;
+}
+
+/* Main entry point to the pass.  */
+
+static unsigned int
+execute_compare_elim_after_reload (void)
+{
+  df_set_flags (DF_DEFER_INSN_RESCAN);
+  df_live_add_problem ();
+  df_chain_add_problem (DF_DU_CHAIN + DF_UD_CHAIN);
+  df_analyze ();
+
+  gcc_checking_assert (all_compares == NULL);
+
+  /* Locate all comparisons and their uses, and eliminate duplicates.  */
+  find_comparisons ();
+  if (all_compares)
+    {
+      struct comparison *cmp;
+      size_t i;
+
+      /* Eliminate comparisons that are redundant with flags computation.  */
+      for (i = 0; VEC_iterate (comparison_struct_p, all_compares, i, cmp); ++i)
+	{
+	  try_eliminate_compare (cmp);
+	  XDELETE (cmp);
+	}
+
+      VEC_free (comparison_struct_p, heap, all_compares);
+      all_compares = NULL;
+
+      df_remove_problem (df_chain);
+      df_analyze ();
+    }
+
+  return 0;
+}
+
+static bool
+gate_compare_elim_after_reload (void)
+{
+  return (flag_compare_elim_after_reload
+	  && targetm.flags_regnum != INVALID_REGNUM);
+}
+
+struct rtl_opt_pass pass_compare_elim_after_reload =
+{
+ {
+  RTL_PASS,
+  "cmpelim",				/* name */
+  gate_compare_elim_after_reload,	/* gate */
+  execute_compare_elim_after_reload,	/* execute */
+  NULL,					/* sub */
+  NULL,					/* next */
+  0,					/* static_pass_number */
+  TV_NONE,				/* tv_id */
+  0,					/* properties_required */
+  0,					/* properties_provided */
+  0,					/* properties_destroyed */
+  0,					/* todo_flags_start */
+  TODO_df_finish
+  | TODO_df_verify
+  | TODO_verify_rtl_sharing
+  | TODO_dump_func
+  | TODO_ggc_collect			/* todo_flags_finish */
+ }
+};
diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c
index 25bfa0d..e5bfdae 100644
--- a/gcc/config/mn10300/mn10300.c
+++ b/gcc/config/mn10300/mn10300.c
@@ -3023,4 +3023,7 @@ mn10300_md_asm_clobbers (tree outputs ATTRIBUTE_UNUSED,
 #undef TARGET_MD_ASM_CLOBBERS
 #define TARGET_MD_ASM_CLOBBERS  mn10300_md_asm_clobbers
 
+#undef  TARGET_FLAGS_REGNUM
+#define TARGET_FLAGS_REGNUM  CC_REG
+
 struct gcc_target targetm = TARGET_INITIALIZER;
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 800c592..e50de64 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -337,7 +337,7 @@ Objective-C and Objective-C++ Dialects}.
 -fauto-inc-dec -fbranch-probabilities -fbranch-target-load-optimize @gol
 -fbranch-target-load-optimize2 -fbtr-bb-exclusive -fcaller-saves @gol
 -fcheck-data-deps -fcombine-stack-adjustments -fconserve-stack @gol
--fcprop-registers -fcrossjumping @gol
+-fcompare-elim -fcprop-registers -fcrossjumping @gol
 -fcse-follow-jumps -fcse-skip-blocks -fcx-fortran-rules @gol
 -fcx-limited-range @gol
 -fdata-sections -fdce -fdce @gol
@@ -5870,6 +5870,7 @@ compilation time.
 @option{-O} turns on the following optimization flags:
 @gccoptlist{
 -fauto-inc-dec @gol
+-fcompare-elim @gol
 -fcprop-registers @gol
 -fdce @gol
 -fdefer-pop @gol
@@ -7680,6 +7681,18 @@ use hidden visibility) is similar to @code{-fwhole-program}.  See
 Enabled by default when LTO support in GCC is enabled and GCC was compiled
 with linker supporting plugins (GNU ld or @code{gold}).
 
+@item -fcompare-elim
+@opindex fcompare-elim
+After register allocation and post-register allocation instruction splitting,
+identify arithmetic instructions that compute processor flags similar to a
+comparison operation based on that arithmetic.  If possible, eliminate the
+explicit comparison operation.
+
+This pass only applies to certain targets that cannot explicitly represent
+the comparison operation before register allocation is complete.
+
+Enabled at levels @option{-O}, @option{-O2}, @option{-O3}, @option{-Os}.
+
 @item -fcprop-registers
 @opindex fcprop-registers
 After register allocation and post-register allocation instruction splitting,
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 139c5a7..5dfd100 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -4345,6 +4345,10 @@ to return a nonzero value when it is required, the compiler will run out
 of spill registers and print a fatal error message.
 @end deftypefn
 
+@deftypevr {Target Hook} {unsigned int} TARGET_FLAGS_REGNUM
+If the target has a dedicated flags register, and it needs to use the post-reload comparison elimination pass, then this value should be set appropriately.
+@end deftypevr
+
 @node Scalar Return
 @subsection How Scalar Function Values Are Returned
 @cindex return values in registers
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 2085816..bd49012 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -4333,6 +4333,8 @@ to return a nonzero value when it is required, the compiler will run out
 of spill registers and print a fatal error message.
 @end deftypefn
 
+@hook TARGET_FLAGS_REGNUM
+
 @node Scalar Return
 @subsection How Scalar Function Values Are Returned
 @cindex return values in registers
diff --git a/gcc/opts.c b/gcc/opts.c
index 42d53f4..7001122 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -456,6 +456,7 @@ static const struct default_options default_options_table[] =
     { OPT_LEVELS_1_PLUS, OPT_ftree_sink, NULL, 1 },
     { OPT_LEVELS_1_PLUS, OPT_ftree_ch, NULL, 1 },
     { OPT_LEVELS_1_PLUS, OPT_fcombine_stack_adjustments, NULL, 1 },
+    { OPT_LEVELS_1_PLUS, OPT_fcompare_elim, NULL, 1 },
 
     /* -O2 optimizations.  */
     { OPT_LEVELS_2_PLUS, OPT_finline_small_functions, NULL, 1 },
diff --git a/gcc/passes.c b/gcc/passes.c
index 804ac9f..5aba987 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -1021,6 +1021,7 @@ init_optimization_passes (void)
 	  NEXT_PASS (pass_gcse2);
 	  NEXT_PASS (pass_split_after_reload);
 	  NEXT_PASS (pass_implicit_zee);
+	  NEXT_PASS (pass_compare_elim_after_reload);
 	  NEXT_PASS (pass_branch_target_load_optimize1);
 	  NEXT_PASS (pass_thread_prologue_and_epilogue);
 	  NEXT_PASS (pass_rtl_dse2);
diff --git a/gcc/recog.h b/gcc/recog.h
index 217c6e5..534d2c9 100644
--- a/gcc/recog.h
+++ b/gcc/recog.h
@@ -18,6 +18,9 @@ You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
+#ifndef GCC_RECOG_H
+#define GCC_RECOG_H
+
 /* Random number that should be large enough for all purposes.  */
 #define MAX_RECOG_ALTERNATIVES 30
 
@@ -305,3 +308,5 @@ struct insn_data_d
 
 extern const struct insn_data_d insn_data[];
 extern int peep2_current_count;
+
+#endif /* GCC_RECOG_H */
diff --git a/gcc/target.def b/gcc/target.def
index 9d96e65..29d2a51 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -1627,6 +1627,15 @@ DEFHOOK
  bool, (enum machine_mode mode),
  hook_bool_mode_false)
 
+/* Register number for a flags register.  Only needs to be defined if the
+   target is constrainted to use post-reload comparison elimination.  */
+DEFHOOKPOD
+(flags_regnum,
+ "If the target has a dedicated flags register, and it needs to use the\
+ post-reload comparison elimination pass, then this value should be set\
+ appropriately.",
+ unsigned int, INVALID_REGNUM)
+
 /* Compute a (partial) cost for rtx X.  Return true if the complete
    cost has been computed, and false if subexpressions should be
    scanned.  In either case, *TOTAL contains the cost result.  */
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 32d8f40..dd82288 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -551,6 +551,7 @@ extern struct rtl_opt_pass pass_reorder_blocks;
 extern struct rtl_opt_pass pass_branch_target_load_optimize2;
 extern struct rtl_opt_pass pass_leaf_regs;
 extern struct rtl_opt_pass pass_split_before_sched2;
+extern struct rtl_opt_pass pass_compare_elim_after_reload;
 extern struct rtl_opt_pass pass_sched2;
 extern struct rtl_opt_pass pass_stack_regs;
 extern struct rtl_opt_pass pass_stack_regs_run;
-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 90+ messages in thread

* [PATCH 18/28] mn10300: Cleanup all arithmetic.
  2011-01-10 20:33 [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Richard Henderson
                   ` (22 preceding siblings ...)
  2011-01-10 20:34 ` [PATCH 26/28] mn10300: Auto-clobber the flags in asms Richard Henderson
@ 2011-01-10 20:34 ` Richard Henderson
  2011-01-19 16:58   ` Jeff Law
  2011-01-10 20:34 ` [PATCH 22/28] mn10300: Emit retf instruction Richard Henderson
                   ` (5 subsequent siblings)
  29 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-10 20:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: nickc, law, Richard Henderson

From: Richard Henderson <rth@twiddle.net>

For addition and logicals, define an operation-plus-flags update pattern
in preparation for compare elimination.  In addition, clean up the way
we compare and validate CC_MODEs.  Define NEG in terms of NOT; this is
smaller and allows a non-clobbering destination alternative.
---
 gcc/config/mn10300/mn10300-modes.def |    2 +
 gcc/config/mn10300/mn10300-protos.h  |    7 +-
 gcc/config/mn10300/mn10300.c         |  481 ++++++++++-----
 gcc/config/mn10300/mn10300.h         |    2 +-
 gcc/config/mn10300/mn10300.md        | 1120 +++++++++++-----------------------
 gcc/config/mn10300/predicates.md     |   16 +
 6 files changed, 684 insertions(+), 944 deletions(-)

diff --git a/gcc/config/mn10300/mn10300-modes.def b/gcc/config/mn10300/mn10300-modes.def
index 8bcffcd..832663e 100644
--- a/gcc/config/mn10300/mn10300-modes.def
+++ b/gcc/config/mn10300/mn10300-modes.def
@@ -19,4 +19,6 @@
    the Free Software Foundation, , Inc., 51 Franklin Street - Fifth
    Floor, Boston, MA 02110-1301, USA.  */
 
+CC_MODE (CCZN);
+CC_MODE (CCZNC);
 CC_MODE (CC_FLOAT);
diff --git a/gcc/config/mn10300/mn10300-protos.h b/gcc/config/mn10300/mn10300-protos.h
index d0ce1b3..28a9412 100644
--- a/gcc/config/mn10300/mn10300-protos.h
+++ b/gcc/config/mn10300/mn10300-protos.h
@@ -32,13 +32,16 @@ extern int   mn10300_get_live_callee_saved_regs (void);
 extern bool  mn10300_hard_regno_mode_ok (unsigned int, Mmode);
 extern bool  mn10300_legitimate_constant_p (rtx);
 extern bool  mn10300_modes_tieable (Mmode, Mmode);
-extern Cstar mn10300_output_cmp (rtx, rtx);
+extern Cstar mn10300_output_add (rtx[3], bool);
 extern void  mn10300_print_operand (FILE *, rtx, int);
 extern void  mn10300_print_operand_address (FILE *, rtx);
 extern void  mn10300_print_reg_list (FILE *, int);
-extern Mmode mn10300_select_cc_mode (rtx);
+extern Mmode mn10300_select_cc_mode (enum rtx_code, rtx, rtx);
 extern int   mn10300_store_multiple_operation (rtx, Mmode);
 extern int   mn10300_symbolic_operand (rtx, Mmode);
+extern void  mn10300_split_cbranch (Mmode, rtx, rtx);
+extern int   mn10300_split_and_operand_count (rtx);
+extern bool  mn10300_match_ccmode (rtx, Mmode);
 #endif /* RTX_CODE */
 
 extern bool  mn10300_regno_in_class_p (unsigned, int, bool);
diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c
index 36c35ca..8e62a0c 100644
--- a/gcc/config/mn10300/mn10300.c
+++ b/gcc/config/mn10300/mn10300.c
@@ -81,6 +81,14 @@ static const struct default_options mn10300_option_optimization_table[] =
     { OPT_LEVELS_1_PLUS, OPT_fomit_frame_pointer, NULL, 1 },
     { OPT_LEVELS_NONE, 0, NULL, 0 }
   };
+
+#define CC_FLAG_Z	1
+#define CC_FLAG_N	2
+#define CC_FLAG_C	4
+#define CC_FLAG_V	8
+
+static int cc_flags_for_mode(enum machine_mode);
+static int cc_flags_for_code(enum rtx_code);
 \f
 /* Implement TARGET_HANDLE_OPTION.  */
 
@@ -134,7 +142,7 @@ mn10300_option_override (void)
 	 when this flag is not enabled by default.  */
       flag_split_wide_types = 1;
     }
-  
+
   if (mn10300_tune_string)
     {
       if (strcasecmp (mn10300_tune_string, "mn10300") == 0)
@@ -171,95 +179,82 @@ mn10300_print_operand (FILE *file, rtx x, int code)
     {
       case 'b':
       case 'B':
-	if (GET_MODE (XEXP (x, 0)) == CC_FLOATmode)
-	  {
-	    switch (code == 'b' ? GET_CODE (x)
-		    : reverse_condition_maybe_unordered (GET_CODE (x)))
-	      {
-	      case NE:
-		fprintf (file, "ne");
-		break;
-	      case EQ:
-		fprintf (file, "eq");
-		break;
-	      case GE:
-		fprintf (file, "ge");
-		break;
-	      case GT:
-		fprintf (file, "gt");
-		break;
-	      case LE:
-		fprintf (file, "le");
-		break;
-	      case LT:
-		fprintf (file, "lt");
-		break;
-	      case ORDERED:
-		fprintf (file, "lge");
-		break;
-	      case UNORDERED:
-		fprintf (file, "uo");
-		break;
-	      case LTGT:
-		fprintf (file, "lg");
-		break;
-	      case UNEQ:
-		fprintf (file, "ue");
-		break;
-	      case UNGE:
-		fprintf (file, "uge");
-		break;
-	      case UNGT:
-		fprintf (file, "ug");
-		break;
-	      case UNLE:
-		fprintf (file, "ule");
-		break;
-	      case UNLT:
-		fprintf (file, "ul");
-		break;
-	      default:
-		gcc_unreachable ();
-	      }
-	    break;
-	  }
-	/* These are normal and reversed branches.  */
-	switch (code == 'b' ? GET_CODE (x) : reverse_condition (GET_CODE (x)))
-	  {
-	  case NE:
-	    fprintf (file, "ne");
-	    break;
-	  case EQ:
-	    fprintf (file, "eq");
-	    break;
-	  case GE:
-	    fprintf (file, "ge");
-	    break;
-	  case GT:
-	    fprintf (file, "gt");
-	    break;
-	  case LE:
-	    fprintf (file, "le");
-	    break;
-	  case LT:
-	    fprintf (file, "lt");
-	    break;
-	  case GEU:
-	    fprintf (file, "cc");
-	    break;
-	  case GTU:
-	    fprintf (file, "hi");
-	    break;
-	  case LEU:
-	    fprintf (file, "ls");
-	    break;
-	  case LTU:
-	    fprintf (file, "cs");
-	    break;
-	  default:
-	    gcc_unreachable ();
-	  }
+	{
+	  enum rtx_code cmp = GET_CODE (x);
+	  enum machine_mode mode = GET_MODE (XEXP (x, 0));
+	  const char *str;
+	  int have_flags;
+
+	  if (code == 'B')
+	    cmp = reverse_condition (cmp);
+	  have_flags = cc_flags_for_mode (mode);
+
+	  switch (cmp)
+	    {
+	    case NE:
+	      str = "ne";
+	      break;
+	    case EQ:
+	      str = "eq";
+	      break;
+	    case GE:
+	      /* bge is smaller than bnc.  */
+	      str = (have_flags & CC_FLAG_V ? "ge" : "nc");
+	      break;
+	    case LT:
+	      str = (have_flags & CC_FLAG_V ? "lt" : "ns");
+	      break;
+	    case GT:
+	      str = "gt";
+	      break;
+	    case LE:
+	      str = "le";
+	      break;
+	    case GEU:
+	      str = "cc";
+	      break;
+	    case GTU:
+	      str = "hi";
+	      break;
+	    case LEU:
+	      str = "ls";
+	      break;
+	    case LTU:
+	      str = "cs";
+	      break;
+	    case ORDERED:
+	      str = "lge";
+	      break;
+	    case UNORDERED:
+	      str = "uo";
+	      break;
+	    case LTGT:
+	      str = "lg";
+	      break;
+	    case UNEQ:
+	      str = "ue";
+	      break;
+	    case UNGE:
+	      str = "uge";
+	      break;
+	    case UNGT:
+	      str = "ug";
+	      break;
+	    case UNLE:
+	      str = "ule";
+	      break;
+	    case UNLT:
+	      str = "ul";
+	      break;
+	    default:
+	      gcc_unreachable ();
+	    }
+
+	  gcc_checking_assert ((cc_flags_for_code (cmp) & ~have_flags) == 0);
+	  fputs (str, file);
+	}
 	break;
+
       case 'C':
 	/* This is used for the operand to a call instruction;
 	   if it's a REG, enclose it in parens, else output
@@ -1709,95 +1704,96 @@ mn10300_function_value_regno_p (const unsigned int regno)
  return (regno == FIRST_DATA_REGNUM || regno == FIRST_ADDRESS_REGNUM);
 }
 
-/* Output a compare insn.  */
+/* Output an addition operation.  */
 
 const char *
-mn10300_output_cmp (rtx operand, rtx insn)
+mn10300_output_add (rtx operands[3], bool need_flags)
 {
-  rtx temp;
-  int past_call = 0;
+  rtx dest, src1, src2;
+  unsigned int dest_regnum, src1_regnum, src2_regnum;
+  enum reg_class src1_class, src2_class, dest_class;
 
-  /* We can save a byte if we can find a register which has the value
-     zero in it.  */
-  temp = PREV_INSN (insn);
-  while (optimize && temp)
-    {
-      rtx set;
-
-      /* We allow the search to go through call insns.  We record
-	 the fact that we've past a CALL_INSN and reject matches which
-	 use call clobbered registers.  */
-      if (LABEL_P (temp)
-	  || JUMP_P (temp)
-	  || GET_CODE (temp) == BARRIER)
-	break;
+  dest = operands[0];
+  src1 = operands[1];
+  src2 = operands[2];
 
-      if (CALL_P (temp))
-	past_call = 1;
+  dest_regnum = true_regnum (dest);
+  src1_regnum = true_regnum (src1);
 
-      if (GET_CODE (temp) == NOTE)
-	{
-	  temp = PREV_INSN (temp);
-	  continue;
-	}
+  dest_class = REGNO_REG_CLASS (dest_regnum);
+  src1_class = REGNO_REG_CLASS (src1_regnum);
 
-      /* It must be an insn, see if it is a simple set.  */
-      set = single_set (temp);
-      if (!set)
-	{
-	  temp = PREV_INSN (temp);
-	  continue;
-	}
+  if (GET_CODE (src2) == CONST_INT)
+    {
+      gcc_assert (dest_regnum == src1_regnum);
 
-      /* Are we setting a data register to zero (this does not win for
-	 address registers)?
-
-	 If it's a call clobbered register, have we past a call?
-
-	 Make sure the register we find isn't the same as ourself;
-	 the mn10300 can't encode that.
-
-	 ??? reg_set_between_p return nonzero anytime we pass a CALL_INSN
-	 so the code to detect calls here isn't doing anything useful.  */
-      if (REG_P (SET_DEST (set))
-	  && SET_SRC (set) == CONST0_RTX (GET_MODE (SET_DEST (set)))
-	  && !reg_set_between_p (SET_DEST (set), temp, insn)
-	  && (REGNO_REG_CLASS (REGNO (SET_DEST (set)))
-	      == REGNO_REG_CLASS (REGNO (operand)))
-	  && REGNO_REG_CLASS (REGNO (SET_DEST (set))) != EXTENDED_REGS
-	  && REGNO (SET_DEST (set)) != REGNO (operand)
-	  && (!past_call
-	      || ! call_really_used_regs [REGNO (SET_DEST (set))]))
-	{
-	  rtx xoperands[2];
-	  xoperands[0] = operand;
-	  xoperands[1] = SET_DEST (set);
+      if (src2 == const1_rtx && !need_flags)
+	return "inc %0";
+      if (INTVAL (src2) == 4 && !need_flags && dest_class != DATA_REGS)
+        return "inc4 %0";
 
-	  output_asm_insn ("cmp %1,%0", xoperands);
-	  return "";
-	}
+      gcc_assert (!need_flags || dest_class != SP_REGS);
+      return "add %2,%0";
+    }
+  else if (CONSTANT_P (src2))
+    return "add %2,%0";
+
+  src2_regnum = true_regnum (src2);
+  src2_class = REGNO_REG_CLASS (src2_regnum);
+      
+  if (dest_regnum == src1_regnum)
+    return "add %2,%0";
+  if (dest_regnum == src2_regnum)
+    return "add %1,%0";
+
+  /* The rest of the cases are reg = reg+reg.  For AM33, we can implement
+     this directly, as below, but when optimizing for space we can sometimes
+     do better by using a mov+add.  For MN103, we claimed that we could
+     implement a three-operand add because the various move and add insns
+     change sizes across register classes, and we can often do better than
+     reload in chosing which operand to move.  */
+  if (TARGET_AM33 && optimize_insn_for_speed_p ())
+    return "add %2,%1,%0";
+
+  /* Catch cases where no extended register was used.  */
+  if (src1_class != EXTENDED_REGS
+      && src2_class != EXTENDED_REGS
+      && dest_class != EXTENDED_REGS)
+    {
+      /* We have to copy one of the sources into the destination, then
+         add the other source to the destination.
+
+         Carefully select which source to copy to the destination; a
+         naive implementation will waste a byte when the source classes
+         are different and the destination is an address register.
+         Selecting the lowest cost register copy will optimize this
+         sequence.  */
+      if (src1_class == dest_class)
+        return "mov %1,%0\n\tadd %2,%0";
+      else
+	return "mov %2,%0\n\tadd %1,%0";
+    }
 
-      if (REGNO_REG_CLASS (REGNO (operand)) == EXTENDED_REGS
-	  && REG_P (SET_DEST (set))
-	  && SET_SRC (set) == CONST0_RTX (GET_MODE (SET_DEST (set)))
-	  && !reg_set_between_p (SET_DEST (set), temp, insn)
-	  && (REGNO_REG_CLASS (REGNO (SET_DEST (set)))
-	      != REGNO_REG_CLASS (REGNO (operand)))
-	  && REGNO_REG_CLASS (REGNO (SET_DEST (set))) == EXTENDED_REGS
-	  && REGNO (SET_DEST (set)) != REGNO (operand)
-	  && (!past_call
-	      || ! call_really_used_regs [REGNO (SET_DEST (set))]))
-	{
-	  rtx xoperands[2];
-	  xoperands[0] = operand;
-	  xoperands[1] = SET_DEST (set);
+  /* At least one register is an extended register.  */
 
-	  output_asm_insn ("cmp %1,%0", xoperands);
-	  return "";
-	}
-      temp = PREV_INSN (temp);
-    }
-  return "cmp 0,%0";
+  /* The three operand add instruction on the am33 is a win iff the
+     output register is an extended register, or if both source
+     registers are extended registers.  */
+  if (dest_class == EXTENDED_REGS || src1_class == src2_class)
+    return "add %2,%1,%0";
+
+  /* It is better to copy one of the sources to the destination, then
+     perform a 2 address add.  The destination in this case must be
+     an address or data register and one of the sources must be an
+     extended register and the remaining source must not be an extended
+     register.
+
+     The best code for this case is to copy the extended reg to the
+     destination, then emit a two address add.  */
+  if (src1_class == EXTENDED_REGS)
+    return "mov %1,%0\n\tadd %2,%0";
+  else
+    return "mov %2,%0\n\tadd %1,%0";
 }
 
 /* Return 1 if X contains a symbolic expression.  We know these
@@ -2614,10 +2610,80 @@ mn10300_modes_tieable (enum machine_mode mode1, enum machine_mode mode2)
   return false;
 }
 
+static int
+cc_flags_for_mode (enum machine_mode mode)
+{
+  switch (mode)
+    {
+    case CCmode:
+      return CC_FLAG_Z | CC_FLAG_N | CC_FLAG_C | CC_FLAG_V;
+    case CCZNCmode:
+      return CC_FLAG_Z | CC_FLAG_N | CC_FLAG_C;
+    case CCZNmode:
+      return CC_FLAG_Z | CC_FLAG_N;
+    case CC_FLOATmode:
+      return -1;
+    default:
+      gcc_unreachable ();
+    }
+}
+
+static int
+cc_flags_for_code (enum rtx_code code)
+{
+  switch (code)
+    {
+    case EQ:	/* Z */
+    case NE:	/* ~Z */
+      return CC_FLAG_Z;
+
+    case LT:	/* N */
+    case GE:	/* ~N */
+      return CC_FLAG_N;
+      break;
+
+    case GT:    /* ~(Z|(N^V)) */
+    case LE:    /* Z|(N^V) */
+      return CC_FLAG_Z | CC_FLAG_N | CC_FLAG_V;
+
+    case GEU:	/* ~C */
+    case LTU:	/* C */
+      return CC_FLAG_C;
+
+    case GTU:	/* ~(C | Z) */
+    case LEU:	/* C | Z */
+      return CC_FLAG_Z | CC_FLAG_C;
+
+    case ORDERED:
+    case UNORDERED:
+    case LTGT:
+    case UNEQ:
+    case UNGE:
+    case UNGT:
+    case UNLE:
+    case UNLT:
+      return -1;
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
 enum machine_mode
-mn10300_select_cc_mode (rtx x)
+mn10300_select_cc_mode (enum rtx_code code, rtx x, rtx y ATTRIBUTE_UNUSED)
 {
-  return (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) ? CC_FLOATmode : CCmode;
+  int req;
+
+  if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
+    return CC_FLOATmode;
+
+  req = cc_flags_for_code (code);
+
+  if (req & CC_FLAG_V)
+    return CCmode;
+  if (req & CC_FLAG_C)
+    return CCZNCmode;
+  return CCZNmode;
 }
 
 static inline bool
@@ -2736,6 +2802,83 @@ mn10300_conditional_register_usage (void)
     fixed_regs[PIC_OFFSET_TABLE_REGNUM] =
     call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
 }
+
+\f
+/* A helper function for splitting cbranch patterns after reload.  */
+
+void
+mn10300_split_cbranch (enum machine_mode cmp_mode, rtx cmp_op, rtx label_ref)
+{
+  rtx flags, x;
+
+  flags = gen_rtx_REG (cmp_mode, CC_REG);
+  x = gen_rtx_COMPARE (cmp_mode, XEXP (cmp_op, 0), XEXP (cmp_op, 1));
+  x = gen_rtx_SET (VOIDmode, flags, x);
+  emit_insn (x);
+
+  x = gen_rtx_fmt_ee (GET_CODE (cmp_op), VOIDmode, flags, const0_rtx);
+  x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, label_ref, pc_rtx);
+  x = gen_rtx_SET (VOIDmode, pc_rtx, x);
+  emit_jump_insn (x);
+}
+
+/* A helper function for matching parallels that set the flags.  */
+
+bool
+mn10300_match_ccmode (rtx insn, enum machine_mode cc_mode)
+{
+  rtx op1, flags;
+  enum machine_mode flags_mode;
+
+  gcc_checking_assert (XVECLEN (PATTERN (insn), 0) == 2);
+
+  op1 = XVECEXP (PATTERN (insn), 0, 1);
+  gcc_checking_assert (GET_CODE (SET_SRC (op1)) == COMPARE);
+
+  flags = SET_DEST (op1);
+  flags_mode = GET_MODE (flags);
+
+  if (GET_MODE (SET_SRC (op1)) != flags_mode)
+    return false;
+  if (GET_MODE_CLASS (flags_mode) != MODE_CC)
+    return false;
+
+  /* Ensure that the mode of FLAGS is compatible with CC_MODE.  */
+  if (cc_flags_for_mode (flags_mode) & ~cc_flags_for_mode (cc_mode))
+    return false;
+
+  return true;
+}
+
+int
+mn10300_split_and_operand_count (rtx op)
+{
+  HOST_WIDE_INT val = INTVAL (op);
+  int count;
+
+  if (val < 0)
+    {
+      /* High bit is set, look for bits clear at the bottom.  */
+      count = exact_log2 (-val);
+      if (count < 0)
+	return 0;
+      /* This is only size win if we can use the asl2 insn.  Otherwise we
+	 would be replacing 1 6-byte insn with 2 3-byte insns.  */
+      if (count > (optimize_insn_for_speed_p () ? 2 : 4))
+	return 0;
+      return -count;
+    }
+  else
+    {
+      /* High bit is clear, look for bits set at the bottom.  */
+      count = exact_log2 (val + 1);
+      count = 32 - count;
+      /* Again, this is only a size win with asl2.  */
+      if (count > (optimize_insn_for_speed_p () ? 2 : 4))
+	return 0;
+      return -count;
+    }
+}
 \f
 /* Initialize the GCC target structure.  */
 
diff --git a/gcc/config/mn10300/mn10300.h b/gcc/config/mn10300/mn10300.h
index 43bad54..34ff2ae 100644
--- a/gcc/config/mn10300/mn10300.h
+++ b/gcc/config/mn10300/mn10300.h
@@ -600,7 +600,7 @@ do {									     \
 /* Non-global SYMBOL_REFs have SYMBOL_REF_FLAG enabled.  */
 #define MN10300_GLOBAL_P(X) (! SYMBOL_REF_FLAG (X))
 \f
-#define SELECT_CC_MODE(OP, X, Y)  mn10300_select_cc_mode (X)
+#define SELECT_CC_MODE(OP, X, Y)  mn10300_select_cc_mode (OP, X, Y)
 #define REVERSIBLE_CC_MODE(MODE)  0
 \f
 /* Nonzero if access to memory by bytes or half words is no faster
diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md
index 88743d6..965c6558 100644
--- a/gcc/config/mn10300/mn10300.md
+++ b/gcc/config/mn10300/mn10300.md
@@ -491,222 +491,95 @@
 				(const_int 13) (const_int 24))
 		 ])]
 )
-
 \f
 ;; ----------------------------------------------------------------------
 ;; ADD INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
-(define_expand "addsi3"
-  [(parallel [(set (match_operand:SI          0 "register_operand")
-		   (plus:SI (match_operand:SI 1 "register_operand")
-			    (match_operand:SI 2 "nonmemory_operand")))
-	      (clobber (reg:CC CC_REG))
-	     ])
-  ]
+(define_insn "addsi3"
+  [(set (match_operand:SI          0 "register_operand"  "=r,!*y,!r")
+	(plus:SI (match_operand:SI 1 "register_operand"  "%0,  0, r")
+		 (match_operand:SI 2 "nonmemory_operand" "ri,  i, r")))
+   (clobber (reg:CC CC_REG))]
   ""
-  "")
-
-(define_insn "*am33_addsi3"
-  [(set (match_operand:SI          0 "register_operand" "=dx,a,x,a,dax,!*y,!dax")
-	(plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,dax")
-		 (match_operand:SI 2 "nonmemory_operand" "J,J,L,L,daxi,i,dax")))
-   (clobber (reg:CC CC_REG))
-  ]
-  "TARGET_AM33"
-  "*
-{
-  switch (which_alternative)
-    {
-    case 0:
-    case 1:
-      return \"inc %0\";
-    case 2:
-    case 3:
-      return \"inc4 %0\";
-    case 4:
-    case 5:
-      return \"add %2,%0\";
-    case 6:
-      {
-	enum reg_class src1_class, src2_class, dst_class;
-
-	src1_class = REGNO_REG_CLASS (true_regnum (operands[1]));
-	src2_class = REGNO_REG_CLASS (true_regnum (operands[2]));
-	dst_class = REGNO_REG_CLASS (true_regnum (operands[0]));
-
-	/* I'm not sure if this can happen or not.  Might as well be prepared
-	  and generate the best possible code if it does happen.  */
-	if (true_regnum (operands[0]) == true_regnum (operands[1]))
-	  return \"add %2,%0\";
-	if (true_regnum (operands[0]) == true_regnum (operands[2]))
-	  return \"add %1,%0\";
-
-	/* Catch cases where no extended register was used.  These should be
-	   handled just like the mn10300.  */
-	if (src1_class != EXTENDED_REGS
-	    && src2_class != EXTENDED_REGS
-	    && dst_class != EXTENDED_REGS)
-	  {
-	    /* We have to copy one of the sources into the destination, then
-	       add the other source to the destination.
-
-	       Carefully select which source to copy to the destination; a
-	       naive implementation will waste a byte when the source classes
-	       are different and the destination is an address register.
-	       Selecting the lowest cost register copy will optimize this
-	       sequence.  */
-	    if (REGNO_REG_CLASS (true_regnum (operands[1]))
-		== REGNO_REG_CLASS (true_regnum (operands[0])))
-	      return \"mov %1,%0\;add %2,%0\";
-	    return \"mov %2,%0\;add %1,%0\";
-	  }
-
-	/* At least one register is an extended register.  */
-
-	/* The three operand add instruction on the am33 is a win iff the
-	   output register is an extended register, or if both source
-	   registers are extended registers.  */
-	if (dst_class == EXTENDED_REGS
-	    || src1_class == src2_class)
-	  return \"add %2,%1,%0\";
-
-      /* It is better to copy one of the sources to the destination, then
-	 perform a 2 address add.  The destination in this case must be
-	 an address or data register and one of the sources must be an
-	 extended register and the remaining source must not be an extended
-	 register.
-
-	 The best code for this case is to copy the extended reg to the
-	 destination, then emit a two address add.  */
-      if (src1_class == EXTENDED_REGS)
-	return \"mov %1,%0\;add %2,%0\";
-      return \"mov %2,%0\;add %1,%0\";
-      }
-    default:
-      gcc_unreachable ();
-    }
-  }"
-  [(set_attr "timings" "11,11,11,11,11,11,22")]
+  { return mn10300_output_add (operands, false); }
+  [(set_attr "timings" "11,11,22")]
 )
 
-(define_insn "*mn10300_addsi3"
-  [(set (match_operand:SI          0 "register_operand" "=dx,a,a,dax,!*y,!dax")
-	(plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,dax")
-		 (match_operand:SI 2 "nonmemory_operand" "J,J,L,daxi,i,dax")))
-   (clobber (reg:CC CC_REG))
-  ]
-  ""
-  "*
-{
-  switch (which_alternative)
-    {
-    case 0:
-    case 1:
-      return \"inc %0\";
-    case 2:
-      return \"inc4 %0\";
-    case 3:
-    case 4:
-      return \"add %2,%0\";
-    case 5:
-      /* I'm not sure if this can happen or not.  Might as well be prepared
-	 and generate the best possible code if it does happen.  */
-      if (true_regnum (operands[0]) == true_regnum (operands[1]))
-	return \"add %2,%0\";
-      if (true_regnum (operands[0]) == true_regnum (operands[2]))
-	return \"add %1,%0\";
-
-      /* We have to copy one of the sources into the destination, then add
-	 the other source to the destination.
-
-	 Carefully select which source to copy to the destination; a naive
-	 implementation will waste a byte when the source classes are different
-	 and the destination is an address register.  Selecting the lowest
-	 cost register copy will optimize this sequence.  */
-      if (REGNO_REG_CLASS (true_regnum (operands[1]))
-	  == REGNO_REG_CLASS (true_regnum (operands[0])))
-	return \"mov %1,%0\;add %2,%0\";
-      return \"mov %2,%0\;add %1,%0\";
-    default:
-      gcc_unreachable ();
-    }
-}"
-  [(set_attr "timings" "11,11,11,11,11,22")]
+;; Note that ADD IMM,SP does not set the flags, so omit that here.
+(define_insn "*addsi3_flags"
+  [(set (match_operand:SI          0 "register_operand"  "=r,!r")
+  	(plus:SI (match_operand:SI 1 "register_operand"  "%0, r")
+		 (match_operand:SI 2 "nonmemory_operand" "ri, r")))
+   (set (reg CC_REG)
+   	(compare (plus:SI (match_dup 1) (match_dup 2))
+		 (const_int 0)))]
+  "reload_completed && mn10300_match_ccmode (insn, CCZNCmode)"
+  { return mn10300_output_add (operands, true); }
+  [(set_attr "timings" "11,22")]
 )
 
 ;; ----------------------------------------------------------------------
 ;; SUBTRACT INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
-(define_expand "subsi3"
-  [(parallel [(set (match_operand:SI           0 "register_operand")
-		   (minus:SI (match_operand:SI 1 "register_operand")
-			     (match_operand:SI 2 "nonmemory_operand")))
-	      (clobber (reg:CC CC_REG))
-	     ])
-  ]
+(define_insn "subsi3"
+  [(set (match_operand:SI           0 "register_operand"  "=r,r")
+	(minus:SI (match_operand:SI 1 "register_operand"  " 0,r")
+		  (match_operand:SI 2 "nonmemory_operand" "ri,r")))
+   (clobber (reg:CC CC_REG))]
   ""
-  "")
-
-(define_insn "*am33_subsi3"
-  [(set (match_operand:SI           0 "register_operand" "=dax,!dax")
-	(minus:SI (match_operand:SI 1 "register_operand" "0,dax")
-		  (match_operand:SI 2 "nonmemory_operand" "daxi,dax")))
-   (clobber (reg:CC CC_REG))
-  ]
-  "TARGET_AM33"
-  "*
-  {
-    if (true_regnum (operands[0]) == true_regnum (operands[1]))
-      return \"sub %2,%0\";
-    else
-      {
-        enum reg_class src1_class, src2_class, dst_class;
-
-        src1_class = REGNO_REG_CLASS (true_regnum (operands[1]));
-        src2_class = REGNO_REG_CLASS (true_regnum (operands[2]));
-        dst_class = REGNO_REG_CLASS (true_regnum (operands[0]));
-
-        /* If no extended registers are used, then the best way to handle
-	   this is to copy the first source operand into the destination
-	   and emit a two address subtraction.  */
-        if (src1_class != EXTENDED_REGS
-	    && src2_class != EXTENDED_REGS
-	    && dst_class != EXTENDED_REGS
-	    && true_regnum (operands[0]) != true_regnum (operands[2]))
-	  return \"mov %1,%0\;sub %2,%0\";
-        return \"sub %2,%1,%0\";
-      }
-  }"
-  [(set_attr "timings" "11,22")]
+  "@
+   sub %2,%0
+   sub %2,%1,%0"
+  [(set_attr "isa" "*,am33")
+   (set_attr "timings" "11,22")]
 )
 
-(define_insn "*mn10300_subsi3"
-  [(set (match_operand:SI           0 "register_operand" "=dax")
-	(minus:SI (match_operand:SI 1 "register_operand" "0")
-		  (match_operand:SI 2 "nonmemory_operand" "daxi")))
-   (clobber (reg:CC CC_REG))
-  ]
-  ""
-  "sub %2,%0"
-  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
-				       (const_int 11) (const_int 22)))]
+(define_insn "*subsi3_flags"
+  [(set (match_operand:SI           0 "register_operand"  "=r,r")
+	(minus:SI (match_operand:SI 1 "register_operand"  " 0,r")
+		  (match_operand:SI 2 "nonmemory_operand" "ri,r")))
+   (set (reg CC_REG)
+   	(compare (minus:SI (match_dup 1) (match_dup 2))
+		 (const_int 0)))]
+  "reload_completed && mn10300_match_ccmode (insn, CCZNCmode)"
+  "@
+   sub %2,%0
+   sub %2,%1,%0"
+  [(set_attr "isa" "*,am33")
+   (set_attr "timings" "11,22")]
 )
 
-(define_expand "negsi2"
-  [(set (match_operand:SI         0 "register_operand")
-        (neg:SI (match_operand:SI 1 "register_operand")))]
+(define_insn_and_split "negsi2"
+  [(set (match_operand:SI         0 "register_operand"  "=D,&r")
+	(neg:SI (match_operand:SI 1 "register_operand"  " 0, r")))
+   (clobber (reg:CC CC_REG))]
   ""
-  "
+  "#"
+  "&& reload_completed"
+  [(const_int 0)]
 {
-  rtx target = gen_reg_rtx (SImode);
-
-  emit_move_insn (target, const0_rtx);
-  emit_insn (gen_subsi3 (target, target, operands[1]));
-  emit_move_insn (operands[0], target);
+  /* Recall that twos-compliment is ones-compliment plus one.  When
+     allocated in DATA_REGS this is 2+1 bytes; otherwise (for am33)
+     this is 3+3 bytes.
+
+     For AM33, it would have been possible to load zero and use the
+     three-address subtract to have a total size of 3+4*N bytes for
+     multiple negations, plus increased throughput.  Not attempted here.  */
+     
+  if (true_regnum (operands[0]) == true_regnum (operands[1]))
+    {
+      emit_insn (gen_one_cmplsi2 (operands[0], operands[0]));
+      emit_insn (gen_addsi3 (operands[0], operands[0], const1_rtx));
+    }
+  else
+    {
+      emit_move_insn (operands[0], const0_rtx);
+      emit_insn (gen_subsi3 (operands[0], operands[0], operands[1]));
+    }
   DONE;
-}")
+})
 
 ;; ----------------------------------------------------------------------
 ;; MULTIPLY INSTRUCTIONS
@@ -896,221 +769,174 @@
 ;; AND INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
-(define_expand "andsi3"
-  [(parallel [(set (match_operand:SI         0 "register_operand")
-		   (and:SI (match_operand:SI 1 "register_operand")
-			   (match_operand:SI 2 "nonmemory_operand")))
-	      (clobber (reg:CC CC_REG))
-	     ])
-  ]
+(define_insn "andsi3"
+  [(set (match_operand:SI         0 "register_operand"  "=D,D,r")
+	(and:SI (match_operand:SI 1 "register_operand"  "%0,0,r")
+		(match_operand:SI 2 "nonmemory_operand" " i,D,r")))
+   (clobber (reg:CC CC_REG))]
   ""
-  "")
-
-(define_insn "*am33_andsi3"
-  [(set (match_operand:SI         0 "register_operand" "=dx,dx,!dax")
-	(and:SI (match_operand:SI 1 "register_operand" "%0,0,dax")
-		(match_operand:SI 2 "nonmemory_operand" "N,dxi,dax")))
-   (clobber (reg:CC CC_REG))
-  ]
-  "TARGET_AM33"
-  {
-    if (CONST_INT_P (operands[2]))
-      switch (INTVAL (operands[2]))
-        {
-        case 0xff:       return "extbu %0";
-        case 0xffff:     return "exthu %0";
-        case 0x7fffffff: return "add  %0, %0; lsr 1, %0";
-        case 0x3fffffff: return "asl2 %0; lsr 2, %0";
-        case 0x1fffffff: return "add  %0, %0; asl2 %0; lsr 3, %0";
-        case 0x0fffffff: return "asl2 %0; asl2 %0; lsr 4, %0";
-        case 0xfffffffe: return "lsr 1, %0; add  %0, %0";
-        case 0xfffffffc: return "lsr 2, %0; asl2 %0";
-        case 0xfffffff8: return "lsr 3, %0; add  %0, %0; asl2 %0";
-        case 0xfffffff0: return "lsr 4, %0; asl2 %0; asl2 %0";
-        }
-      
-    if (REG_P (operands[2]) && REG_P (operands[1])
-        && true_regnum (operands[0]) != true_regnum (operands[1])
-        && true_regnum (operands[0]) != true_regnum (operands[2])
-        && REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS
-        && REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS
-        && REGNO_REG_CLASS (true_regnum (operands[2])) == DATA_REGS)
-      return "mov %1, %0; and %2, %0";
-    if (REG_P (operands[2]) && REG_P (operands[1])
-        && true_regnum (operands[0]) != true_regnum (operands[1])
-        && true_regnum (operands[0]) != true_regnum (operands[2]))
-      return "and %1, %2, %0";
-    if (REG_P (operands[2]) && REG_P (operands[0])
-        && true_regnum (operands[2]) == true_regnum (operands[0]))
-      return "and %1, %0";
-
-    return "and %2, %0";
-  }
-  [(set_attr "timings" "33")]
+  "@
+   and %2,%0
+   and %2,%0
+   and %2,%1,%0"
+  [(set_attr "isa" "*,*,am33")
+   (set_attr "timings" "22,11,11")]
+)
+
+(define_insn "*andsi3_flags"
+  [(set (match_operand:SI         0 "register_operand"  "=D,D,r")
+	(and:SI (match_operand:SI 1 "register_operand"  "%0,0,r")
+		(match_operand:SI 2 "nonmemory_operand" " i,D,r")))
+   (set (reg CC_REG)
+   	(compare (and:SI (match_dup 1) (match_dup 2))
+		 (const_int 0)))]
+  "reload_completed && mn10300_match_ccmode (insn, CCZNmode)"
+  "@
+   and %2,%0
+   and %2,%0
+   and %2,%1,%0"
+  [(set_attr "isa" "*,*,am33")
+   (set_attr "timings" "22,11,11")]
 )
 
-(define_insn "*mn10300_andsi3"
-  [(set (match_operand:SI         0 "register_operand" "=dx,dx")
-	(and:SI (match_operand:SI 1 "register_operand" "%0,0")
-		(match_operand:SI 2 "nonmemory_operand" "N,dxi")))
-   (clobber (reg:CC CC_REG))
-  ]
+;; Make sure we generate extensions instead of ANDs.
+
+(define_split
+  [(parallel [(set (match_operand:SI 0 "register_operand" "")
+		   (and:SI (match_operand:SI 1 "register_operand" "")
+			   (const_int 255)))
+	      (clobber (reg:CC CC_REG))])]
   ""
-  {
-    if (CONST_INT_P (operands[2]))
-      switch (INTVAL (operands[2]))
-        {
-        case 0xff:       return "extbu %0";
-        case 0xffff:     return "exthu %0";
-        case 0x7fffffff: return "add  %0, %0; lsr 1, %0";
-        case 0x3fffffff: return "asl2 %0; lsr 2, %0";
-        case 0x1fffffff: return "add  %0, %0; asl2 %0; lsr 3, %0";
-        case 0x0fffffff: return "asl2 %0; asl2 %0; lsr 4, %0";
-        case 0xfffffffe: return "lsr 1, %0; add  %0, %0";
-        case 0xfffffffc: return "lsr 2, %0; asl2 %0";
-        case 0xfffffff8: return "lsr 3, %0; add  %0, %0; asl2 %0";
-        case 0xfffffff0: return "lsr 4, %0; asl2 %0; asl2 %0";
-	}
+  [(set (match_dup 0) (zero_extend:SI (match_dup 1)))]
+  { operands[1] = gen_lowpart (QImode, operands[1]); }
+)
 
-    return "and %2, %0";
-  }
-  [(set_attr "timings" "33")]
+(define_split
+  [(parallel [(set (match_operand:SI 0 "register_operand" "")
+		   (and:SI (match_operand:SI 1 "register_operand" "")
+			   (const_int 65535)))
+	      (clobber (reg:CC CC_REG))])]
+  ""
+  [(set (match_dup 0) (zero_extend:SI (match_dup 1)))]
+  { operands[1] = gen_lowpart (HImode, operands[1]); }
 )
 
+;; Split AND by an appropriate constant into two shifts.  Recall that 
+;; operations with a full 32-bit immediate require an extra cycle, so
+;; this is a size optimization with no speed penalty.  This only applies
+;; do DATA_REGS; the shift insns that AM33 adds are too large for a win.
+
+(define_split
+  [(parallel [(set (match_operand:SI 0 "register_operand" "")
+		   (and:SI (match_dup 0)
+			   (match_operand:SI 1 "const_int_operand" "")))
+	      (clobber (reg:CC CC_REG))])]
+  "reload_completed
+   && REGNO_DATA_P (true_regnum (operands[0]), 1)
+   && mn10300_split_and_operand_count (operands[1]) != 0"
+  [(const_int 0)]
+{
+  int count = mn10300_split_and_operand_count (operands[1]);
+  if (count > 0)
+    {
+      emit_insn (gen_lshrsi3 (operands[0], operands[0], GEN_INT (count)));
+      emit_insn (gen_ashlsi3 (operands[0], operands[0], GEN_INT (count)));
+    }
+  else
+    {
+      emit_insn (gen_ashlsi3 (operands[0], operands[0], GEN_INT (-count)));
+      emit_insn (gen_lshrsi3 (operands[0], operands[0], GEN_INT (-count)));
+    }
+  DONE;
+})
+
 ;; ----------------------------------------------------------------------
 ;; OR INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
-(define_expand "iorsi3"
-  [(parallel [(set (match_operand:SI         0 "register_operand")
-		   (ior:SI (match_operand:SI 1 "register_operand")
-			   (match_operand:SI 2 "nonmemory_operand")))
-	      (clobber (reg:CC CC_REG))
-	     ])
-  ]
-  ""
-  "")
-
-(define_insn "*am33_iorsi3"
-  [(set (match_operand:SI 0 "register_operand" "=dx,!dax")
-	(ior:SI (match_operand:SI 1 "register_operand" "%0,dax")
-		(match_operand:SI 2 "nonmemory_operand" "dxi,dax")))
-   (clobber (reg:CC CC_REG))
-  ]
-  "TARGET_AM33"
-  "*
-  {
-    if (REG_P (operands[2]) && REG_P (operands[1])
-        && true_regnum (operands[0]) != true_regnum (operands[1])
-        && true_regnum (operands[0]) != true_regnum (operands[2])
-        && REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS
-        && REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS
-        && REGNO_REG_CLASS (true_regnum (operands[2])) == DATA_REGS)
-      return \"mov %1,%0\;or %2,%0\";
-    if (REG_P (operands[2]) && REG_P (operands[1])
-        && true_regnum (operands[0]) != true_regnum (operands[1])
-        && true_regnum (operands[0]) != true_regnum (operands[2]))
-      return \"or %1,%2,%0\";
-    if (REG_P (operands[2]) && REG_P (operands[0])
-        && true_regnum (operands[2]) == true_regnum (operands[0]))
-      return \"or %1,%0\";
-    return \"or %2,%0\";
-  }"
-  [(set_attr "timings" "22")]
-)
-
-(define_insn "*mn10300_iorsi3"
-  [(set (match_operand:SI         0 "register_operand" "=dx")
-	(ior:SI (match_operand:SI 1 "register_operand" "%0")
-		(match_operand:SI 2 "nonmemory_operand" "dxi")))
-   (clobber (reg:CC CC_REG))
-  ]
+(define_insn "iorsi3"
+  [(set (match_operand:SI         0 "register_operand"  "=D,D,r")
+	(ior:SI (match_operand:SI 1 "register_operand"  "%0,0,r")
+		(match_operand:SI 2 "nonmemory_operand" " i,D,r")))
+   (clobber (reg:CC CC_REG))]
   ""
-  "or %2,%0"
-  [(set_attr "timings" "33")]
+  "@
+   or %2,%0
+   or %2,%0
+   or %2,%1,%0"
+  [(set_attr "isa" "*,*,am33")
+   (set_attr "timings" "22,11,11")]
+)
+
+(define_insn "*iorsi3_flags"
+  [(set (match_operand:SI         0 "register_operand"  "=D,D,r")
+	(ior:SI (match_operand:SI 1 "register_operand"  "%0,0,r")
+		(match_operand:SI 2 "nonmemory_operand" " i,D,r")))
+   (set (reg CC_REG)
+   	(compare (ior:SI (match_dup 1) (match_dup 2))
+		 (const_int 0)))]
+  "reload_completed && mn10300_match_ccmode (insn, CCZNmode)"
+  "@
+   or %2,%0
+   or %2,%0
+   or %2,%1,%0"
+  [(set_attr "isa" "*,*,am33")
+   (set_attr "timings" "22,11,11")]
 )
 
 ;; ----------------------------------------------------------------------
 ;; XOR INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
-(define_expand "xorsi3"
-  [(parallel [(set (match_operand:SI         0 "register_operand")
-		   (xor:SI (match_operand:SI 1 "register_operand")
-			   (match_operand:SI 2 "nonmemory_operand")))
-	      (clobber (reg:CC CC_REG))
-	     ])
-  ]
-  ""
-  "")
-
-(define_insn "*am33_xorsi3"
-  [(set (match_operand:SI         0 "register_operand" "=dx,!dax")
-	(xor:SI (match_operand:SI 1 "register_operand" "%0,dax")
-		(match_operand:SI 2 "nonmemory_operand" "dxi,dax")))
-   (clobber (reg:CC CC_REG))
-  ]
-  "TARGET_AM33"
-  "*
-  {
-    if (REG_P (operands[2]) && REG_P (operands[1])
-        && true_regnum (operands[0]) != true_regnum (operands[1])
-        && true_regnum (operands[0]) != true_regnum (operands[2])
-        && REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS
-        && REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS
-        && REGNO_REG_CLASS (true_regnum (operands[2])) == DATA_REGS)
-      return \"mov %1,%0\;xor %2,%0\";
-    if (REG_P (operands[2]) && REG_P (operands[1])
-        && true_regnum (operands[0]) != true_regnum (operands[1])
-        && true_regnum (operands[0]) != true_regnum (operands[2]))
-      return \"xor %1,%2,%0\";
-    if (REG_P (operands[2]) && REG_P (operands[0])
-        && true_regnum (operands[2]) == true_regnum (operands[0]))
-      return \"xor %1,%0\";
-    return \"xor %2,%0\";
-  }"
-  [(set_attr "timings" "22")]
-)
-
-(define_insn "*mn10300_xorsi3"
-  [(set (match_operand:SI         0 "register_operand" "=dx")
-	(xor:SI (match_operand:SI 1 "register_operand" "%0")
-		(match_operand:SI 2 "nonmemory_operand" "dxi")))
-   (clobber (reg:CC CC_REG))
-  ]
+(define_insn "xorsi3"
+  [(set (match_operand:SI         0 "register_operand"  "=D,D,r")
+	(xor:SI (match_operand:SI 1 "register_operand"  "%0,0,r")
+		(match_operand:SI 2 "nonmemory_operand" " i,D,r")))
+   (clobber (reg:CC CC_REG))]
   ""
-  "xor %2,%0"
-  [(set_attr "timings" "11")]
+  "@
+   xor %2,%0
+   xor %2,%0
+   xor %2,%1,%0"
+  [(set_attr "isa" "*,*,am33")
+   (set_attr "timings" "22,11,11")]
+)
+
+(define_insn "*xorsi3_flags"
+  [(set (match_operand:SI         0 "register_operand"  "=D,D,r")
+	(xor:SI (match_operand:SI 1 "register_operand"  "%0,0,r")
+		(match_operand:SI 2 "nonmemory_operand" " i,D,r")))
+   (set (reg CC_REG)
+   	(compare (xor:SI (match_dup 1) (match_dup 2))
+		 (const_int 0)))]
+  "reload_completed && mn10300_match_ccmode (insn, CCZNmode)"
+  "@
+   xor %2,%0
+   xor %2,%0
+   xor %2,%1,%0"
+  [(set_attr "isa" "*,*,am33")
+   (set_attr "timings" "22,11,11")]
 )
 
 ;; ----------------------------------------------------------------------
 ;; NOT INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
-(define_expand "one_cmplsi2"
-  [(parallel [(set (match_operand:SI         0 "register_operand")
-		   (not:SI (match_operand:SI 1 "register_operand")))
-	      (clobber (reg:CC CC_REG))
-	     ])
-  ]
+(define_insn "one_cmplsi2"
+  [(set (match_operand:SI         0 "register_operand" "=D")
+	(not:SI (match_operand:SI 1 "register_operand" " 0")))
+   (clobber (reg:CC CC_REG))]
   ""
-  "")
-
-(define_insn "*am33_cmplsi2"
-  [(set (match_operand:SI         0 "register_operand" "=dx,!dax")
-	(not:SI (match_operand:SI 1 "register_operand" "0,0")))
-   (clobber (reg:CC CC_REG))
-  ]
-  "TARGET_AM33"
   "not %0"
 )
 
-(define_insn "*mn10300_cmplsi2"
-  [(set (match_operand:SI         0 "register_operand" "=dx")
-	(not:SI (match_operand:SI 1 "register_operand" "0")))
-   (clobber (reg:CC CC_REG))
-  ]
-  ""
+(define_insn "*one_cmplsi2_flags"
+  [(set (match_operand:SI         0 "register_operand" "=D")
+	(not:SI (match_operand:SI 1 "register_operand" " 0")))
+   (set (reg CC_REG)
+   	(compare (not:SI (match_dup 1))
+		 (const_int 0)))]
+  "reload_completed && mn10300_match_ccmode (insn, CCZNmode)"
   "not %0"
 )
 \f
@@ -1126,140 +952,133 @@
 	      (match_operator                    0 "ordered_comparison_operator"
 			      [(match_operand:SI 1 "register_operand")
 			       (match_operand:SI 2 "nonmemory_operand")])
-              (label_ref (match_operand          3 ""))
+              (label_ref (match_operand 3 ""))
               (pc)))]
   ""
   ""
 )
 
-(define_insn_and_split "*cbranchsi4_post_reload"
+(define_insn_and_split "*cbranchsi4_cmp"
   [(set (pc)
 	(if_then_else (match_operator           3 "ordered_comparison_operator"
-                       [(match_operand:SI       0 "register_operand"  "dax")
-		        (match_operand:SI       1 "nonmemory_operand" "daxi")])
-		      (label_ref (match_operand 2 "" ""))
-		      (pc)))
-   ]
+                       [(match_operand:SI       0 "register_operand"  "r")
+		        (match_operand:SI       1 "nonmemory_operand" "ri")])
+		      (match_operand            2 "label_ref_operand" "")
+		      (pc)))]
   ""
   "#"
   "reload_completed"
   [(const_int 0)]
-  "
-  /* We construct the split by hand as otherwise the JUMP_LABEL
-     attribute is not set correctly on the jump insn.  */
-  emit_insn (gen_cmpsi (operands[0], operands[1]));
-  
-  emit_jump_insn (gen_integer_conditional_branch
-                      (gen_rtx_fmt_ee (GET_CODE (operands[3]),
-				       CCmode,
-		 		       gen_rtx_REG (CCmode, CC_REG),
-				  	            const0_rtx),
-				       operands[2]));
-  "
-)
+{
+  mn10300_split_cbranch (CCmode, operands[3], operands[2]);
+  DONE;
+})
 
-;; Ordinarily, the cmp instruction will set the Z bit of cc0 to 1 if
-;; its operands hold equal values, but the operands of a cmp
-;; instruction must be distinct registers.  In the case where we'd
-;; like to compare a register to itself, we can achieve this effect
-;; with a btst 0,d0 instead.  (This will not alter the contents of d0
-;; but will have the proper effect on cc0.  Using d0 is arbitrary; any
-;; data register would work.)
-
-;; Even though the first alternative would be preferable if it can
-;; possibly match, reload must not be given the opportunity to attempt
-;; to use it.  It assumes that such matches can only occur when one of
-;; the operands is used for input and the other for output.  Since
-;; this is not the case, it abort()s.  Indeed, such a reload cannot be
-;; possibly satisfied, so just mark the alternative with a `!', so
-;; that it is not considered by reload.
-
-(define_insn "cmpsi"
-  [(set (reg:CC CC_REG)
-	(compare (match_operand:SI 0 "register_operand" "!*d*a*x,dax,dax")
-		 (match_operand:SI 1 "nonmemory_operand" "*0,I,daxi")))]
-  ""
-  {
-    if (which_alternative == 0)
-      return \"btst 0,d0\";
-    if (which_alternative == 1)
-      return mn10300_output_cmp (operands[0], insn);
-    return \"cmp %1,%0\";
-  }
+(define_insn "*cmpsi"
+  [(set (reg CC_REG)
+	(compare (match_operand:SI 0 "register_operand"  "r")
+		 (match_operand:SI 1 "nonmemory_operand" "ri")))]
+  "reload_completed"
+{
+  /* The operands of CMP must be distinct registers.  In the case where
+     we've failed to optimize the comparison of a register to itself, we
+     must use another method to set the Z flag.  We can achieve this 
+     effect with a BTST 0,D0.  This will not alter the contents of D0;
+     the use of d0 is arbitrary; any data register would work.  */
+  if (rtx_equal_p (operands[0], operands[1]))
+    return "btst 0,d0";
+  else
+    return "cmp %1,%0";
+}
   [(set_attr_alternative "timings"
-			 [(const_int 11)
-			  (if_then_else (eq_attr "cpu" "am34")
-					(const_int 11) (const_int 22))
-			  (const_int 22)
-			 ])
-  ]
+     [(if_then_else (eq_attr "cpu" "am34") (const_int 11) (const_int 22))])]
 )
 
-(define_insn "integer_conditional_branch"
+(define_insn "*integer_conditional_branch"
   [(set (pc)
 	(if_then_else (match_operator 0 "comparison_operator"
-				      [(reg:CC CC_REG) (const_int 0)])
+			[(match_operand 2 "int_mode_flags" "")
+			 (const_int 0)])
 		      (label_ref (match_operand 1 "" ""))
 		      (pc)))]
-  ""
+  "reload_completed"
   "b%b0 %1"
 )
 
+(define_insn_and_split "*cbranchsi4_btst"
+  [(set (pc)
+	(if_then_else
+	  (match_operator 3 "CCZN_comparison_operator"
+	    [(and:SI (match_operand:SI 0 "register_operand" "D")
+		     (match_operand:SI 1 "immediate_operand" "i"))
+	     (const_int 0)])
+	  (match_operand 2 "label_ref_operand" "")
+	  (pc)))]
+  ""
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+{
+  mn10300_split_cbranch (CCZNmode, operands[3], operands[2]);
+  DONE;
+})
+
+(define_insn "*btstsi"
+  [(set (reg:CCZN CC_REG)
+	(compare:CCZN
+	  (and:SI (match_operand:SI 0 "register_operand" "D")
+		  (match_operand:SI 1 "immediate_operand" "i"))
+	  (const_int 0)))]
+  "reload_completed"
+  "btst %1,%0"
+)
+
 (define_expand "cbranchsf4"
   [(set (pc)
       (if_then_else
             (match_operator                    0 "ordered_comparison_operator"
 			    [(match_operand:SF 1 "register_operand")
 			     (match_operand:SF 2 "nonmemory_operand")])
-	    (label_ref (match_operand          3 ""))
+	    (label_ref (match_operand 3 ""))
 	    (pc)))]
   "TARGET_AM33_2"
   ""
 )
 
-(define_insn_and_split "*cbranchsf4_post_reload"
+(define_insn_and_split "*cbranchsf4_cmp"
   [(set (pc)
 	(if_then_else (match_operator            3 "ordered_comparison_operator"
 			[(match_operand:SF       0 "register_operand"  "f")
 			 (match_operand:SF       1 "nonmemory_operand" "fF")])
-		      (label_ref (match_operand  2 "" ""))
+		      (match_operand             2 "label_ref_operand" "")
 		      (pc)))
    ]
   "TARGET_AM33_2"
   "#"
   "&& reload_completed"
   [(const_int 0)]
-  "
-  /* We construct the split by hand as otherwise the JUMP_LABEL
-     attribute is not set correctly on the jump insn.  */
-  emit_insn (gen_am33_cmpsf (operands[0], operands[1]));
-  
-  emit_jump_insn (gen_float_conditional_branch
-                     (gen_rtx_fmt_ee (GET_CODE (operands[3]),
-				      CC_FLOATmode,
- 		 	       	      gen_rtx_REG (CC_FLOATmode, CC_REG),
-				      const0_rtx),
-				      operands[2]));
-  "
-)
+{
+  mn10300_split_cbranch (CC_FLOATmode, operands[3], operands[2]);
+  DONE;
+})
 
-(define_insn "am33_cmpsf"
+(define_insn "*am33_cmpsf"
   [(set (reg:CC_FLOAT CC_REG)
 	(compare:CC_FLOAT (match_operand:SF 0 "register_operand"  "f")
 			  (match_operand:SF 1 "nonmemory_operand" "fF")))]
-  "TARGET_AM33_2"
+  "TARGET_AM33_2 && reload_completed"
   "fcmp %1, %0"
   [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
 				       (const_int 17) (const_int 25)))]
 )
 
-(define_insn "float_conditional_branch"
+(define_insn "*float_conditional_branch"
   [(set (pc)
 	(if_then_else (match_operator 0 "comparison_operator"
 				      [(reg:CC_FLOAT CC_REG) (const_int 0)])
 		      (label_ref (match_operand 1 "" ""))
 		      (pc)))]
-  "TARGET_AM33_2"
+  "TARGET_AM33_2 && reload_completed"
   "fb%b0 %1"
   [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
 				       (const_int 44) (const_int 33)))]
@@ -1301,7 +1120,6 @@
    (match_operand:SI 2 "immediate_operand")
    (match_operand 3 "" "") (match_operand 4 "")]
   ""
-  "
 {
   rtx table = gen_reg_rtx (SImode);
   rtx index = gen_reg_rtx (SImode);
@@ -1321,7 +1139,7 @@
 
   emit_jump_insn (gen_tablejump (addr, operands[3]));
   DONE;
-}")
+})
 
 (define_insn "tablejump"
   [(set (pc) (match_operand:SI 0 "register_operand" "a"))
@@ -1431,7 +1249,6 @@
               (match_operand 1 "")
               (match_operand 2 "")])]
   ""
-  "
 {
   int i;
 
@@ -1443,7 +1260,7 @@
       emit_move_insn (SET_DEST (set), SET_SRC (set));
     }
   DONE;
-}")
+})
 
 (define_insn "nop"
   [(const_int 0)]
@@ -1455,328 +1272,109 @@
 ;; EXTEND INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
-(define_expand "zero_extendqisi2"
-  [(set (match_operand:SI 0 "register_operand")
+(define_insn "zero_extendqisi2"
+  [(set (match_operand:SI 0 "register_operand"      "=D,D,r")
 	(zero_extend:SI
-	 (match_operand:QI 1 "nonimmediate_operand")))]
+	 (match_operand:QI 1 "nonimmediate_operand" " 0,m,r")))]
   ""
-  "")
-
-(define_insn "*zero_extendqisi2_am33"
-  [(set (match_operand:SI 0 "register_operand" "=dx,dx,dx,!dax,!dax,!dax")
-	(zero_extend:SI
-	 (match_operand:QI 1 "nonimmediate_operand" "0,dax,m,0,dax,m")))]
-  "TARGET_AM33"
   "@
-  extbu %0
-  mov %1,%0\;extbu %0
-  movbu %1,%0
-  extbu %0
-  mov %1,%0\;extbu %0
-  movbu %1,%0"
-  [(set_attr_alternative "timings"
-			 [(const_int 11)
-			  (const_int 22)
-			  (if_then_else (eq_attr "cpu" "am34")
-					(const_int 13) (const_int 24))
-			  (const_int 11)
-			  (const_int 22)
-			  (if_then_else (eq_attr "cpu" "am34")
-					(const_int 13) (const_int 24))
-			 ])
-  ]
-)
-
-(define_insn "*zero_extendqisi2_mn10300"
-  [(set (match_operand:SI 0 "register_operand" "=dx,dx,dx")
-	(zero_extend:SI
-	 (match_operand:QI 1 "nonimmediate_operand" "0,d,m")))]
-  ""
-  "@
-  extbu %0
-  mov %1,%0\;extbu %0
-  movbu %1,%0"
-  [(set_attr_alternative "timings"
-			 [(const_int 11)
-			  (const_int 22)
-			  (if_then_else (eq_attr "cpu" "am34")
-					(const_int 13) (const_int 24))
-			 ])
-  ]
-)
-
-(define_expand "zero_extendhisi2"
-  [(set (match_operand:SI 0 "register_operand")
-	(zero_extend:SI
-	 (match_operand:HI 1 "nonimmediate_operand")))]
-  ""
-  "")
-
-(define_insn "*zero_extendhisi2_am33"
-  [(set (match_operand:SI 0 "register_operand" "=dx,dx,dx,!dax,!dax,!dax")
-	(zero_extend:SI
-	 (match_operand:HI 1 "nonimmediate_operand" "0,dax,m,0,dax,m")))]
-  "TARGET_AM33"
-  "@
-  exthu %0
-  mov %1,%0\;exthu %0
-  movhu %1,%0
-  exthu %0
-  mov %1,%0\;exthu %0
-  movhu %1,%0"
-  [(set_attr_alternative "timings"
-			 [(const_int 11)
-			  (const_int 22)
-			  (if_then_else (eq_attr "cpu" "am34")
-					(const_int 13) (const_int 24))
-			  (const_int 11)
-			  (const_int 22)
-			  (if_then_else (eq_attr "cpu" "am34")
-					(const_int 13) (const_int 24))
-			 ])
-  ]
+   extbu %0
+   movbu %1,%0
+   extbu %1,%0"
+  [(set_attr "isa" "*,*,am33")
+   (set_attr_alternative "timings"
+		 [(const_int 11)
+		  (if_then_else (eq_attr "cpu" "am34")
+				(const_int 13) (const_int 24))
+		  (const_int 11)
+		 ])]
 )
 
-(define_insn "*zero_extendhisi2_mn10300"
-  [(set (match_operand:SI 0 "register_operand" "=dx,dx,dx")
+(define_insn "zero_extendhisi2"
+  [(set (match_operand:SI 0 "register_operand"      "=D,D,r")
 	(zero_extend:SI
-	 (match_operand:HI 1 "nonimmediate_operand" "0,dx,m")))]
+	 (match_operand:HI 1 "nonimmediate_operand" " 0,m,r")))]
   ""
   "@
-  exthu %0
-  mov %1,%0\;exthu %0
-  movhu %1,%0"
-  [(set_attr_alternative "timings"
-			 [(const_int 11)
-			  (const_int 22)
-			  (if_then_else (eq_attr "cpu" "am34")
-					(const_int 13) (const_int 24))
-			 ])
-  ]
-)
-
-;;- sign extension instructions
-
-(define_expand "extendqisi2"
-  [(set (match_operand:SI 0 "register_operand")
-	(sign_extend:SI
-	 (match_operand:QI 1 "register_operand")))]
-  ""
-  "")
-
-(define_insn "*extendqisi2_am33"
-  [(set (match_operand:SI 0 "register_operand" "=dx,dx,!dax,!dax")
-	(sign_extend:SI
-	 (match_operand:QI 1 "register_operand" "0,dx,0,dax")))]
-  "TARGET_AM33"
-  "@
-  extb %0
-  mov %1,%0\;extb %0
-  extb %0
-  mov %1,%0\;extb %0"
-  [(set_attr "timings" "11,22,11,22")]
-)
-
-(define_insn "*extendqisi2_mn10300"
-  [(set (match_operand:SI 0 "register_operand" "=dx,dx")
-	(sign_extend:SI
-	 (match_operand:QI 1 "register_operand" "0,dx")))]
-  ""
-  "@
-  extb %0
-  mov %1,%0\;extb %0"
-  [(set_attr "timings" "11,22")]
+   exthu %0
+   movhu %1,%0
+   exthu %1,%0"
+  [(set_attr "isa" "*,*,am33")
+   (set_attr_alternative "timings"
+		 [(const_int 11)
+		  (if_then_else (eq_attr "cpu" "am34")
+				(const_int 13) (const_int 24))
+		  (const_int 11)])]
 )
 
-(define_expand "extendhisi2"
-  [(set (match_operand:SI 0 "register_operand")
+(define_insn "extendqisi2"
+  [(set (match_operand:SI 0 "register_operand" "=D,r")
 	(sign_extend:SI
-	 (match_operand:HI 1 "register_operand")))]
+	 (match_operand:QI 1 "register_operand" "0,r")))]
   ""
-  "")
-
-(define_insn "*extendhisi2_am33"
-  [(set (match_operand:SI 0 "register_operand" "=dx,dx,!dax,!dax")
-	(sign_extend:SI
-	 (match_operand:HI 1 "register_operand" "0,dax,0,dax")))]
-  "TARGET_AM33"
   "@
-  exth %0
-  mov %1,%0\;exth %0
-  exth %0
-  mov %1,%0\;exth %0"
-  [(set_attr "timings" "11,22,11,22")]
+   extb %0
+   extb %1,%0"
+  [(set_attr "isa" "*,am33")]
 )
 
-(define_insn "*extendhisi2_mn10300"
-  [(set (match_operand:SI 0 "register_operand" "=dx,dx")
+(define_insn "extendhisi2"
+  [(set (match_operand:SI 0 "register_operand" "=D,r")
 	(sign_extend:SI
-	 (match_operand:HI 1 "register_operand" "0,dx")))]
+	 (match_operand:HI 1 "register_operand" "0,r")))]
   ""
   "@
-  exth %0
-  mov %1,%0\;exth %0"
-  [(set_attr "timings" "11,22")]
+   exth %0
+   exth %1,%0"
+  [(set_attr "isa" "*,am33")]
 )
 \f
 ;; ----------------------------------------------------------------------
 ;; SHIFTS
 ;; ----------------------------------------------------------------------
 
-(define_expand "ashlsi3"
-  [(parallel [(set (match_operand:SI 0 "register_operand")
-		   (ashift:SI
-		    (match_operand:SI 1 "register_operand")
-		    (match_operand:QI 2 "nonmemory_operand")))
-	      (clobber (reg:CC CC_REG))
-	     ])
-  ]
-  ""
-  "")
-
-(define_insn "*am33_ashlsi3"
-  [(set (match_operand:SI 0 "register_operand" "=dax,dx,!dax")
+(define_insn "ashlsi3"
+  [(set (match_operand:SI  0 "register_operand"  "=r,D,d,d, D,r")
 	(ashift:SI
-	 (match_operand:SI 1 "register_operand" "0,0,dax")
-	 (match_operand:QI 2 "nonmemory_operand" "J,dxi,dax")))
-   (clobber (reg:CC CC_REG))
-  ]
-  "TARGET_AM33"
-  "*
-  {
-    if (CONST_INT_P (operands[2]) && INTVAL (operands[2]) == 1)
-      return \"add %0,%0\";
-
-    if (CONST_INT_P (operands[2]) && INTVAL (operands[2]) == 2)
-      return \"asl2 %0\";
-
-    if (CONST_INT_P (operands[2]) && INTVAL (operands[2]) == 3
-        && REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS)
-      return \"asl2 %0\;add %0,%0\";
-
-    if (CONST_INT_P (operands[2]) && INTVAL (operands[2]) == 4
-        && REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS)
-      return \"asl2 %0\;asl2 %0\";
-
-    if (true_regnum (operands[1]) == true_regnum (operands[0]))
-      return \"asl %S2,%0\";
-
-    if (REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS
-        && REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS
-        && true_regnum (operands[0]) != true_regnum (operands[2]))
-      return \"mov %1,%0\;asl %S2,%0\";
-    return \"asl %2,%1,%0\";
-  }"
-  [(set_attr "timings" "22")]
-)
-
-(define_insn "*mn10300_ashlsi3"
-  [(set (match_operand:SI 0 "register_operand" "=dax,dx,dx,dx,dx")
-	(ashift:SI
-	 (match_operand:SI 1 "register_operand" "0,0,0,0,0")
-	 (match_operand:QI 2 "nonmemory_operand" "J,K,M,L,dxi")))
-   (clobber (reg:CC CC_REG))
-  ]
+	  (match_operand:SI 1 "register_operand"  " 0,0,0,0, 0,r")
+	  (match_operand:QI 2 "nonmemory_operand" " J,K,M,L,Di,r")))
+   (clobber (reg:CC CC_REG))]
   ""
   "@
-  add %0,%0
-  asl2 %0
-  asl2 %0\;add %0,%0
-  asl2 %0\;asl2 %0
-  asl %S2,%0"
-  [(set_attr "timings" "11,11,22,22,11")]
-)
-
-(define_expand "lshrsi3"
-  [(parallel [(set (match_operand:SI 0 "register_operand")
-		   (lshiftrt:SI
-		    (match_operand:SI 1 "register_operand")
-		    (match_operand:QI 2 "nonmemory_operand")))
-	      (clobber (reg:CC CC_REG))
-	     ])
-  ]
-  ""
-  "")
-
-(define_insn "*am33_lshrsi3"
-  [(set (match_operand:SI 0 "register_operand" "=dx,!dax")
+   add %0,%0
+   asl2 %0
+   asl2 %0\;add %0,%0
+   asl2 %0\;asl2 %0
+   asl %S2,%0
+   asl %2,%1,%0"
+  [(set_attr "isa" "*,*,*,*,*,am33")
+   (set_attr "timings" "11,11,22,22,11,11")]
+)
+
+(define_insn "lshrsi3"
+  [(set (match_operand:SI  0 "register_operand"  "=D,r")
 	(lshiftrt:SI
-	 (match_operand:SI 1 "register_operand" "0,dax")
-	 (match_operand:QI 2 "nonmemory_operand" "dxi,dax")))
-   (clobber (reg:CC CC_REG))
-  ]
-  "TARGET_AM33"
-  "*
-  {
-    if (true_regnum (operands[1]) == true_regnum (operands[0]))
-      return \"lsr %S2,%0\";
-
-    if (REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS
-        && REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS
-        && true_regnum (operands[0]) != true_regnum (operands[2]))
-      return \"mov %1,%0\;lsr %S2,%0\";
-    return \"lsr %2,%1,%0\";
-  }"
-  [(set_attr "timings" "22")]
-)
-
-(define_insn "*mn10300_lshrsi3"
-  [(set (match_operand:SI 0 "register_operand" "=dx")
-	(lshiftrt:SI
-	 (match_operand:SI 1 "register_operand" "0")
-	 (match_operand:QI 2 "nonmemory_operand" "dxi")))
-   (clobber (reg:CC CC_REG))
-  ]
-  ""
-  "lsr %S2,%0"
-  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
-				       (const_int 11) (const_int 22)))]
-)
-
-(define_expand "ashrsi3"
-  [(parallel [(set (match_operand:SI 0 "register_operand")
-		   (ashiftrt:SI
-		    (match_operand:SI 1 "register_operand")
-		    (match_operand:QI 2 "nonmemory_operand")))
-	      (clobber (reg:CC CC_REG))
-	     ])
-  ]
+	  (match_operand:SI 1 "register_operand"  " 0,r")
+	  (match_operand:QI 2 "nonmemory_operand" "Di,r")))
+   (clobber (reg:CC CC_REG))]
   ""
-  "")
-
-(define_insn "*am33_ashrisi3"
-  [(set (match_operand:SI 0 "register_operand" "=dx,!dax")
-	(ashiftrt:SI
-	 (match_operand:SI 1 "register_operand" "0,dax")
-	 (match_operand:QI 2 "nonmemory_operand" "dxi,dax")))
-   (clobber (reg:CC CC_REG))
-  ]
-  "TARGET_AM33"
-  "*
-  {
-    if (true_regnum (operands[1]) == true_regnum (operands[0]))
-      return \"asr %S2,%0\";
-
-    if (REGNO_REG_CLASS (true_regnum (operands[0])) == DATA_REGS
-        && REGNO_REG_CLASS (true_regnum (operands[1])) == DATA_REGS
-        && true_regnum (operands[0]) != true_regnum (operands[2]))
-      return \"mov %1,%0\;asr %S2,%0\";
-    return \"asr %2,%1,%0\";
-  }"
-  [(set_attr "timings" "22")]
+  "@
+   lsr %S2,%0
+   lsr %2,%1,%0"
+  [(set_attr "isa" "*,am33")]
 )
 
-(define_insn "*mn10300_ashrsi3"
-  [(set (match_operand:SI 0 "register_operand" "=dx")
+(define_insn "ashrsi3"
+  [(set (match_operand:SI  0 "register_operand"  "=D,r")
 	(ashiftrt:SI
-	 (match_operand:SI 1 "register_operand" "0")
-	 (match_operand:QI 2 "nonmemory_operand" "dxi")))
-   (clobber (reg:CC CC_REG))
-  ]
+	  (match_operand:SI 1 "register_operand"  " 0,r")
+	  (match_operand:QI 2 "nonmemory_operand" "Di,r")))
+   (clobber (reg:CC CC_REG))]
   ""
-  "asr %S2,%0"
-  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
-				       (const_int 11) (const_int 22)))]
+  "@
+   asr %S2,%0
+   asr %2,%1,%0"
+  [(set_attr "isa" "*,am33")]
 )
 
 ;; ----------------------------------------------------------------------
@@ -2031,28 +1629,6 @@
   [(set_attr "timings" "66")]
 )
 
-;; Try to combine consecutive updates of the stack pointer (or any
-;; other register for that matter).
-(define_peephole
-  [(parallel [(set (match_operand:SI 0 "register_operand" "=dxay")
-		   (plus:SI (match_dup 0)
-			    (match_operand 1 "const_int_operand" "")))
-	      (clobber (reg:CC CC_REG))
-	     ])
-   (parallel [(set (match_dup 0)
-		   (plus:SI (match_dup 0)
-			    (match_operand 2 "const_int_operand" "")))
-	      (clobber (reg:CC CC_REG))
-	     ])
-  ]
-  ""
-  "*
-{
-  operands[1] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[1]));
-  return \"add %1,%0\";
-}"
-)
-
 (define_expand "int_label"
   [(unspec [(match_operand:SI 0 "" "")] UNSPEC_INT_LABEL)]
   "" "")
diff --git a/gcc/config/mn10300/predicates.md b/gcc/config/mn10300/predicates.md
index df1b1f4..4badebb 100644
--- a/gcc/config/mn10300/predicates.md
+++ b/gcc/config/mn10300/predicates.md
@@ -42,3 +42,19 @@
   return XEXP (op, 0) == stack_pointer_rtx
       || XEXP (op, 1) == stack_pointer_rtx;
 })
+
+(define_predicate "label_ref_operand"
+  (match_code "label_ref"))
+
+(define_special_predicate "int_mode_flags"
+  (match_code "reg")
+{
+  if (REGNO (op) != CC_REG)
+    return false;
+  if (GET_MODE (op) == CC_FLOATmode)
+    return false;
+  return GET_MODE_CLASS (GET_MODE (op)) == MODE_CC;
+})
+
+(define_predicate "CCZN_comparison_operator"
+  (match_code "eq,ne,lt,ge"))
-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 90+ messages in thread

* [PATCH 08/28] mn10300: Define the A and D constraints.
  2011-01-10 20:33 [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Richard Henderson
                   ` (20 preceding siblings ...)
  2011-01-10 20:34 ` [PATCH 03/28] mn10300: delete ASM_PN_FORMAT Richard Henderson
@ 2011-01-10 20:34 ` Richard Henderson
  2011-01-11 14:56   ` Jeff Law
  2011-01-10 20:34 ` [PATCH 26/28] mn10300: Auto-clobber the flags in asms Richard Henderson
                   ` (7 subsequent siblings)
  29 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-10 20:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: nickc, law, Richard Henderson

From: Richard Henderson <rth@twiddle.net>

This will allow combining am33 and mn103 alternatives
without having to resort to the enabled attribute.

The existing 'A' constraint renamed to 'c'.  Thankfully
this existing accumulator constraint doesn't appear in
either newlib or eglibc sources.
---
 gcc/config/mn10300/constraints.md |   11 ++++++++++-
 gcc/config/mn10300/mn10300.md     |    8 ++++----
 2 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/gcc/config/mn10300/constraints.md b/gcc/config/mn10300/constraints.md
index 509970c..c9863fc 100644
--- a/gcc/config/mn10300/constraints.md
+++ b/gcc/config/mn10300/constraints.md
@@ -23,6 +23,15 @@
 (define_register_constraint "a" "ADDRESS_REGS"
   "An address register.")
 
+;; This can be used for QI/HImode memory operations, and most arithmetic.
+;; AM33 supports these on all registers, where MN103 needs DATA_REGS.
+(define_register_constraint "D" "TARGET_AM33 ? GENERAL_REGS : DATA_REGS"
+  "A general register for AM33, and a data register otherwise.")
+
+;; Similarly for ADDRESS_REGS vs GENERAL_REGS.
+(define_register_constraint "A" "TARGET_AM33 ? GENERAL_REGS : ADDRESS_REGS"
+  "A general register for AM33, and an address register otherwise.")
+
 (define_register_constraint "y" "SP_REGS"
   "An SP register (if available).")
 
@@ -32,7 +41,7 @@
 (define_register_constraint "f" "TARGET_AM33_2 ? FP_REGS : NO_REGS"
   "A floating point register.")
 
-(define_register_constraint "A" "TARGET_AM33_2 ? FP_ACC_REGS : NO_REGS"
+(define_register_constraint "c" "TARGET_AM33_2 ? FP_ACC_REGS : NO_REGS"
   "A floating point accumulator register.")
 
 (define_memory_constraint "Q"
diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md
index bfa453f..1773a03 100644
--- a/gcc/config/mn10300/mn10300.md
+++ b/gcc/config/mn10300/mn10300.md
@@ -2717,7 +2717,7 @@
 )
 
 (define_insn "fmasf4"
-  [(set (match_operand:SF         0 "register_operand" "=A")
+  [(set (match_operand:SF         0 "register_operand" "=c")
 	(fma:SF (match_operand:SF 1 "register_operand" "f")
 		(match_operand:SF 2 "register_operand" "f")
 		(match_operand:SF 3 "register_operand" "f")))
@@ -2730,7 +2730,7 @@
 )
 
 (define_insn "fmssf4"
-  [(set (match_operand:SF                 0 "register_operand" "=A")
+  [(set (match_operand:SF                 0 "register_operand" "=c")
 	(fma:SF (match_operand:SF         1 "register_operand" "f")
 		(match_operand:SF         2 "register_operand" "f")
 		(neg:SF (match_operand:SF 3 "register_operand" "f"))))
@@ -2743,7 +2743,7 @@
 )
 
 (define_insn "fnmasf4"
-  [(set (match_operand:SF                 0 "register_operand" "=A")
+  [(set (match_operand:SF                 0 "register_operand" "=c")
 	(fma:SF (neg:SF (match_operand:SF 1 "register_operand" "f"))
 		(match_operand:SF         2 "register_operand" "f")
 		(match_operand:SF         3 "register_operand" "f")))
@@ -2756,7 +2756,7 @@
 )
 
 (define_insn "fnmssf4"
-  [(set (match_operand:SF                 0 "register_operand" "=A")
+  [(set (match_operand:SF                 0 "register_operand" "=c")
 	(fma:SF (neg:SF (match_operand:SF 1 "register_operand" "f"))
 		(match_operand:SF         2 "register_operand" "f")
 		(neg:SF (match_operand:SF 3 "register_operand" "f"))))
-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 90+ messages in thread

* [PATCH 17/28] mn10300: Explicitly represent MDR in multiply and divide.
  2011-01-10 20:33 [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Richard Henderson
                   ` (18 preceding siblings ...)
  2011-01-10 20:34 ` [PATCH 24/28] mn10300: Implement adddi3, subdi3 Richard Henderson
@ 2011-01-10 20:34 ` Richard Henderson
  2011-01-18 18:13   ` Jeff Law
  2011-01-10 20:34 ` [PATCH 03/28] mn10300: delete ASM_PN_FORMAT Richard Henderson
                   ` (9 subsequent siblings)
  29 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-10 20:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: nickc, law, Richard Henderson

From: Richard Henderson <rth@twiddle.net>

Note that the mulsidi3_internal pattern is structured so
as to let the lower-subregs pass fully split the result.
---
 gcc/config/mn10300/mn10300.md |  271 +++++++++++++++++++++++------------------
 1 files changed, 155 insertions(+), 116 deletions(-)

diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md
index 86f26728..88743d6 100644
--- a/gcc/config/mn10300/mn10300.md
+++ b/gcc/config/mn10300/mn10300.md
@@ -37,6 +37,8 @@
   (UNSPEC_GOTOFF	3)
   (UNSPEC_PLT		4)
   (UNSPEC_GOTSYM_OFF	5)
+
+  (UNSPEC_EXT		6)
 ])
 
 (include "predicates.md")
@@ -160,6 +162,8 @@
   (eq_attr "timings" "4040") "throughput*40")
 (define_insn_reservation "throughput_41_latency_42" 42
   (eq_attr "timings" "4142") "throughput*41,nothing")
+(define_insn_reservation "throughput_42_latency_43" 44
+  (eq_attr "timings" "4243") "throughput*42,nothing")
 (define_insn_reservation "throughput_43_latency_44" 44
   (eq_attr "timings" "4344") "throughput*43,nothing")
 (define_insn_reservation "throughput_45_latency_46" 46
@@ -708,148 +712,183 @@
 ;; MULTIPLY INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
-(define_insn "mulsidi3"
-  [(set (match_operand:DI 0 "register_operand" "=dax")
-        (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "dax"))
-                 (sign_extend:DI (match_operand:SI 2 "register_operand" "dax"))))
-   (clobber (reg:CC CC_REG))
-  ]
-  "TARGET_AM33"
-  "mul %1,%2,%H0,%L0"
-  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
-				       (const_int 24) (const_int 23)))]
-)
+;; ??? Note that AM33 has a third multiply variant that puts the high part
+;; into the MDRQ register, however this variant also constrains the inputs
+;; to be in DATA_REGS and thus isn't as helpful as it might be considering
+;; the existance of the 4-operand multiply.  Nor is there a set of divide
+;; insns that use MDRQ.  Given that there is an IMM->MDRQ insn, this would
+;; have been very handy for starting udivmodsi4...
+
+(define_expand "mulsidi3"
+  [(set (match_operand:DI 0 "register_operand" "")
+        (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" ""))
+                 (sign_extend:DI (match_operand:SI 2 "register_operand" ""))))]
+  ""
+{
+  emit_insn (gen_mulsidi3_internal (gen_lowpart (SImode, operands[0]),
+				    gen_highpart (SImode, operands[0]),
+				    operands[1], operands[2]));
+  DONE;
+})
 
-(define_insn "umulsidi3"
-  [(set (match_operand:DI                          0 "register_operand" "=dax")
-        (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "dax"))
-                 (zero_extend:DI (match_operand:SI 2 "register_operand" "dax"))))
-   (clobber (reg:CC CC_REG))
-  ]
-  "TARGET_AM33"
-  "mulu %1,%2,%H0,%L0"
-  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
-				       (const_int 24) (const_int 23)))]
+(define_insn "mulsidi3_internal"
+  [(set (match_operand:SI          0 "register_operand" "=D,r")
+	(mult:SI (match_operand:SI 2 "register_operand" "%0,r")
+		 (match_operand:SI 3 "register_operand" " D,r")))
+   (set (match_operand:SI          1 "register_operand" "=z,r")
+	(truncate:SI
+	  (ashiftrt:DI
+	    (mult:DI (sign_extend:DI (match_dup 2))
+		     (sign_extend:DI (match_dup 3)))
+	    (const_int 32))))
+   (clobber (reg:CC CC_REG))]
+  ""
+{
+  if (which_alternative == 1)
+    return "mul %2,%3,%1,%0";
+  else if (TARGET_MULT_BUG)
+    return "nop\;nop\;mul %3,%0";
+  else
+    return "mul %3,%0";
+}
+  [(set_attr "isa" "*,am33")
+   (set (attr "timings")
+        (if_then_else (eq_attr "cpu" "am34") (const_int 24) (const_int 23)))]
 )
 
-(define_expand "mulsi3"
-  [(parallel [(set (match_operand:SI          0 "register_operand")
-		   (mult:SI (match_operand:SI 1 "register_operand")
-			    (match_operand:SI 2 "register_operand")))
-	      (clobber (reg:CC CC_REG))
-	     ])
-  ]
+(define_expand "umulsidi3"
+  [(set (match_operand:DI 0 "register_operand" "")
+        (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" ""))
+                 (zero_extend:DI (match_operand:SI 2 "register_operand" ""))))
+   (clobber (reg:CC CC_REG))]
   ""
-  "")
+{
+  emit_insn (gen_umulsidi3_internal (gen_lowpart (SImode, operands[0]),
+				     gen_highpart (SImode, operands[0]),
+				     operands[1], operands[2]));
+  DONE;
+})
 
-(define_insn "*am33_mulsi3"
-  [(set (match_operand:SI          0 "register_operand" "=dx,!dax")
-	(mult:SI (match_operand:SI 1 "register_operand" "%0,0")
-		 (match_operand:SI 2 "nonmemory_operand" "dx,daxi")))
-   (clobber (reg:CC CC_REG))
-  ]
-  "TARGET_AM33"
-  "*
+(define_insn "umulsidi3_internal"
+  [(set (match_operand:SI          0 "register_operand" "=D,r")
+	(mult:SI (match_operand:SI 2 "register_operand" "%0,r")
+		 (match_operand:SI 3 "register_operand" " D,r")))
+   (set (match_operand:SI          1 "register_operand" "=z,r")
+	(truncate:SI
+	  (lshiftrt:DI
+	    (mult:DI (zero_extend:DI (match_dup 2))
+		     (zero_extend:DI (match_dup 3)))
+	    (const_int 32))))
+   (clobber (reg:CC CC_REG))]
+  ""
 {
-  if (TARGET_MULT_BUG)
-    return \"nop\;nop\;mul %2,%0\";
+  if (which_alternative == 1)
+    return "mulu %2,%3,%1,%0";
+  else if (TARGET_MULT_BUG)
+    return "nop\;nop\;mulu %3,%0";
   else
-    return \"mul %2,%0\";
-}"
-  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34") (const_int 24) (const_int 23)))]
+    return "mulu %3,%0";
+}
+  [(set_attr "isa" "*,am33")
+   (set (attr "timings")
+        (if_then_else (eq_attr "cpu" "am34") (const_int 24) (const_int 23)))]
 )
 
-(define_insn "*mn10300_mulsi3"
-  [(set (match_operand:SI          0 "register_operand" "=dx")
-	(mult:SI (match_operand:SI 1 "register_operand" "%0")
-		 (match_operand:SI 2 "register_operand" "dx")))
-   (clobber (reg:CC CC_REG))
-  ]
+(define_expand "mulsi3"
+  [(parallel [(set (match_operand:SI          0 "register_operand"  "")
+		   (mult:SI (match_operand:SI 1 "register_operand"  "")
+			    (match_operand:SI 2 "nonmemory_operand" "")))
+	      (clobber (match_scratch:SI      3 ""))
+	      (clobber (reg:CC CC_REG))])]
   ""
-  "*
-{
-  if (TARGET_MULT_BUG)
-    return \"nop\;nop\;mul %2,%0\";
-  else
-    return \"mul %2,%0\";
-}"
-  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
-  	      		 	       (const_int 24) (const_int 23)))]
 )
 
-;; ??? This pattern causes too-high register pressure for MN103.
-;; ??? To be fixed by exposing the MDR register properly.
-(define_insn "udivmodsi4"
-  [(set (match_operand:SI          0 "register_operand" "=D")
-	(udiv:SI (match_operand:SI 1 "register_operand" "0")
-		 (match_operand:SI 2 "register_operand" "D")))
-   (set (match_operand:SI          3 "register_operand" "=&d")
-	(umod:SI (match_dup 1) (match_dup 2)))
+(define_insn "*mulsi3"
+  [(set (match_operand:SI          0 "register_operand"  "=D, r,r")
+	(mult:SI (match_operand:SI 2 "register_operand"  "%0, 0,r")
+		 (match_operand:SI 3 "nonmemory_operand" " D,ri,r")))
+   (clobber (match_scratch:SI      1                     "=z, z,r"))
    (clobber (reg:CC CC_REG))]
-  "TARGET_AM33"
+  ""
 {
-  output_asm_insn ("clr %3\;ext %3", operands);
-  if (find_reg_note (insn, REG_UNUSED, operands[3]))
-    return "divu %2,%0";
+  if (which_alternative == 2)
+    return "mul %2,%3,%1,%0";
+  else if (TARGET_MULT_BUG)
+    return "nop\;nop\;mul %3,%0";
   else
-    return "divu %2,%0\;mov mdr,%3";
+    return "mul %3,%0";
 }
-  ;; Timings:  AM33   AM34
-  ;;  SUB       1/1    1/1
-  ;;  MOV       1/1    1/1
-  ;;  DIVU     38/39  42/43
-  ;;  MOV       1/1    1/1
-  ;;  --------------------
-  ;;  total    41/42  45/46  (worst case sceanario)
-  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
-  	      		 	       (const_int 4546) (const_int 4142)))]
+  [(set_attr "isa" "*,am33,am33")
+   (set (attr "timings")
+	(if_then_else (eq_attr "cpu" "am34") (const_int 24) (const_int 23)))]
 )
 
-;; ??? In the meantime MN103 can use these two patterns,
-;; which reduce the register pressure by one.
-(define_insn "udivsi3"
-  [(set (match_operand:SI          0 "register_operand" "=&d")
-	(udiv:SI (match_operand:SI 1 "register_operand" "d")
-		 (match_operand:SI 2 "register_operand" "d")))
-   (clobber (reg:CC CC_REG))]
-  "!TARGET_AM33"
-  "clr %0\;ext %0\;mov %1,%0\;divu %2,%0"
-  [(set_attr "timings" "4142")]
+(define_expand "udivmodsi4"
+  [(parallel [(set (match_operand:SI          0 "register_operand")
+		   (udiv:SI (match_operand:SI 1 "register_operand")
+			    (match_operand:SI 2 "register_operand")))
+	      (set (match_operand:SI          3 "register_operand")
+		   (umod:SI (match_dup 1) (match_dup 2)))
+	      (use (const_int 0))
+	      (clobber (reg:CC CC_REG))])]
+  ""
 )
 
-(define_insn "umodsi3"
-  [(set (match_operand:SI          0 "register_operand" "=&d")
-	(umod:SI (match_operand:SI 1 "register_operand" "d")
-		 (match_operand:SI 2 "register_operand" "d")))
+;; Note the trick to get reload to put the zero into the MDR register,
+;; rather than exposing the load early and letting CSE or someone try
+;; to share the zeros between division insns.  Which tends to result
+;; in sequences like 0->r0->d0->mdr.
+
+(define_insn "*udivmodsi4"
+  [(set (match_operand:SI          0 "register_operand" "=D")
+	(udiv:SI (match_operand:SI 2 "register_operand" " 0")
+		 (match_operand:SI 3 "register_operand" " D")))
+   (set (match_operand:SI          1 "register_operand" "=z")
+	(umod:SI (match_dup 2) (match_dup 3)))
+   (use (match_operand:SI          4 "nonmemory_operand" " 1"))
    (clobber (reg:CC CC_REG))]
-  "!TARGET_AM33"
-  "clr %0\;ext %0\;mov %1,%0\;divu %2,%0\;mov mdr,%0"
-  [(set_attr "timings" "4142")]
+  ""
+  "divu %3,%0"
+  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
+  	      		 	       (const_int 3839) (const_int 4243)))]
 )
 
-(define_insn "divmodsi4"
-  [(set (match_operand:SI          0 "register_operand" "=dx")
-	(div:SI (match_operand:SI  1 "register_operand"  "0")
-		 (match_operand:SI 2 "register_operand"  "dx")))
-   (set (match_operand:SI          3 "register_operand" "=d")
-	(mod:SI (match_dup 1) (match_dup 2)))
-   (clobber (reg:CC CC_REG))
-  ]
+(define_expand "divmodsi4"
+  [(parallel [(set (match_operand:SI          0 "register_operand" "")
+		   (div:SI (match_operand:SI  1 "register_operand" "")
+			   (match_operand:SI  2 "register_operand" "")))
+	      (set (match_operand:SI          3 "register_operand" "")
+		   (mod:SI (match_dup 1) (match_dup 2)))
+	      (use (match_dup 4))
+	      (clobber (reg:CC CC_REG))])]
   ""
-  "*
 {
-  if (find_reg_note (insn, REG_UNUSED, operands[3]))
-    return \"ext %0\;div %2,%0\";
-  else
-    return \"ext %0\;div %2,%0\;mov mdr,%3\";
-}"
-  ;; Timings:  AM33   AM34
-  ;;  EXT       1/1    1/1
-  ;;  DIV      38/39  42/43
-  ;;  --------------------
-  ;;  total    39/40  43/44  (worst case sceanario)
+  operands[4] = gen_reg_rtx (SImode);
+  emit_insn (gen_ext_internal (operands[4], operands[1]));
+})
+
+;; ??? Ideally we'd represent this via shift, but it seems like adding a
+;; special-case pattern for (ashiftrt x 31) is just as likely to result
+;; in poor register allocation choices.
+(define_insn "ext_internal"
+  [(set (match_operand:SI 0 "register_operand" "=z")
+	(unspec:SI [(match_operand:SI 1 "register_operand" "D")] UNSPEC_EXT))]
+  ""
+  "ext %1"
+)
+
+(define_insn "*divmodsi4"
+  [(set (match_operand:SI          0 "register_operand" "=D")
+	(div:SI (match_operand:SI  2 "register_operand" " 0")
+		(match_operand:SI  3 "register_operand" " D")))
+   (set (match_operand:SI          1 "register_operand" "=z")
+	(mod:SI (match_dup 2) (match_dup 3)))
+   (use (match_operand:SI          4 "register_operand" " 1"))
+   (clobber (reg:CC CC_REG))]
+  ""
+  "div %3,%0";
   [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
-  	      		 	       (const_int 4344) (const_int 3940)))]
+  	      		 	       (const_int 3839) (const_int 4243)))]
 )
 
 \f
-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 90+ messages in thread

* [PATCH 14/28] mn10300: Cleanup legitimate addresses
  2011-01-10 20:33 [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Richard Henderson
                   ` (24 preceding siblings ...)
  2011-01-10 20:34 ` [PATCH 22/28] mn10300: Emit retf instruction Richard Henderson
@ 2011-01-10 20:34 ` Richard Henderson
  2011-01-18 17:14   ` Jeff Law
  2011-01-10 20:39 ` [PATCH 16/28] mn10300: Expose the MDR register to register allocation Richard Henderson
                   ` (3 subsequent siblings)
  29 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-10 20:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: nickc, law, Richard Henderson

From: Richard Henderson <rth@twiddle.net>

Allow REG+REG and POST_MODIFY addressing for AM33.  Fix AM33 base and
index register classes.  Remove a bunch of register class combinations
that aren't really useful after this cleanup.
---
 gcc/config/mn10300/mn10300-protos.h |    2 +
 gcc/config/mn10300/mn10300.c        |  157 ++++++++++++++++++++++++-----------
 gcc/config/mn10300/mn10300.h        |   85 ++++++++-----------
 3 files changed, 147 insertions(+), 97 deletions(-)

diff --git a/gcc/config/mn10300/mn10300-protos.h b/gcc/config/mn10300/mn10300-protos.h
index 37968ff..d0ce1b3 100644
--- a/gcc/config/mn10300/mn10300-protos.h
+++ b/gcc/config/mn10300/mn10300-protos.h
@@ -26,6 +26,7 @@
 #ifdef RTX_CODE
 extern rtx   mn10300_legitimize_pic_address (rtx, rtx);
 extern int   mn10300_legitimate_pic_operand_p (rtx);
+extern rtx   mn10300_legitimize_reload_address (rtx, Mmode, int, int, int);
 extern bool  mn10300_function_value_regno_p (const unsigned int);
 extern int   mn10300_get_live_callee_saved_regs (void);
 extern bool  mn10300_hard_regno_mode_ok (unsigned int, Mmode);
@@ -40,6 +41,7 @@ extern int   mn10300_store_multiple_operation (rtx, Mmode);
 extern int   mn10300_symbolic_operand (rtx, Mmode);
 #endif /* RTX_CODE */
 
+extern bool  mn10300_regno_in_class_p (unsigned, int, bool);
 extern int   mn10300_can_use_return_insn (void);
 extern void  mn10300_expand_prologue (void);
 extern void  mn10300_expand_epilogue (void);
diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c
index 78b5b5d..32fb57d 100644
--- a/gcc/config/mn10300/mn10300.c
+++ b/gcc/config/mn10300/mn10300.c
@@ -489,26 +489,38 @@ mn10300_print_operand_address (FILE *file, rtx addr)
   switch (GET_CODE (addr))
     {
     case POST_INC:
-      mn10300_print_operand_address (file, XEXP (addr, 0));
+      mn10300_print_operand (file, XEXP (addr, 0), 0);
       fputc ('+', file);
       break;
+
+    case POST_MODIFY:
+      mn10300_print_operand (file, XEXP (addr, 0), 0);
+      fputc ('+', file);
+      fputc (',', file);
+      mn10300_print_operand (file, XEXP (addr, 1), 0);
+      break;
+
     case REG:
       mn10300_print_operand (file, addr, 0);
       break;
     case PLUS:
       {
-	rtx base, index;
-	if (REG_P (XEXP (addr, 0))
-	    && REG_OK_FOR_BASE_P (XEXP (addr, 0)))
-	  base = XEXP (addr, 0), index = XEXP (addr, 1);
-	else if (REG_P (XEXP (addr, 1))
-	    && REG_OK_FOR_BASE_P (XEXP (addr, 1)))
-	  base = XEXP (addr, 1), index = XEXP (addr, 0);
-      	else
-	  gcc_unreachable ();
+	rtx base = XEXP (addr, 0);
+	rtx index = XEXP (addr, 1);
+	
+	if (REG_P (index) && !REG_OK_FOR_INDEX_P (index))
+	  {
+	    rtx x = base;
+	    base = index;
+	    index = x;
+
+	    gcc_assert (REG_P (index) && REG_OK_FOR_INDEX_P (index));
+	  }
+	gcc_assert (REG_OK_FOR_BASE_P (base));
+
 	mn10300_print_operand (file, index, 0);
 	fputc (',', file);
-	mn10300_print_operand (file, base, 0);;
+	mn10300_print_operand (file, base, 0);
 	break;
       }
     case SYMBOL_REF:
@@ -1389,8 +1401,7 @@ mn10300_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i,
   if (in_p
       && rclass != SP_REGS
       && rclass != SP_OR_ADDRESS_REGS
-      && rclass != SP_OR_EXTENDED_REGS
-      && rclass != SP_OR_ADDRESS_OR_EXTENDED_REGS
+      && rclass != SP_OR_GENERAL_REGS
       && GET_CODE (x) == PLUS
       && (XEXP (x, 0) == stack_pointer_rtx
 	  || XEXP (x, 1) == stack_pointer_rtx))
@@ -1416,7 +1427,7 @@ mn10300_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i,
 	addr = XEXP (x, 0);
 
       if (addr && CONSTANT_ADDRESS_P (addr))
-	return DATA_OR_EXTENDED_REGS;
+	return GENERAL_REGS;
     }
 
   /* Otherwise assume no secondary reloads are needed.  */
@@ -1948,51 +1959,99 @@ mn10300_legitimate_pic_operand_p (rtx x)
 static bool
 mn10300_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
 {
-  if (CONSTANT_ADDRESS_P (x)
-      && (! flag_pic || mn10300_legitimate_pic_operand_p (x)))
-    return TRUE;
+  rtx base, index;
+
+  if (CONSTANT_ADDRESS_P (x))
+    return !flag_pic || mn10300_legitimate_pic_operand_p (x);
 
   if (RTX_OK_FOR_BASE_P (x, strict))
-    return TRUE;
+    return true;
 
-  if (TARGET_AM33
-      && GET_CODE (x) == POST_INC
-      && RTX_OK_FOR_BASE_P (XEXP (x, 0), strict)
-      && (mode == SImode || mode == SFmode || mode == HImode))
-    return TRUE;
+  if (TARGET_AM33 && (mode == SImode || mode == SFmode || mode == HImode))
+    {
+      if (GET_CODE (x) == POST_INC)
+	return RTX_OK_FOR_BASE_P (XEXP (x, 0), strict);
+      if (GET_CODE (x) == POST_MODIFY)
+	return (RTX_OK_FOR_BASE_P (XEXP (x, 0), strict)
+		&& CONSTANT_ADDRESS_P (XEXP (x, 1)));
+    }
 
-  if (GET_CODE (x) == PLUS)
+  if (GET_CODE (x) != PLUS)
+    return false;
+
+  base = XEXP (x, 0);
+  index = XEXP (x, 1);
+
+  if (!REG_P (base))
+    return false;
+  if (REG_P (index))
     {
-      rtx base = 0, index = 0;
+      /* ??? Without AM33 generalized (Ri,Rn) addressing, reg+reg
+	 addressing is hard to satisfy.  */
+      if (!TARGET_AM33)
+	return false;
 
-      if (REG_P (XEXP (x, 0))
-	  && REGNO_STRICT_OK_FOR_BASE_P (REGNO (XEXP (x, 0)), strict))
-	{
-	  base = XEXP (x, 0);
-	  index = XEXP (x, 1);
-	}
+      return (REGNO_GENERAL_P (REGNO (base), strict)
+	      && REGNO_GENERAL_P (REGNO (index), strict));
+    }
 
-      if (REG_P (XEXP (x, 1))
-	  && REGNO_STRICT_OK_FOR_BASE_P (REGNO (XEXP (x, 1)), strict))
-	{
-	  base = XEXP (x, 1);
-	  index = XEXP (x, 0);
-	}
+  if (!REGNO_STRICT_OK_FOR_BASE_P (REGNO (base), strict))
+    return false;
 
-      if (base != 0 && index != 0)
-	{
-	  if (CONST_INT_P (index))
-	    return TRUE;
-	  if (GET_CODE (index) == CONST
-	      && GET_CODE (XEXP (index, 0)) != PLUS
-	      && (! flag_pic
- 		  || (mn10300_legitimate_pic_operand_p (index)
-		      && GET_MODE_SIZE (mode) == 4)))
-	    return TRUE;
-	}
+  if (CONST_INT_P (index))
+    return IN_RANGE (INTVAL (index), -1 - 0x7fffffff, 0x7fffffff);
+
+  if (CONSTANT_ADDRESS_P (index))
+    return !flag_pic || mn10300_legitimate_pic_operand_p (index);
+
+  return false;
+}
+
+bool
+mn10300_regno_in_class_p (unsigned regno, int rclass, bool strict)
+{
+  if (regno >= FIRST_PSEUDO_REGISTER)
+    {
+      if (!strict)
+	return true;
+      if (!reg_renumber)
+	return false;
+      regno = reg_renumber[regno];
+    }
+  return TEST_HARD_REG_BIT (reg_class_contents[rclass], regno);
+}
+
+rtx
+mn10300_legitimize_reload_address (rtx x,
+				   enum machine_mode mode ATTRIBUTE_UNUSED,
+				   int opnum, int type,
+				   int ind_levels ATTRIBUTE_UNUSED)
+{
+  bool any_change = false;
+
+  /* See above re disabling reg+reg addressing for MN103.  */
+  if (!TARGET_AM33)
+    return NULL_RTX;
+
+  if (GET_CODE (x) != PLUS)
+    return NULL_RTX;
+
+  if (XEXP (x, 0) == stack_pointer_rtx)
+    {
+      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
+		   GENERAL_REGS, GET_MODE (x), VOIDmode, 0, 0,
+		   opnum, (enum reload_type) type);
+      any_change = true;
+    }
+  if (XEXP (x, 1) == stack_pointer_rtx)
+    {
+      push_reload (XEXP (x, 1), NULL_RTX, &XEXP (x, 1), NULL,
+		   GENERAL_REGS, GET_MODE (x), VOIDmode, 0, 0,
+		   opnum, (enum reload_type) type);
+      any_change = true;
     }
 
-  return FALSE;
+  return any_change ? x : NULL_RTX;
 }
 
 /* Used by LEGITIMATE_CONSTANT_P().  Returns TRUE if X is a valid
diff --git a/gcc/config/mn10300/mn10300.h b/gcc/config/mn10300/mn10300.h
index 4fe0c48..7a6f1a8 100644
--- a/gcc/config/mn10300/mn10300.h
+++ b/gcc/config/mn10300/mn10300.h
@@ -261,12 +261,9 @@ extern enum processor_type mn10300_tune_cpu;
 
 enum reg_class
 {
-  NO_REGS, DATA_REGS, ADDRESS_REGS, SP_REGS,
-  DATA_OR_ADDRESS_REGS, SP_OR_ADDRESS_REGS,
-  EXTENDED_REGS, DATA_OR_EXTENDED_REGS, ADDRESS_OR_EXTENDED_REGS,
-  SP_OR_EXTENDED_REGS, SP_OR_ADDRESS_OR_EXTENDED_REGS,
-  FP_REGS, FP_ACC_REGS, CC_REGS,
-  GENERAL_REGS, ALL_REGS, LIM_REG_CLASSES
+  NO_REGS, DATA_REGS, ADDRESS_REGS, SP_REGS, SP_OR_ADDRESS_REGS,
+  EXTENDED_REGS, FP_REGS, FP_ACC_REGS, CC_REGS,
+  GENERAL_REGS, SP_OR_GENERAL_REGS, ALL_REGS, LIM_REG_CLASSES
 };
 
 #define N_REG_CLASSES (int) LIM_REG_CLASSES
@@ -274,13 +271,9 @@ enum reg_class
 /* Give names of register classes as strings for dump file.  */
 
 #define REG_CLASS_NAMES					   	\
-{ "NO_REGS", "DATA_REGS", "ADDRESS_REGS",			\
-  "SP_REGS", "DATA_OR_ADDRESS_REGS", "SP_OR_ADDRESS_REGS",	\
-  "EXTENDED_REGS",						\
-  "DATA_OR_EXTENDED_REGS", "ADDRESS_OR_EXTENDED_REGS",		\
-  "SP_OR_EXTENDED_REGS", "SP_OR_ADDRESS_OR_EXTENDED_REGS",	\
-  "FP_REGS", "FP_ACC_REGS", "CC_REGS",				\
-  "GENERAL_REGS", "ALL_REGS", "LIM_REGS"			\
+{ "NO_REGS", "DATA_REGS", "ADDRESS_REGS", "SP_REGS", "SP_OR_ADDRESS_REGS", \
+  "EXTENDED_REGS", "FP_REGS", "FP_ACC_REGS", "CC_REGS",		\
+  "GENERAL_REGS", "SP_OR_GENERAL_REGS", "ALL_REGS", "LIM_REGS"	\
 }
 
 /* Define which registers fit in which classes.
@@ -292,17 +285,13 @@ enum reg_class
   { 0x0000000f, 0 },	  /* DATA_REGS */			\
   { 0x000001f0, 0 },	  /* ADDRESS_REGS */			\
   { 0x00000200, 0 },	  /* SP_REGS */				\
-  { 0x000001ff, 0 },	  /* DATA_OR_ADDRESS_REGS */		\
   { 0x000003f0, 0 },	  /* SP_OR_ADDRESS_REGS */		\
   { 0x0003fc00, 0 },	  /* EXTENDED_REGS */			\
-  { 0x0003fc0f, 0 },	  /* DATA_OR_EXTENDED_REGS */		\
-  { 0x0003fdf0, 0 },	  /* ADDRESS_OR_EXTENDED_REGS */	\
-  { 0x0003fe00, 0 },	  /* SP_OR_EXTENDED_REGS */		\
-  { 0x0003fff0, 0 },	  /* SP_OR_ADDRESS_OR_EXTENDED_REGS */	\
   { 0xfffc0000, 0x3ffff },/* FP_REGS */				\
   { 0x03fc0000, 0 },	  /* FP_ACC_REGS */			\
   { 0x00000000, 0x80000 },/* CC_REGS */				\
   { 0x0003fdff, 0 }, 	  /* GENERAL_REGS */			\
+  { 0x0003ffff, 0 },      /* SP_OR_GENERAL_REGS */		\
   { 0xffffffff, 0xfffff } /* ALL_REGS */			\
 }
 
@@ -334,8 +323,10 @@ enum reg_class
    NO_REGS)
 
 /* The class value for index registers, and the one for base regs.  */
-#define INDEX_REG_CLASS DATA_OR_EXTENDED_REGS
-#define BASE_REG_CLASS  SP_OR_ADDRESS_REGS
+#define INDEX_REG_CLASS \
+  (TARGET_AM33 ? GENERAL_REGS : DATA_REGS)
+#define BASE_REG_CLASS \
+  (TARGET_AM33 ? SP_OR_GENERAL_REGS : SP_OR_ADDRESS_REGS)
 
 /* Macros to check register numbers against specific register classes.  */
 
@@ -364,50 +355,31 @@ enum reg_class
 # define REG_STRICT 1
 #endif
 
-# define REGNO_IN_RANGE_P(regno,min,max,strict) \
-  (IN_RANGE ((regno), (min), (max)) 		\
-   || ((strict)					\
-       ? (reg_renumber				\
-	  && reg_renumber[(regno)] >= (min)	\
-	  && reg_renumber[(regno)] <= (max))	\
-       : (regno) >= FIRST_PSEUDO_REGISTER))
-
 #define REGNO_DATA_P(regno, strict) \
-  (REGNO_IN_RANGE_P ((regno), FIRST_DATA_REGNUM, LAST_DATA_REGNUM, \
-		     (strict)))
+  mn10300_regno_in_class_p (regno, DATA_REGS, strict)
 #define REGNO_ADDRESS_P(regno, strict) \
-  (REGNO_IN_RANGE_P ((regno), FIRST_ADDRESS_REGNUM, LAST_ADDRESS_REGNUM, \
-		     (strict)))
-#define REGNO_SP_P(regno, strict) \
-  (REGNO_IN_RANGE_P ((regno), STACK_POINTER_REGNUM, STACK_POINTER_REGNUM, \
-		     (strict)))
+  mn10300_regno_in_class_p (regno, ADDRESS_REGS, strict)
 #define REGNO_EXTENDED_P(regno, strict) \
-  (REGNO_IN_RANGE_P ((regno), FIRST_EXTENDED_REGNUM, LAST_EXTENDED_REGNUM, \
-		     (strict)))
-#define REGNO_AM33_P(regno, strict) \
-  (REGNO_DATA_P ((regno), (strict)) || REGNO_ADDRESS_P ((regno), (strict)) \
-   || REGNO_EXTENDED_P ((regno), (strict)))
-#define REGNO_FP_P(regno, strict) \
-  (REGNO_IN_RANGE_P ((regno), FIRST_FP_REGNUM, LAST_FP_REGNUM, (strict)))
+  mn10300_regno_in_class_p (regno, EXTENDED_REGS, strict)
+#define REGNO_GENERAL_P(regno, strict) \
+  mn10300_regno_in_class_p (regno, GENERAL_REGS, strict)
 
 #define REGNO_STRICT_OK_FOR_BASE_P(regno, strict) \
-  (REGNO_SP_P ((regno), (strict)) \
-   || REGNO_ADDRESS_P ((regno), (strict)) \
-   || REGNO_EXTENDED_P ((regno), (strict)))
+  mn10300_regno_in_class_p (regno, BASE_REG_CLASS, strict)
 #define REGNO_OK_FOR_BASE_P(regno) \
   (REGNO_STRICT_OK_FOR_BASE_P ((regno), REG_STRICT))
 #define REG_OK_FOR_BASE_P(X) \
   (REGNO_OK_FOR_BASE_P (REGNO (X)))
 
 #define REGNO_STRICT_OK_FOR_BIT_BASE_P(regno, strict) \
-  (REGNO_SP_P ((regno), (strict)) || REGNO_ADDRESS_P ((regno), (strict)))
+  mn10300_regno_in_class_p (regno, ADDRESS_REGS, strict)
 #define REGNO_OK_FOR_BIT_BASE_P(regno) \
   (REGNO_STRICT_OK_FOR_BIT_BASE_P ((regno), REG_STRICT))
 #define REG_OK_FOR_BIT_BASE_P(X) \
   (REGNO_OK_FOR_BIT_BASE_P (REGNO (X)))
 
 #define REGNO_STRICT_OK_FOR_INDEX_P(regno, strict) \
-  (REGNO_DATA_P ((regno), (strict)) || REGNO_EXTENDED_P ((regno), (strict)))
+  mn10300_regno_in_class_p (regno, INDEX_REG_CLASS, strict)
 #define REGNO_OK_FOR_INDEX_P(regno) \
   (REGNO_STRICT_OK_FOR_INDEX_P ((regno), REG_STRICT))
 #define REG_OK_FOR_INDEX_P(X) \
@@ -557,7 +529,15 @@ struct cum_arg
 #define MAX_REGS_PER_ADDRESS 2
 
 \f
-#define HAVE_POST_INCREMENT (TARGET_AM33)
+/* We have post-increments.  */
+#define HAVE_POST_INCREMENT	TARGET_AM33
+#define HAVE_POST_MODIFY_DISP	TARGET_AM33
+
+/* ... But we don't want to use them for block moves.  Small offsets are
+   just as effective, at least for inline block move sizes, and appears
+   to produce cleaner code.  */
+#define USE_LOAD_POST_INCREMENT(M)	0
+#define USE_STORE_POST_INCREMENT(M)	0
 
 /* Accept either REG or SUBREG where a register is valid.  */
 
@@ -568,6 +548,15 @@ struct cum_arg
        && REGNO_STRICT_OK_FOR_BASE_P (REGNO (SUBREG_REG (X)),	\
  				      (strict))))
 
+#define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_L,WIN)		     \
+do {									     \
+  rtx new_x = mn10300_legitimize_reload_address (X, MODE, OPNUM, TYPE, IND_L); \
+  if (new_x)								     \
+    {									     \
+      X = new_x;							     \
+      goto WIN;								     \
+    }									     \
+} while (0)
 \f
 
 /* Nonzero if the constant value X is a legitimate general operand.
-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 90+ messages in thread

* [PATCH 11/28] mn10300: Clean up costing.
  2011-01-10 20:33 [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Richard Henderson
                   ` (13 preceding siblings ...)
  2011-01-10 20:34 ` [PATCH 05/28] mn10300: Fix debug offsets into the stack frame Richard Henderson
@ 2011-01-10 20:34 ` Richard Henderson
  2011-01-11 15:02   ` Jeff Law
  2011-01-10 20:34 ` [PATCH 09/28] mn10300: Remove bset/bclr patterns Richard Henderson
                   ` (14 subsequent siblings)
  29 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-10 20:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: nickc, law, Richard Henderson

From: Richard Henderson <rth@twiddle.net>

Address, register, memory and rtx costs bore little relation to reality.
---
 gcc/config/mn10300/mn10300-protos.h |    1 -
 gcc/config/mn10300/mn10300.c        |  420 ++++++++++++++++++++++++-----------
 gcc/config/mn10300/mn10300.h        |   13 -
 3 files changed, 291 insertions(+), 143 deletions(-)

diff --git a/gcc/config/mn10300/mn10300-protos.h b/gcc/config/mn10300/mn10300-protos.h
index 8979eb4..d6cf850 100644
--- a/gcc/config/mn10300/mn10300-protos.h
+++ b/gcc/config/mn10300/mn10300-protos.h
@@ -39,7 +39,6 @@ extern Rclas mn10300_secondary_reload_class (Rclas, Mmode, rtx);
 extern Mmode mn10300_select_cc_mode (rtx);
 extern int   mn10300_store_multiple_operation (rtx, Mmode);
 extern int   mn10300_symbolic_operand (rtx, Mmode);
-extern bool  mn10300_wide_const_load_uses_clr (rtx operands[2]);
 #endif /* RTX_CODE */
 
 extern int   mn10300_can_use_return_insn (void);
diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c
index 7c090aa..5f2d63b 100644
--- a/gcc/config/mn10300/mn10300.c
+++ b/gcc/config/mn10300/mn10300.c
@@ -75,8 +75,6 @@ enum processor_type mn10300_tune_cpu = PROCESSOR_DEFAULT;
 				|| df_regs_ever_live_p (16)	\
 				|| df_regs_ever_live_p (17)))
 
-static int mn10300_address_cost (rtx, bool);
-
 /* Implement TARGET_OPTION_OPTIMIZATION_TABLE.  */
 static const struct default_options mn10300_option_optimization_table[] =
   {
@@ -2034,180 +2032,340 @@ mn10300_legitimate_constant_p (rtx x)
   return true;
 }
 
+/* For addresses, costs are relative to "MOV (Rm),Rn".  For AM33 this is
+   the 3-byte fully general instruction; for MN103 this is the 2-byte form
+   with an address register.  */
+
 static int
-mn10300_address_cost_1 (rtx x, int *unsig)
+mn10300_address_cost (rtx x, bool speed)
 {
+  HOST_WIDE_INT i;
+  rtx base, index;
+
   switch (GET_CODE (x))
     {
+    case CONST:
+    case SYMBOL_REF:
+    case LABEL_REF:
+      /* We assume all of these require a 32-bit constant, even though
+	 some symbol and label references can be relaxed.  */
+      return speed ? 1 : 4;
+
     case REG:
-      switch (REGNO_REG_CLASS (REGNO (x)))
+    case SUBREG:
+    case POST_INC:
+      return 0;
+
+    case POST_MODIFY:
+      /* Assume any symbolic offset is a 32-bit constant.  */
+      i = (CONST_INT_P (XEXP (x, 1)) ? INTVAL (XEXP (x, 1)) : 0x12345678);
+      if (IN_RANGE (i, -128, 127))
+	return speed ? 0 : 1;
+      if (speed)
+	return 1;
+      if (IN_RANGE (i, -0x800000, 0x7fffff))
+	return 3;
+      return 4;
+
+    case PLUS:
+      base = XEXP (x, 0);
+      index = XEXP (x, 1);
+      if (register_operand (index, SImode))
 	{
-	case SP_REGS:
-	  *unsig = 1;
-	  return 0;
+	  /* Attempt to minimize the number of registers in the address.
+	     This is similar to what other ports do.  */
+	  if (register_operand (base, SImode))
+	    return 1;
 
-	case ADDRESS_REGS:
-	  return 1;
+	  base = XEXP (x, 1);
+	  index = XEXP (x, 0);
+	}
 
-	case DATA_REGS:
-	case EXTENDED_REGS:
-	case FP_REGS:
-	  return 3;
+      /* Assume any symbolic offset is a 32-bit constant.  */
+      i = (CONST_INT_P (XEXP (x, 1)) ? INTVAL (XEXP (x, 1)) : 0x12345678);
+      if (IN_RANGE (i, -128, 127))
+	return speed ? 0 : 1;
+      if (IN_RANGE (i, -32768, 32767))
+	return speed ? 0 : 2;
+      return speed ? 2 : 6;
 
-	case NO_REGS:
-	  return 5;
+    default:
+      return rtx_cost (x, MEM, speed);
+    }
+}
 
-	default:
-	  gcc_unreachable ();
-	}
+/* Implement the TARGET_REGISTER_MOVE_COST hook.
 
-    case PLUS:
-    case MINUS:
-    case ASHIFT:
-    case AND:
-    case IOR:
-      return (mn10300_address_cost_1 (XEXP (x, 0), unsig)
-	      + mn10300_address_cost_1 (XEXP (x, 1), unsig));
+   Recall that the base value of 2 is required by assumptions elsewhere
+   in the body of the compiler, and that cost 2 is special-cased as an
+   early exit from reload meaning no work is required.  */
 
-    case EXPR_LIST:
-    case SUBREG:
-    case MEM:
-      return mn10300_address_cost (XEXP (x, 0), !optimize_size);
+static int
+mn10300_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
+			    reg_class_t ifrom, reg_class_t ito)
+{
+  enum reg_class from = (enum reg_class) ifrom;
+  enum reg_class to = (enum reg_class) ito;
+  enum reg_class scratch, test;
+
+  /* Simplify the following code by unifying the fp register classes.  */
+  if (to == FP_ACC_REGS)
+    to = FP_REGS;
+  if (from == FP_ACC_REGS)
+    from = FP_REGS;
+
+  /* Diagnose invalid moves by costing them as two moves.  */
+
+  scratch = NO_REGS;
+  test = from;
+  if (to == SP_REGS)
+    scratch = (TARGET_AM33 ? GENERAL_REGS : ADDRESS_REGS);
+  else if (to == FP_REGS && to != from)
+    scratch = GENERAL_REGS;
+  else
+    {
+      test = to;
+      if (from == SP_REGS)
+	scratch = (TARGET_AM33 ? GENERAL_REGS : ADDRESS_REGS);
+      else if (from == FP_REGS && to != from)
+	scratch = GENERAL_REGS;
+    }
+  if (scratch != NO_REGS && !reg_class_subset_p (test, scratch))
+    return (mn10300_register_move_cost (VOIDmode, from, scratch)
+	    + mn10300_register_move_cost (VOIDmode, scratch, to));
 
-    case ZERO_EXTEND:
-      *unsig = 1;
-      return mn10300_address_cost_1 (XEXP (x, 0), unsig);
+  /* From here on, all we need consider are legal combinations.  */
 
-    case CONST_INT:
-      if (INTVAL (x) == 0)
-	return 0;
-      if (INTVAL (x) + (*unsig ? 0 : 0x80) < 0x100)
-	return 1;
-      if (INTVAL (x) + (*unsig ? 0 : 0x8000) < 0x10000)
-	return 3;
-      if (INTVAL (x) + (*unsig ? 0 : 0x800000) < 0x1000000)
-	return 5;
-      return 7;
+  if (optimize_size)
+    {
+      /* The scale here is bytes * 2.  */
 
-    case CONST:
-    case SYMBOL_REF:
-    case LABEL_REF:
-      return 8;
+      if (from == to && (to == ADDRESS_REGS || to == DATA_REGS))
+	return 2;
 
-    default:
-      gcc_unreachable ();
+      if (from == SP_REGS)
+	return (to == ADDRESS_REGS ? 2 : 6);
+
+      /* For MN103, all remaining legal moves are two bytes.  */
+      if (TARGET_AM33)
+	return 4;
+
+      if (to == SP_REGS)
+	return (from == ADDRESS_REGS ? 4 : 6);
+
+      if ((from == ADDRESS_REGS || from == DATA_REGS)
+	   && (to == ADDRESS_REGS || to == DATA_REGS))
+	return 4;
+
+      if (to == EXTENDED_REGS)
+	return (to == from ? 6 : 4);
 
+      /* What's left are SP_REGS, FP_REGS, or combinations of the above.  */
+      return 6;
+    }
+  else
+    {
+      /* The scale here is cycles * 2.  */
+
+      if (to == FP_REGS)
+	return 8;
+      if (from == FP_REGS)
+	return 4;
+
+      /* All legal moves between integral registers are single cycle.  */
+      return 2;
     }
 }
 
+/* Implement the TARGET_MEMORY_MOVE_COST hook.
+
+   Given lack of the form of the address, this must be speed-relative,
+   though we should never be less expensive than a size-relative register
+   move cost above.  This is not a problem.  */
+
 static int
-mn10300_address_cost (rtx x, bool speed ATTRIBUTE_UNUSED)
+mn10300_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED, 
+			  reg_class_t iclass, bool in ATTRIBUTE_UNUSED)
 {
-  int s = 0;
-  return mn10300_address_cost_1 (x, &s);
+  enum reg_class rclass = (enum reg_class) iclass;
+
+  if (rclass == FP_REGS)
+    return 8;
+  return 6;
 }
 
+/* Implement the TARGET_RTX_COSTS hook.
+
+   Speed-relative costs are relative to COSTS_N_INSNS, which is intended
+   to represent cycles.  Size-relative costs are in bytes.  */
+
 static bool
-mn10300_rtx_costs (rtx x, int code, int outer_code, int *total,
-		   bool speed ATTRIBUTE_UNUSED)
+mn10300_rtx_costs (rtx x, int code, int outer_code, int *ptotal, bool speed)
 {
+  /* This value is used for SYMBOL_REF etc where we want to pretend
+     we have a full 32-bit constant.  */
+  HOST_WIDE_INT i = 0x12345678;
+  int total;
+
   switch (code)
     {
     case CONST_INT:
-      /* Zeros are extremely cheap.  */
-      if (INTVAL (x) == 0 && (outer_code == SET || outer_code == COMPARE))
-	*total = 0;
-      /* If it fits in 8 bits, then it's still relatively cheap.  */
-      else if (INT_8_BITS (INTVAL (x)))
-	*total = 1;
-      /* This is the "base" cost, includes constants where either the
-	 upper or lower 16bits are all zeros.  */
-      else if (INT_16_BITS (INTVAL (x))
-	       || (INTVAL (x) & 0xffff) == 0
-	       || (INTVAL (x) & 0xffff0000) == 0)
-	*total = 2;
+      i = INTVAL (x);
+    do_int_costs:
+      if (speed)
+	{
+	  if (outer_code == SET)
+	    {
+	      /* 16-bit integer loads have latency 1, 32-bit loads 2.  */
+	      if (IN_RANGE (i, -32768, 32767))
+		total = COSTS_N_INSNS (1);
+	      else
+		total = COSTS_N_INSNS (2);
+	    }
+	  else
+	    {
+	      /* 16-bit integer operands don't affect latency;
+		 24-bit and 32-bit operands add a cycle.  */
+	      if (IN_RANGE (i, -32768, 32767))
+		total = 0;
+	      else
+		total = COSTS_N_INSNS (1);
+	    }
+	}
       else
-	*total = 4;
-      return true;
+	{
+	  if (outer_code == SET)
+	    {
+	      if (i == 0)
+		total = 1;
+	      else if (IN_RANGE (i, -128, 127))
+		total = 2;
+	      else if (IN_RANGE (i, -32768, 32767))
+		total = 3;
+	      else
+		total = 6;
+	    }
+	  else
+	    {
+	      /* Reference here is ADD An,Dn, vs ADD imm,Dn.  */
+	      if (IN_RANGE (i, -128, 127))
+		total = 0;
+	      else if (IN_RANGE (i, -32768, 32767))
+		total = 2;
+	      else if (TARGET_AM33 && IN_RANGE (i, -0x01000000, 0x00ffffff))
+		total = 3;
+	      else
+		total = 4;
+	    }
+	}
+      goto alldone;
 
     case CONST:
     case LABEL_REF:
     case SYMBOL_REF:
-      /* These are more costly than a CONST_INT, but we can relax them,
-	 so they're less costly than a CONST_DOUBLE.  */
-      *total = 6;
-      return true;
-
     case CONST_DOUBLE:
-      /* We don't optimize CONST_DOUBLEs well nor do we relax them well,
-	 so their cost is very high.  */
-      *total = 8;
-      return true;
-
-    case ZERO_EXTRACT:
-      /* This is cheap, we can use btst.  */
-      if (outer_code == COMPARE)
-	*total = 0;
-      return false;
+      /* We assume all of these require a 32-bit constant, even though
+	 some symbol and label references can be relaxed.  */
+      goto do_int_costs;
 
-   /* ??? This probably needs more work.  */
-    case MOD:
-    case DIV:
-    case MULT:
-      *total = 8;
-      return true;
+    case UNSPEC:
+      switch (XINT (x, 1))
+	{
+	case UNSPEC_PIC:
+	case UNSPEC_GOT:
+	case UNSPEC_GOTOFF:
+	case UNSPEC_PLT:
+	case UNSPEC_GOTSYM_OFF:
+	  /* The PIC unspecs also resolve to a 32-bit constant.  */
+	  goto do_int_costs;
 
-    default:
-      return false;
-    }
-}
+	default:
+	  /* Assume any non-listed unspec is some sort of arithmetic.  */
+	  goto do_arith_costs;
+	}
 
-/* Check whether a constant used to initialize a DImode or DFmode can
-   use a clr instruction.  The code here must be kept in sync with
-   movdf and movdi.  */
+    case PLUS:
+      /* Notice the size difference of INC and INC4.  */
+      if (!speed && outer_code == SET && CONST_INT_P (XEXP (x, 1)))
+	{
+	  i = INTVAL (XEXP (x, 1));
+	  if (i == 1 || i == 4)
+	    {
+	      total = 1 + rtx_cost (XEXP (x, 0), PLUS, speed);
+	      goto alldone;
+	    }
+	}
+      goto do_arith_costs;
+	
+    case MINUS:
+    case AND:
+    case IOR:
+    case XOR:
+    case NOT:
+    case NEG:
+    case ZERO_EXTEND:
+    case SIGN_EXTEND:
+    case COMPARE:
+    case BSWAP:
+    case CLZ:
+    do_arith_costs:
+      total = (speed ? COSTS_N_INSNS (1) : 2);
+      break;
 
-bool
-mn10300_wide_const_load_uses_clr (rtx operands[2])
-{
-  long val[2] = {0, 0};
+    case ASHIFT:
+      /* Notice the size difference of ASL2 and variants.  */
+      if (!speed && CONST_INT_P (XEXP (x, 1)))
+	switch (INTVAL (XEXP (x, 1)))
+	  {
+	  case 1:
+	  case 2:
+	    total = 1;
+	    goto alldone;
+	  case 3:
+	  case 4:
+	    total = 2;
+	    goto alldone;
+	  }
+      /* FALLTHRU */
 
-  if ((! REG_P (operands[0]))
-      || REGNO_REG_CLASS (REGNO (operands[0])) != DATA_REGS)
-    return false;
+    case ASHIFTRT:
+    case LSHIFTRT:
+      total = (speed ? COSTS_N_INSNS (1) : 3);
+      goto alldone;
 
-  switch (GET_CODE (operands[1]))
-    {
-    case CONST_INT:
-      {
-	rtx low, high;
-	split_double (operands[1], &low, &high);
-	val[0] = INTVAL (low);
-	val[1] = INTVAL (high);
-      }
+    case MULT:
+      total = (speed ? COSTS_N_INSNS (3) : 2);
       break;
 
-    case CONST_DOUBLE:
-      if (GET_MODE (operands[1]) == DFmode)
-	{
-	  REAL_VALUE_TYPE rv;
-
-	  REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
-	  REAL_VALUE_TO_TARGET_DOUBLE (rv, val);
-	}
-      else if (GET_MODE (operands[1]) == VOIDmode
-	       || GET_MODE (operands[1]) == DImode)
-	{
-	  val[0] = CONST_DOUBLE_LOW (operands[1]);
-	  val[1] = CONST_DOUBLE_HIGH (operands[1]);
-	}
+    case DIV:
+    case UDIV:
+    case MOD:
+    case UMOD:
+      total = (speed ? COSTS_N_INSNS (39)
+		/* Include space to load+retrieve MDR.  */
+		: code == MOD || code == UMOD ? 6 : 4);
       break;
 
+    case MEM:
+      total = mn10300_address_cost (XEXP (x, 0), speed);
+      if (speed)
+	total = COSTS_N_INSNS (2 + total);
+      goto alldone;
+
     default:
-      return false;
+      /* Probably not implemented.  Assume external call.  */
+      total = (speed ? COSTS_N_INSNS (10) : 7);
+      break;
     }
 
-  return val[0] == 0 || val[1] == 0;
+  *ptotal = total;
+  return false;
+
+ alldone:
+  *ptotal = total;
+  return true;
 }
+
 /* If using PIC, mark a SYMBOL_REF for a non-global symbol so that we
    may access it using GOTOFF instead of GOT.  */
 
@@ -2504,10 +2662,14 @@ mn10300_conditional_register_usage (void)
 #undef  TARGET_LEGITIMIZE_ADDRESS
 #define TARGET_LEGITIMIZE_ADDRESS mn10300_legitimize_address
 
+#undef  TARGET_ADDRESS_COST
+#define TARGET_ADDRESS_COST  mn10300_address_cost
+#undef  TARGET_REGISTER_MOVE_COST
+#define TARGET_REGISTER_MOVE_COST  mn10300_register_move_cost
+#undef  TARGET_MEMORY_MOVE_COST
+#define TARGET_MEMORY_MOVE_COST  mn10300_memory_move_cost
 #undef  TARGET_RTX_COSTS
 #define TARGET_RTX_COSTS mn10300_rtx_costs
-#undef  TARGET_ADDRESS_COST
-#define TARGET_ADDRESS_COST mn10300_address_cost
 
 #undef  TARGET_ASM_FILE_START
 #define TARGET_ASM_FILE_START mn10300_file_start
diff --git a/gcc/config/mn10300/mn10300.h b/gcc/config/mn10300/mn10300.h
index 0ee0cd1..f5f6416 100644
--- a/gcc/config/mn10300/mn10300.h
+++ b/gcc/config/mn10300/mn10300.h
@@ -599,19 +599,6 @@ struct cum_arg
 #define SELECT_CC_MODE(OP, X, Y)  mn10300_select_cc_mode (X)
 #define REVERSIBLE_CC_MODE(MODE)  0
 \f
-#define REGISTER_MOVE_COST(MODE, CLASS1, CLASS2) \
-  ((CLASS1 == CLASS2 && (CLASS1 == ADDRESS_REGS || CLASS1 == DATA_REGS)) ? 2 :\
-   ((CLASS1 == ADDRESS_REGS || CLASS1 == DATA_REGS) && \
-    (CLASS2 == ADDRESS_REGS || CLASS2 == DATA_REGS)) ? 4 : \
-   (CLASS1 == SP_REGS && CLASS2 == ADDRESS_REGS) ? 2 : \
-   (CLASS1 == ADDRESS_REGS && CLASS2 == SP_REGS) ? 4 : \
-   ! TARGET_AM33 ? 6 : \
-   (CLASS1 == SP_REGS || CLASS2 == SP_REGS) ? 6 : \
-   (CLASS1 == CLASS2 && CLASS1 == EXTENDED_REGS) ? 6 : \
-   (CLASS1 == FP_REGS || CLASS2 == FP_REGS) ? 6 : \
-   (CLASS1 == EXTENDED_REGS || CLASS2 == EXTENDED_REGS) ? 4 : \
-   4)
-
 /* Nonzero if access to memory by bytes or half words is no faster
    than accessing full words.  */
 #define SLOW_BYTE_ACCESS 1
-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 90+ messages in thread

* [PATCH 26/28] mn10300: Auto-clobber the flags in asms.
  2011-01-10 20:33 [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Richard Henderson
                   ` (21 preceding siblings ...)
  2011-01-10 20:34 ` [PATCH 08/28] mn10300: Define the A and D constraints Richard Henderson
@ 2011-01-10 20:34 ` Richard Henderson
  2011-01-12 14:22   ` Jeff Law
  2011-01-10 20:34 ` [PATCH 18/28] mn10300: Cleanup all arithmetic Richard Henderson
                   ` (6 subsequent siblings)
  29 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-10 20:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: nickc, law, Richard Henderson

From: Richard Henderson <rth@twiddle.net>

---
 gcc/config/mn10300/mn10300.c |   18 ++++++++++++++++++
 1 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c
index 17e58fe..25bfa0d 100644
--- a/gcc/config/mn10300/mn10300.c
+++ b/gcc/config/mn10300/mn10300.c
@@ -2909,6 +2909,21 @@ mn10300_split_and_operand_count (rtx op)
       return -count;
     }
 }
+
+
+/* Worker function for TARGET_MD_ASM_CLOBBERS.
+   We do this in the mn10300 backend to maintain source compatibility
+   with the old cc0-based compiler.  */
+
+static tree
+mn10300_md_asm_clobbers (tree outputs ATTRIBUTE_UNUSED,
+                         tree inputs ATTRIBUTE_UNUSED,
+                         tree clobbers)
+{
+  clobbers = tree_cons (NULL_TREE, build_string (5, "EPSW"),
+                        clobbers);
+  return clobbers;
+}
 \f
 /* Initialize the GCC target structure.  */
 
@@ -3005,4 +3020,7 @@ mn10300_split_and_operand_count (rtx op)
 #undef  TARGET_CONDITIONAL_REGISTER_USAGE
 #define TARGET_CONDITIONAL_REGISTER_USAGE mn10300_conditional_register_usage
 
+#undef TARGET_MD_ASM_CLOBBERS
+#define TARGET_MD_ASM_CLOBBERS  mn10300_md_asm_clobbers
+
 struct gcc_target targetm = TARGET_INITIALIZER;
-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 90+ messages in thread

* [PATCH 07/28] mn10300: Add attribute enabled.
  2011-01-10 20:33 [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Richard Henderson
                   ` (16 preceding siblings ...)
  2011-01-10 20:34 ` [PATCH 28/28] New -fcompare-elim pass Richard Henderson
@ 2011-01-10 20:34 ` Richard Henderson
  2011-01-11 14:47   ` Jeff Law
  2011-01-10 20:34 ` [PATCH 24/28] mn10300: Implement adddi3, subdi3 Richard Henderson
                   ` (11 subsequent siblings)
  29 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-10 20:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: nickc, law, Richard Henderson

From: Richard Henderson <rth@twiddle.net>

This will allow merging am33 and mn103 patterns for which the
set of alternatives can't be merged via constraint letters.
---
 gcc/config/mn10300/mn10300.md |   22 ++++++++++++++++++++++
 1 files changed, 22 insertions(+), 0 deletions(-)

diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md
index 3a266960..bfa453f 100644
--- a/gcc/config/mn10300/mn10300.md
+++ b/gcc/config/mn10300/mn10300.md
@@ -46,6 +46,28 @@
 (define_attr "cpu" "mn10300,am33,am33_2,am34"
   (const (symbol_ref "(enum attr_cpu) mn10300_tune_cpu")))
 
+;; Used to control the "enabled" attribute on a per-instruction basis.
+(define_attr "isa" "base,am33,am33_2,am34"
+  (const_string "base"))
+
+(define_attr "enabled" ""
+  (cond [(eq_attr "isa" "base")
+         (const_int 1)
+
+         (and (eq_attr "isa" "am33")
+	      (ne (symbol_ref "TARGET_AM33") (const_int 0)))
+         (const_int 1)
+
+         (and (eq_attr "isa" "am33_2")
+	      (ne (symbol_ref "TARGET_AM33_2") (const_int 0)))
+         (const_int 1)
+        
+         (and (eq_attr "isa" "am34")
+	      (ne (symbol_ref "TARGET_AM34") (const_int 0)))
+         (const_int 1)
+	]
+	(const_int 0))
+)
 \f
 ;; Pipeline description.
 
-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 90+ messages in thread

* [PATCH 22/28] mn10300: Emit retf instruction
  2011-01-10 20:33 [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Richard Henderson
                   ` (23 preceding siblings ...)
  2011-01-10 20:34 ` [PATCH 18/28] mn10300: Cleanup all arithmetic Richard Henderson
@ 2011-01-10 20:34 ` Richard Henderson
  2011-01-18 18:18   ` Jeff Law
  2011-01-10 20:34 ` [PATCH 14/28] mn10300: Cleanup legitimate addresses Richard Henderson
                   ` (4 subsequent siblings)
  29 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-10 20:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: nickc, law, Richard Henderson

From: Richard Henderson <rth@twiddle.net>

Now that we properly track the life of MDR, we can emit
the RETF instruction if MDR has not been modified.  This
insn is 3-4 cycles faster since the return address is
already loaded.
---
 gcc/config/mn10300/mn10300-protos.h |    3 +-
 gcc/config/mn10300/mn10300.c        |   65 +++++++++++++++++++++++------------
 gcc/config/mn10300/mn10300.md       |   42 ++++++++--------------
 3 files changed, 61 insertions(+), 49 deletions(-)

diff --git a/gcc/config/mn10300/mn10300-protos.h b/gcc/config/mn10300/mn10300-protos.h
index c25ba9b..058f5df 100644
--- a/gcc/config/mn10300/mn10300-protos.h
+++ b/gcc/config/mn10300/mn10300-protos.h
@@ -45,7 +45,8 @@ extern bool  mn10300_match_ccmode (rtx, Mmode);
 #endif /* RTX_CODE */
 
 extern bool  mn10300_regno_in_class_p (unsigned, int, bool);
-extern int   mn10300_can_use_return_insn (void);
+extern bool  mn10300_can_use_rets_insn (void);
+extern bool  mn10300_can_use_retf_insn (void);
 extern void  mn10300_expand_prologue (void);
 extern void  mn10300_expand_epilogue (void);
 extern int   mn10300_initial_offset (int, int);
diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c
index 38a1c53..c56b896 100644
--- a/gcc/config/mn10300/mn10300.c
+++ b/gcc/config/mn10300/mn10300.c
@@ -623,8 +623,33 @@ mn10300_print_reg_list (FILE *file, int mask)
   fputc (']', file);
 }
 
-int
-mn10300_can_use_return_insn (void)
+/* If the MDR register is never clobbered, we can use the RETF instruction
+   which takes the address from the MDR register.  This is 3 cycles faster
+   than having to load the address from the stack.  */
+
+bool
+mn10300_can_use_retf_insn (void)
+{
+  /* Don't bother if we're not optimizing.  In this case we won't
+     have proper access to df_regs_ever_live_p.  */
+  if (!optimize)
+    return false;
+
+  /* EH returns alter the saved return address; MDR is not current.  */
+  if (crtl->calls_eh_return)
+    return false;
+
+  /* Obviously not if MDR is ever clobbered.  */
+  if (df_regs_ever_live_p (MDR_REG))
+    return false;
+
+  /* ??? Careful not to use this during expand_epilogue etc.  */
+  gcc_assert (!in_sequence_p ());
+  return leaf_function_p ();
+}
+
+bool
+mn10300_can_use_rets_insn (void)
 {
   return !mn10300_initial_offset (ARG_POINTER_REGNUM, STACK_POINTER_REGNUM);
 }
@@ -995,6 +1020,7 @@ void
 mn10300_expand_epilogue (void)
 {
   HOST_WIDE_INT size = mn10300_frame_size ();
+  int reg_save_bytes = REG_SAVE_BYTES;
   
   if (TARGET_AM33_2 && fp_regs_to_save ())
     {
@@ -1026,14 +1052,14 @@ mn10300_expand_epilogue (void)
 	  this_strategy_size = SIZE_FMOV_SP (size, num_regs_to_save);
 	  /* If size is too large, we'll have to adjust SP with an
 		 add.  */
-	  if (size + 4 * num_regs_to_save + REG_SAVE_BYTES > 255)
+	  if (size + 4 * num_regs_to_save + reg_save_bytes > 255)
 	    {
 	      /* Insn: add size + 4 * num_regs_to_save, sp.  */
 	      this_strategy_size += SIZE_ADD_SP (size + 4 * num_regs_to_save);
 	    }
 	  /* If we don't have to restore any non-FP registers,
 		 we'll be able to save one byte by using rets.  */
-	  if (! REG_SAVE_BYTES)
+	  if (! reg_save_bytes)
 	    this_strategy_size--;
 
 	  if (this_strategy_size < strategy_size)
@@ -1060,14 +1086,14 @@ mn10300_expand_epilogue (void)
 	     When size is close to 32Kb, we may be able to adjust SP
 	     with an imm16 add instruction while still using fmov
 	     (d8,sp).  */
-	  if (size + 4 * num_regs_to_save + REG_SAVE_BYTES > 255)
+	  if (size + 4 * num_regs_to_save + reg_save_bytes > 255)
 	    {
 	      /* Insn: add size + 4 * num_regs_to_save
-				+ REG_SAVE_BYTES - 252,sp.  */
+				+ reg_save_bytes - 252,sp.  */
 	      this_strategy_size = SIZE_ADD_SP (size + 4 * num_regs_to_save
-						+ REG_SAVE_BYTES - 252);
+						+ reg_save_bytes - 252);
 	      /* Insn: fmov (##,sp),fs#, fo each fs# to be restored.  */
-	      this_strategy_size += SIZE_FMOV_SP (252 - REG_SAVE_BYTES
+	      this_strategy_size += SIZE_FMOV_SP (252 - reg_save_bytes
 						  - 4 * num_regs_to_save,
 						  num_regs_to_save);
 	      /* We're going to use ret to release the FP registers
@@ -1096,14 +1122,14 @@ mn10300_expand_epilogue (void)
 	      this_strategy_size += 3 * num_regs_to_save;
 	      /* If size is large enough, we may be able to save a
 		 couple of bytes.  */
-	      if (size + 4 * num_regs_to_save + REG_SAVE_BYTES > 255)
+	      if (size + 4 * num_regs_to_save + reg_save_bytes > 255)
 		{
 		  /* Insn: mov a1,sp.  */
 		  this_strategy_size += 2;
 		}
 	      /* If we don't have to restore any non-FP registers,
 		 we'll be able to save one byte by using rets.  */
-	      if (! REG_SAVE_BYTES)
+	      if (! reg_save_bytes)
 		this_strategy_size--;
 
 	      if (this_strategy_size < strategy_size)
@@ -1129,8 +1155,8 @@ mn10300_expand_epilogue (void)
 	      emit_insn (gen_addsi3 (stack_pointer_rtx,
 				     stack_pointer_rtx,
 				     GEN_INT (size + 4 * num_regs_to_save
-					      + REG_SAVE_BYTES - 252)));
-	      size = 252 - REG_SAVE_BYTES - 4 * num_regs_to_save;
+					      + reg_save_bytes - 252)));
+	      size = 252 - reg_save_bytes - 4 * num_regs_to_save;
 	      break;
 
 	    case restore_a1:
@@ -1176,7 +1202,7 @@ mn10300_expand_epilogue (void)
       /* If we were using the restore_a1 strategy and the number of
 	 bytes to be released won't fit in the `ret' byte, copy `a1'
 	 to `sp', to avoid having to use `add' to adjust it.  */
-      if (! frame_pointer_needed && reg && size + REG_SAVE_BYTES > 255)
+      if (! frame_pointer_needed && reg && size + reg_save_bytes > 255)
 	{
 	  emit_move_insn (stack_pointer_rtx, XEXP (reg, 0));
 	  size = 0;
@@ -1203,7 +1229,7 @@ mn10300_expand_epilogue (void)
       emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
       size = 0;
     }
-  else if (size + REG_SAVE_BYTES > 255)
+  else if (size + reg_save_bytes > 255)
     {
       emit_insn (gen_addsi3 (stack_pointer_rtx,
 			     stack_pointer_rtx,
@@ -1212,15 +1238,10 @@ mn10300_expand_epilogue (void)
     }
 
   /* Adjust the stack and restore callee-saved registers, if any.  */
-  if (size || df_regs_ever_live_p (2) || df_regs_ever_live_p (3)
-      || df_regs_ever_live_p (6) || df_regs_ever_live_p (7)
-      || df_regs_ever_live_p (14) || df_regs_ever_live_p (15)
-      || df_regs_ever_live_p (16) || df_regs_ever_live_p (17)
-      || frame_pointer_needed)
-    emit_jump_insn (gen_return_internal_regs
-		    (GEN_INT (size + REG_SAVE_BYTES)));
+  if (mn10300_can_use_rets_insn ())
+    emit_jump_insn (gen_rtx_RETURN (VOIDmode));
   else
-    emit_jump_insn (gen_return_internal ());
+    emit_jump_insn (gen_return_ret (GEN_INT (size + REG_SAVE_BYTES)));
 }
 
 /* Recognize the PARALLEL rtx generated by mn10300_gen_multiple_store().
diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md
index 0f04a41..fae87e9 100644
--- a/gcc/config/mn10300/mn10300.md
+++ b/gcc/config/mn10300/mn10300.md
@@ -1598,31 +1598,28 @@
   { mn10300_expand_epilogue (); DONE; }
 )
 
-(define_insn "return_internal"
-  [(const_int 2)
-   (return)]
-  ""
-  "rets"
-  [(set_attr "timings" "66")]
-)
+(define_insn "return"
+  [(return)]
+  "mn10300_can_use_rets_insn ()"
+{
+  /* The RETF insn is 4 cycles faster than RETS, though 1 byte larger.  */
+  if (optimize_insn_for_speed_p () && mn10300_can_use_retf_insn ())
+    return "retf [],0";
+  else
+    return "rets";
+})
 
-;; This insn restores the callee saved registers and does a return, it
-;; can also deallocate stack space.
-(define_insn "return_internal_regs"
-  [(const_int 0)
-   (match_operand:SI 0  "const_int_operand" "i")
-   (return)]
+(define_insn "return_ret"
+  [(return)
+   (use (match_operand:SI 0 "const_int_operand" ""))]
   ""
 {
-  fputs ("\tret ", asm_out_file);
+  /* The RETF insn is up to 3 cycles faster than RET.  */
+  fputs ((mn10300_can_use_retf_insn () ? "\tretf " : "\tret "), asm_out_file);
   mn10300_print_reg_list (asm_out_file, mn10300_get_live_callee_saved_regs ());
   fprintf (asm_out_file, ",%d\n", (int) INTVAL (operands[0]));
   return "";
-}
-  ;; Assumes that there will be no more than 8 regs to pop
-  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
-				       (const_int 1414) (const_int 1313)))]
-)
+})
 
 ;; This instruction matches one generated by mn10300_gen_multiple_store()
 (define_insn "store_movm"
@@ -1642,13 +1639,6 @@
 				       (const_int 99) (const_int 88)))]
 )
 
-(define_insn "return"
-  [(return)]
-  "mn10300_can_use_return_insn ()"
-  "rets"
-  [(set_attr "timings" "66")]
-)
-
 (define_expand "load_pic"
   [(const_int 0)]
   "flag_pic"
-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 90+ messages in thread

* [PATCH 05/28] mn10300: Fix debug offsets into the stack frame
  2011-01-10 20:33 [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Richard Henderson
                   ` (12 preceding siblings ...)
  2011-01-10 20:33 ` [PATCH 23/28] mn10300: Add delegitimize_address hook Richard Henderson
@ 2011-01-10 20:34 ` Richard Henderson
  2011-01-11 14:50   ` Jeff Law
  2011-01-10 20:34 ` [PATCH 11/28] mn10300: Clean up costing Richard Henderson
                   ` (15 subsequent siblings)
  29 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-10 20:34 UTC (permalink / raw)
  To: gcc-patches; +Cc: nickc, law, Richard Henderson

From: Richard Henderson <rth@twiddle.net>

We were using debugging hooks to semi-correct a mistake
in the lack of ARG_POINTER_CFA_OFFSET.
---
 gcc/config/mn10300/mn10300.h |   29 +++--------------------------
 1 files changed, 3 insertions(+), 26 deletions(-)

diff --git a/gcc/config/mn10300/mn10300.h b/gcc/config/mn10300/mn10300.h
index 468c031..60d7d43 100644
--- a/gcc/config/mn10300/mn10300.h
+++ b/gcc/config/mn10300/mn10300.h
@@ -463,6 +463,9 @@ enum reg_class
 
 #define FIRST_PARM_OFFSET(FNDECL) 4
 
+/* But the CFA is at the arg pointer directly, not at the first argument.  */
+#define ARG_POINTER_CFA_OFFSET(FNDECL) 0
+
 #define ELIMINABLE_REGS				\
 {{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM},	\
  { ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM},	\
@@ -731,34 +734,8 @@ struct cum_arg
 #undef  PREFERRED_DEBUGGING_TYPE
 #define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
 #define DWARF2_DEBUGGING_INFO 1
-
 #define DWARF2_ASM_LINE_DEBUG_INFO 1
 
-/* GDB always assumes the current function's frame begins at the value
-   of the stack pointer upon entry to the current function.  Accessing
-   local variables and parameters passed on the stack is done using the
-   base of the frame + an offset provided by GCC.
-
-   For functions which have frame pointers this method works fine;
-   the (frame pointer) == (stack pointer at function entry) and GCC provides
-   an offset relative to the frame pointer.
-
-   This loses for functions without a frame pointer; GCC provides an offset
-   which is relative to the stack pointer after adjusting for the function's
-   frame size.  GDB would prefer the offset to be relative to the value of
-   the stack pointer at the function's entry.  Yuk!  */
-#define DEBUGGER_AUTO_OFFSET(X) \
-  ((GET_CODE (X) == PLUS ? INTVAL (XEXP (X, 1)) : 0) \
-    + (frame_pointer_needed \
-       ? 0 : - mn10300_initial_offset (FRAME_POINTER_REGNUM, \
-				       STACK_POINTER_REGNUM)))
-
-#define DEBUGGER_ARG_OFFSET(OFFSET, X) \
-  ((GET_CODE (X) == PLUS ? OFFSET : 0) \
-    + (frame_pointer_needed \
-       ? 0 : - mn10300_initial_offset (ARG_POINTER_REGNUM, \
-				       STACK_POINTER_REGNUM)))
-
 /* Specify the machine mode that this machine uses
    for the index in the tablejump instruction.  */
 #define CASE_VECTOR_MODE Pmode
-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 90+ messages in thread

* [PATCH 16/28] mn10300: Expose the MDR register to register allocation.
  2011-01-10 20:33 [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Richard Henderson
                   ` (25 preceding siblings ...)
  2011-01-10 20:34 ` [PATCH 14/28] mn10300: Cleanup legitimate addresses Richard Henderson
@ 2011-01-10 20:39 ` Richard Henderson
  2011-01-18 17:56   ` Jeff Law
  2011-01-10 20:44 ` [PATCH 19/28] mn10300: tidy pic address loading Richard Henderson
                   ` (2 subsequent siblings)
  29 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-10 20:39 UTC (permalink / raw)
  To: gcc-patches; +Cc: nickc, law, Richard Henderson

From: Richard Henderson <rth@twiddle.net>

Note that nothing uses the "z" constraint yet except the one
move pattern; this merely defines the register class properly.
---
 gcc/config/mn10300/constraints.md |    3 ++
 gcc/config/mn10300/mn10300.c      |   10 ++++++++
 gcc/config/mn10300/mn10300.h      |   44 ++++++++++++++++++++++++++-----------
 gcc/config/mn10300/mn10300.md     |   17 +++++++++-----
 4 files changed, 55 insertions(+), 19 deletions(-)

diff --git a/gcc/config/mn10300/constraints.md b/gcc/config/mn10300/constraints.md
index 0f7f45b..a4816c1 100644
--- a/gcc/config/mn10300/constraints.md
+++ b/gcc/config/mn10300/constraints.md
@@ -35,6 +35,9 @@
 (define_register_constraint "y" "SP_REGS"
   "An SP register (if available).")
 
+(define_register_constraint "z" "MDR_REGS"
+  "The MDR register.")
+
 (define_register_constraint "x" "TARGET_AM33 ? EXTENDED_REGS : NO_REGS"
   "An extended register.")
 
diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c
index f9dab21..36c35ca 100644
--- a/gcc/config/mn10300/mn10300.c
+++ b/gcc/config/mn10300/mn10300.c
@@ -1416,6 +1416,12 @@ mn10300_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i,
       return NO_REGS;
     }
 
+  /* We can only move MDR to/from a data register.  */
+  if (rclass == MDR_REGS && xclass != DATA_REGS)
+    return DATA_REGS;
+  if (xclass == MDR_REGS && rclass != DATA_REGS)
+    return DATA_REGS;
+
   /* We can't load/store an FP register from a constant address.  */
   if (TARGET_AM33_2
       && (rclass == FP_REGS || xclass == FP_REGS)
@@ -2196,6 +2202,8 @@ mn10300_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
   test = from;
   if (to == SP_REGS)
     scratch = (TARGET_AM33 ? GENERAL_REGS : ADDRESS_REGS);
+  else if (to == MDR_REGS)
+    scratch = DATA_REGS;
   else if (to == FP_REGS && to != from)
     scratch = GENERAL_REGS;
   else
@@ -2203,6 +2211,8 @@ mn10300_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
       test = to;
       if (from == SP_REGS)
 	scratch = (TARGET_AM33 ? GENERAL_REGS : ADDRESS_REGS);
+      else if (from == MDR_REGS)
+	scratch = DATA_REGS;
       else if (from == FP_REGS && to != from)
 	scratch = GENERAL_REGS;
     }
diff --git a/gcc/config/mn10300/mn10300.h b/gcc/config/mn10300/mn10300.h
index 7a6f1a8..43bad54 100644
--- a/gcc/config/mn10300/mn10300.h
+++ b/gcc/config/mn10300/mn10300.h
@@ -157,7 +157,7 @@ extern enum processor_type mn10300_tune_cpu;
 #define LAST_EXTENDED_REGNUM  17
 #define FIRST_FP_REGNUM       18
 #define LAST_FP_REGNUM        49
-#define MDR_REGNUM            50
+/* #define MDR_REG            50 */
 /* #define CC_REG             51 */
 #define FIRST_ARGUMENT_REGNUM  0
 
@@ -182,9 +182,17 @@ extern enum processor_type mn10300_tune_cpu;
    and are not available for the register allocator.  */
 
 #define FIXED_REGISTERS \
-  { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 \
-  , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0	 \
-  , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 \
+  { 0, 0, 0, 0,				/* data regs */		\
+    0, 0, 0, 0,				/* addr regs */		\
+    1,					/* arg reg */		\
+    1,					/* sp reg */		\
+    0, 0, 0, 0, 0, 0, 0, 0,		/* extended regs */	\
+    0, 0,				/* fp regs (18-19) */	\
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* fp regs (20-29) */	\
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* fp regs (30-39) */	\
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* fp regs (40-49) */	\
+    0,					/* mdr reg */		\
+    1					/* cc reg */		\
   }
 
 /* 1 for registers not available across function calls.
@@ -196,9 +204,17 @@ extern enum processor_type mn10300_tune_cpu;
    like.  */
 
 #define CALL_USED_REGISTERS \
-  { 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 \
-  , 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0	 \
-  , 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 \
+  { 1, 1, 0, 0,				/* data regs */		\
+    1, 1, 0, 0,				/* addr regs */		\
+    1,					/* arg reg */		\
+    1,					/* sp reg */		\
+    1, 1, 1, 1, 0, 0, 0, 0,		/* extended regs */	\
+    1, 1,				/* fp regs (18-19) */	\
+    1, 1, 0, 0, 0, 0, 0, 0, 0, 0,	/* fp regs (20-29) */	\
+    0, 0, 0, 0, 0, 0, 0, 0, 1, 1,	/* fp regs (30-39) */	\
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	/* fp regs (40-49) */	\
+    1,					/* mdr reg */		\
+    1					/* cc reg */		\
   }
 
 /* Note: The definition of CALL_REALLY_USED_REGISTERS is not
@@ -211,7 +227,7 @@ extern enum processor_type mn10300_tune_cpu;
 #define REG_ALLOC_ORDER \
   { 0, 1, 4, 5, 2, 3, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 8, 9 \
   , 42, 43, 44, 45, 46, 47, 48, 49, 34, 35, 36, 37, 38, 39, 40, 41 \
-  , 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 51 \
+  , 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 50, 51 \
   }
 
 /* Return number of consecutive hard regs needed starting at reg REGNO
@@ -262,7 +278,7 @@ extern enum processor_type mn10300_tune_cpu;
 enum reg_class
 {
   NO_REGS, DATA_REGS, ADDRESS_REGS, SP_REGS, SP_OR_ADDRESS_REGS,
-  EXTENDED_REGS, FP_REGS, FP_ACC_REGS, CC_REGS,
+  EXTENDED_REGS, FP_REGS, FP_ACC_REGS, CC_REGS, MDR_REGS,
   GENERAL_REGS, SP_OR_GENERAL_REGS, ALL_REGS, LIM_REG_CLASSES
 };
 
@@ -270,10 +286,10 @@ enum reg_class
 
 /* Give names of register classes as strings for dump file.  */
 
-#define REG_CLASS_NAMES					   	\
+#define REG_CLASS_NAMES					   		\
 { "NO_REGS", "DATA_REGS", "ADDRESS_REGS", "SP_REGS", "SP_OR_ADDRESS_REGS", \
-  "EXTENDED_REGS", "FP_REGS", "FP_ACC_REGS", "CC_REGS",		\
-  "GENERAL_REGS", "SP_OR_GENERAL_REGS", "ALL_REGS", "LIM_REGS"	\
+  "EXTENDED_REGS", "FP_REGS", "FP_ACC_REGS", "CC_REGS", "MDR_REGS",	\
+  "GENERAL_REGS", "SP_OR_GENERAL_REGS", "ALL_REGS", "LIM_REGS"		\
 }
 
 /* Define which registers fit in which classes.
@@ -290,6 +306,7 @@ enum reg_class
   { 0xfffc0000, 0x3ffff },/* FP_REGS */				\
   { 0x03fc0000, 0 },	  /* FP_ACC_REGS */			\
   { 0x00000000, 0x80000 },/* CC_REGS */				\
+  { 0x00000000, 0x40000 },/* MDR_REGS */			\
   { 0x0003fdff, 0 }, 	  /* GENERAL_REGS */			\
   { 0x0003ffff, 0 },      /* SP_OR_GENERAL_REGS */		\
   { 0xffffffff, 0xfffff } /* ALL_REGS */			\
@@ -305,7 +322,7 @@ enum reg_class
 
 #define IRA_COVER_CLASSES					\
 {								\
-  GENERAL_REGS, FP_REGS, LIM_REG_CLASSES			\
+  GENERAL_REGS, FP_REGS, MDR_REGS, LIM_REG_CLASSES		\
 }
 
 /* The same information, inverted:
@@ -319,6 +336,7 @@ enum reg_class
    (REGNO) == STACK_POINTER_REGNUM ? SP_REGS :	     \
    (REGNO) <= LAST_EXTENDED_REGNUM ? EXTENDED_REGS : \
    (REGNO) <= LAST_FP_REGNUM ? FP_REGS :	     \
+   (REGNO) == MDR_REG ? MDR_REGS :		     \
    (REGNO) == CC_REG ? CC_REGS :		     \
    NO_REGS)
 
diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md
index 457b17a..86f26728 100644
--- a/gcc/config/mn10300/mn10300.md
+++ b/gcc/config/mn10300/mn10300.md
@@ -26,9 +26,10 @@
 ;; See file "rtl.def" for documentation on define_insn, match_*, et. al.
 
 (define_constants [
-  (PIC_REG 6)
-  (SP_REG  9)
-  (CC_REG 51)
+  (PIC_REG   6)
+  (SP_REG    9)
+  (MDR_REG  50)
+  (CC_REG   51)
 
   (UNSPEC_INT_LABEL	0)
   (UNSPEC_PIC		1)
@@ -375,9 +376,9 @@
 
 (define_insn "*movsi_internal"
   [(set (match_operand:SI 0 "nonimmediate_operand"
-			  "=r,r,r,m,r, A,*y,*y")
+			  "=r,r,r,m,r, A,*y,*y,*z,*d")
 	(match_operand:SI 1 "general_operand"
-			  " 0,i,r,r,m,*y, A, i"))]
+			  " 0,i,r,r,m,*y, A, i,*d,*z"))]
   "register_operand (operands[0], SImode)
    || register_operand (operands[1], SImode)"
 {
@@ -400,12 +401,14 @@
     case 5:  /* sp-reg */
     case 6:  /* reg-sp */
     case 7:  /* imm-sp */
+    case 8:  /* reg-mdr */
+    case 9:  /* mdr-reg */
       return "mov %1,%0";
     default:
       gcc_unreachable ();
     }
 }
-  [(set_attr "isa" "*,*,*,*,*,*,*,am33")
+  [(set_attr "isa" "*,*,*,*,*,*,*,am33,*,*")
    (set_attr_alternative "timings"
 	 [(const_int 11)
 	  (const_int 22)
@@ -419,6 +422,8 @@
 	  (if_then_else (eq_attr "cpu" "am34")
 			(const_int 13) (const_int 24))
 	  (const_int 11)
+	  (const_int 11)
+	  (const_int 11)
 	 ])]
 )
 
-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 90+ messages in thread

* [PATCH 19/28] mn10300: tidy pic address loading
  2011-01-10 20:33 [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Richard Henderson
                   ` (26 preceding siblings ...)
  2011-01-10 20:39 ` [PATCH 16/28] mn10300: Expose the MDR register to register allocation Richard Henderson
@ 2011-01-10 20:44 ` Richard Henderson
  2011-01-19 16:44   ` Jeff Law
  2011-01-11 14:20 ` [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Nick Clifton
  2011-01-11 18:31 ` Richard Henderson
  29 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-10 20:44 UTC (permalink / raw)
  To: gcc-patches; +Cc: nickc, law, Richard Henderson

From: Richard Henderson <rth@twiddle.net>

There's little reason to greatly complicate things by splitting
the pic_load patterns and using complex rtl to make it work out.
Instead, use the %= marker to generate unique numbers and emit
the entire load_pic sequence at once.

At the same time, collect all references to outgoing_args_size
into mn10300_frame_size, and all computations of register save
area size into mn10300_initial_offset.
---
 gcc/config/mn10300/mn10300-protos.h |    1 +
 gcc/config/mn10300/mn10300.c        |  107 +++++-------------
 gcc/config/mn10300/mn10300.h        |    2 -
 gcc/config/mn10300/mn10300.md       |  207 ++++++++++++-----------------------
 4 files changed, 99 insertions(+), 218 deletions(-)

diff --git a/gcc/config/mn10300/mn10300-protos.h b/gcc/config/mn10300/mn10300-protos.h
index 28a9412..c25ba9b 100644
--- a/gcc/config/mn10300/mn10300-protos.h
+++ b/gcc/config/mn10300/mn10300-protos.h
@@ -49,6 +49,7 @@ extern int   mn10300_can_use_return_insn (void);
 extern void  mn10300_expand_prologue (void);
 extern void  mn10300_expand_epilogue (void);
 extern int   mn10300_initial_offset (int, int);
+extern int   mn10300_frame_size (void);
 
 #undef Mmode
 #undef Cstar
diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c
index 8e62a0c..38a1c53 100644
--- a/gcc/config/mn10300/mn10300.c
+++ b/gcc/config/mn10300/mn10300.c
@@ -44,10 +44,6 @@
 #include "target-def.h"
 #include "df.h"
 
-/* This is used by GOTaddr2picreg to uniquely identify
-   UNSPEC_INT_LABELs.  */
-int mn10300_unspec_int_label_counter;
-
 /* This is used in the am33_2.0-linux-gnu port, in which global symbol
    names are not prefixed by underscores, to tell whether to prefix a
    label with a plus sign or not, so that the assembler can tell
@@ -544,10 +540,6 @@ mn10300_asm_output_addr_const_extra (FILE *file, rtx x)
     {
       switch (XINT (x, 1))
 	{
-	case UNSPEC_INT_LABEL:
-	  asm_fprintf (file, ".%LLIL" HOST_WIDE_INT_PRINT_DEC,
-		       INTVAL (XVECEXP (x, 0, 0)));
-	  break;
 	case UNSPEC_PIC:
 	  /* GLOBAL_OFFSET_TABLE or local symbols, no suffix.  */
 	  output_addr_const (file, XVECEXP (x, 0, 0));
@@ -634,24 +626,7 @@ mn10300_print_reg_list (FILE *file, int mask)
 int
 mn10300_can_use_return_insn (void)
 {
-  /* size includes the fixed stack space needed for function calls.  */
-  int size = get_frame_size () + crtl->outgoing_args_size;
-
-  /* And space for the return pointer.  */
-  size += crtl->outgoing_args_size ? 4 : 0;
-
-  return (reload_completed
-	  && size == 0
-	  && !df_regs_ever_live_p (2)
-	  && !df_regs_ever_live_p (3)
-	  && !df_regs_ever_live_p (6)
-	  && !df_regs_ever_live_p (7)
-	  && !df_regs_ever_live_p (14)
-	  && !df_regs_ever_live_p (15)
-	  && !df_regs_ever_live_p (16)
-	  && !df_regs_ever_live_p (17)
-	  && fp_regs_to_save () == 0
-	  && !frame_pointer_needed);
+  return !mn10300_initial_offset (ARG_POINTER_REGNUM, STACK_POINTER_REGNUM);
 }
 
 /* Returns the set of live, callee-saved registers as a bitmask.  The
@@ -760,11 +735,7 @@ mn10300_gen_multiple_store (unsigned int mask)
 void
 mn10300_expand_prologue (void)
 {
-  HOST_WIDE_INT size;
-
-  /* SIZE includes the fixed stack space needed for function calls.  */
-  size = get_frame_size () + crtl->outgoing_args_size;
-  size += (crtl->outgoing_args_size ? 4 : 0);
+  HOST_WIDE_INT size = mn10300_frame_size ();
 
   /* If we use any of the callee-saved registers, save them now.  */
   mn10300_gen_multiple_store (mn10300_get_live_callee_saved_regs ());
@@ -1017,17 +988,13 @@ mn10300_expand_prologue (void)
 			      GEN_INT (-size))));
 
   if (flag_pic && df_regs_ever_live_p (PIC_OFFSET_TABLE_REGNUM))
-    emit_insn (gen_GOTaddr2picreg ());
+    emit_insn (gen_load_pic ());
 }
 
 void
 mn10300_expand_epilogue (void)
 {
-  HOST_WIDE_INT size;
-
-  /* SIZE includes the fixed stack space needed for function calls.  */
-  size = get_frame_size () + crtl->outgoing_args_size;
-  size += (crtl->outgoing_args_size ? 4 : 0);
+  HOST_WIDE_INT size = mn10300_frame_size ();
   
   if (TARGET_AM33_2 && fp_regs_to_save ())
     {
@@ -1442,54 +1409,37 @@ mn10300_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i,
 }
 
 int
+mn10300_frame_size (void)
+{
+  /* size includes the fixed stack space needed for function calls.  */
+  int size = get_frame_size () + crtl->outgoing_args_size;
+
+  /* And space for the return pointer.  */
+  size += crtl->outgoing_args_size ? 4 : 0;
+
+  return size;
+}
+
+int
 mn10300_initial_offset (int from, int to)
 {
+  int diff = 0;
+
+  gcc_assert (from == ARG_POINTER_REGNUM || from == FRAME_POINTER_REGNUM);
+  gcc_assert (to == FRAME_POINTER_REGNUM || to == STACK_POINTER_REGNUM);
+
+  if (to == STACK_POINTER_REGNUM)
+    diff = mn10300_frame_size ();
+
   /* The difference between the argument pointer and the frame pointer
      is the size of the callee register save area.  */
-  if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
+  if (from == ARG_POINTER_REGNUM)
     {
-      if (df_regs_ever_live_p (2) || df_regs_ever_live_p (3)
-	  || df_regs_ever_live_p (6) || df_regs_ever_live_p (7)
-	  || df_regs_ever_live_p (14) || df_regs_ever_live_p (15)
-	  || df_regs_ever_live_p (16) || df_regs_ever_live_p (17)
-	  || fp_regs_to_save ()
-	  || frame_pointer_needed)
-	return REG_SAVE_BYTES
-	  + 4 * fp_regs_to_save ();
-      else
-	return 0;
+      diff += REG_SAVE_BYTES;
+      diff += 4 * fp_regs_to_save ();
     }
 
-  /* The difference between the argument pointer and the stack pointer is
-     the sum of the size of this function's frame, the callee register save
-     area, and the fixed stack space needed for function calls (if any).  */
-  if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
-    {
-      if (df_regs_ever_live_p (2) || df_regs_ever_live_p (3)
-	  || df_regs_ever_live_p (6) || df_regs_ever_live_p (7)
-	  || df_regs_ever_live_p (14) || df_regs_ever_live_p (15)
-	  || df_regs_ever_live_p (16) || df_regs_ever_live_p (17)
-	  || fp_regs_to_save ()
-	  || frame_pointer_needed)
-	return (get_frame_size () + REG_SAVE_BYTES
-		+ 4 * fp_regs_to_save ()
-		+ (crtl->outgoing_args_size
-		   ? crtl->outgoing_args_size + 4 : 0));
-      else
-	return (get_frame_size ()
-		+ (crtl->outgoing_args_size
-		   ? crtl->outgoing_args_size + 4 : 0));
-    }
-
-  /* The difference between the frame pointer and stack pointer is the sum
-     of the size of this function's frame and the fixed stack space needed
-     for function calls (if any).  */
-  if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
-    return (get_frame_size ()
-	    + (crtl->outgoing_args_size
-	       ? crtl->outgoing_args_size + 4 : 0));
-
-  gcc_unreachable ();
+  return diff;
 }
 
 /* Worker function for TARGET_RETURN_IN_MEMORY.  */
@@ -2087,7 +2037,6 @@ mn10300_legitimate_constant_p (rtx x)
 	{
 	  switch (XINT (x, 1))
 	    {
-	    case UNSPEC_INT_LABEL:
 	    case UNSPEC_PIC:
 	    case UNSPEC_GOT:
 	    case UNSPEC_GOTOFF:
diff --git a/gcc/config/mn10300/mn10300.h b/gcc/config/mn10300/mn10300.h
index 34ff2ae..fe6f754 100644
--- a/gcc/config/mn10300/mn10300.h
+++ b/gcc/config/mn10300/mn10300.h
@@ -53,8 +53,6 @@
     }						\
   while (0)
 
-extern GTY(()) int mn10300_unspec_int_label_counter;
-
 enum processor_type
 {
   PROCESSOR_MN10300,
diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md
index 965c6558..24c8d11 100644
--- a/gcc/config/mn10300/mn10300.md
+++ b/gcc/config/mn10300/mn10300.md
@@ -31,7 +31,6 @@
   (MDR_REG  50)
   (CC_REG   51)
 
-  (UNSPEC_INT_LABEL	0)
   (UNSPEC_PIC		1)
   (UNSPEC_GOT		2)
   (UNSPEC_GOTOFF	3)
@@ -284,7 +283,6 @@
 	(match_operand:SI     1 "impossible_plus_operand" ""))
    (clobber (match_operand:SI 2 "register_operand" "=&A"))]
   ""
-  "
 {
   rtx dest, scratch, other;
 
@@ -326,16 +324,7 @@
 	emit_move_insn (dest, scratch);
     }
   DONE;
-}")
-
-(define_insn "pop_pic_reg"
-  [(set (reg:SI PIC_REG)
-	(mem:SI (post_inc:SI (reg:SI SP_REG))))]
-  "reload_completed"
-  "movm (sp),[a2]"
-  [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
-				       (const_int 44) (const_int 33)))]
-)
+})
 
 (define_expand "movsi"
   [(set (match_operand:SI 0 "nonimmediate_operand")
@@ -1106,13 +1095,10 @@
 (define_expand "builtin_setjmp_receiver"
   [(match_operand 0 "" "")]
   "flag_pic"
-  "
 {
-  if (flag_pic)
-    emit_insn (gen_GOTaddr2picreg ());
-
+  emit_insn (gen_load_pic ());
   DONE;
-}")
+})
 
 (define_expand "casesi"
   [(match_operand:SI 0 "register_operand")
@@ -1555,16 +1541,14 @@
 (define_expand "prologue"
   [(const_int 0)]
   ""
-  "mn10300_expand_prologue (); DONE;")
+  { mn10300_expand_prologue (); DONE; }
+)
 
 (define_expand "epilogue"
   [(return)]
   ""
-  "
-  {
-    mn10300_expand_epilogue ();
-    DONE;
-  }")
+  { mn10300_expand_epilogue (); DONE; }
+)
 
 (define_insn "return_internal"
   [(const_int 2)
@@ -1581,13 +1565,12 @@
    (match_operand:SI 0  "const_int_operand" "i")
    (return)]
   ""
-  "*
-  {
-    fputs (\"\\tret \", asm_out_file);
-    mn10300_print_reg_list (asm_out_file, mn10300_get_live_callee_saved_regs ());
-    fprintf (asm_out_file, \",%d\\n\", (int) INTVAL (operands[0]));
-    return \"\";
-  }"
+{
+  fputs ("\tret ", asm_out_file);
+  mn10300_print_reg_list (asm_out_file, mn10300_get_live_callee_saved_regs ());
+  fprintf (asm_out_file, ",%d\n", (int) INTVAL (operands[0]));
+  return "";
+}
   ;; Assumes that there will be no more than 8 regs to pop
   [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
 				       (const_int 1414) (const_int 1313)))]
@@ -1598,15 +1581,14 @@
   [(match_parallel 0 "mn10300_store_multiple_operation"
     [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (match_operand 1 "" "")))])]
   ""
-  "*
-  {
-    fputs (\"\\tmovm \", asm_out_file);
-    mn10300_print_reg_list (asm_out_file,
-                            mn10300_store_multiple_operation (operands[0],
-						              VOIDmode));
-    fprintf (asm_out_file, \",(sp)\\n\");
-    return \"\";
-  }"
+{
+  fputs ("\tmovm ", asm_out_file);
+  mn10300_print_reg_list (asm_out_file,
+                          mn10300_store_multiple_operation (operands[0],
+						            VOIDmode));
+  fprintf (asm_out_file, ",(sp)\n");
+  return "";
+}
   ;; Assume that no more than 8 registers will be pushed.
   [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
 				       (const_int 99) (const_int 88)))]
@@ -1615,116 +1597,67 @@
 (define_insn "return"
   [(return)]
   "mn10300_can_use_return_insn ()"
-  "*
-{
-  rtx next = next_active_insn (insn);
-
-  if (next
-      && JUMP_P (next)
-      && GET_CODE (PATTERN (next)) == RETURN)
-    return \"\";
-  else
-    return \"rets\";
-}"
+  "rets"
   [(set_attr "timings" "66")]
 )
 
-(define_expand "int_label"
-  [(unspec [(match_operand:SI 0 "" "")] UNSPEC_INT_LABEL)]
-  "" "")
-
-(define_expand "GOTaddr2picreg"
-  [(match_dup 0)]
-  "" "
+(define_expand "load_pic"
+  [(const_int 0)]
+  "flag_pic"
 {
-  /* It would be nice to be able to have int_label keep track of the
-     counter and all, but if we add C code to it, we'll get an insn
-     back, and we just want the pattern.  */
-  operands[0] = gen_int_label (GEN_INT (mn10300_unspec_int_label_counter++));
   if (TARGET_AM33)
-    emit_insn (gen_am33_loadPC (operands[0]));
+    emit_insn (gen_am33_load_pic (pic_offset_table_rtx));
+  else if (mn10300_frame_size () == 0)
+    emit_insn (gen_mn10300_load_pic0 (pic_offset_table_rtx));
   else
-    emit_insn (gen_mn10300_loadPC (operands[0]));
-  emit_insn (gen_add_GOT_to_pic_reg (copy_rtx (operands[0])));
+    emit_insn (gen_mn10300_load_pic1 (pic_offset_table_rtx));
   DONE;
-}
-")
+})
 
-(define_insn "am33_loadPC"
-  [(parallel
-    [(set (reg:SI PIC_REG) (pc))
-     (use (match_operand 0 "" ""))])]
+(define_insn "am33_load_pic"
+  [(set (match_operand:SI 0 "register_operand" "=a")
+	(unspec:SI [(const_int 0)] UNSPEC_GOT))
+   (clobber (reg:CC CC_REG))]
   "TARGET_AM33"
-  "%0:\;mov pc,a2"
+{
+  operands[1] = gen_rtx_SYMBOL_REF (VOIDmode, GOT_SYMBOL_NAME);
+  return ".LPIC%=:\;mov pc,%0\;add %1-(.LPIC%=-.),%0";
+}
+  [(set_attr "timings" "33")]
 )
 
-(define_insn_and_split "mn10300_loadPC"
-  [(parallel
-    [(set (reg:SI PIC_REG) (pc))
-     (use (match_operand 0 "" ""))])]
-  "! TARGET_AM33"
-  "#"
-  "&& reload_completed"
-  [(match_operand 0 "" "")]
-  {
-    rtx sp_reg = gen_rtx_REG (SImode, SP_REG);
-    int need_stack_space = (get_frame_size () == 0
-	                    && crtl->outgoing_args_size == 0);
-
-    if (need_stack_space)
-      emit_insn (gen_addsi3 (sp_reg, sp_reg, GEN_INT (-4)));
-
-    emit_insn (gen_call_next_insn (operands[0]));
-
-    if (need_stack_space)
-      emit_insn (gen_pop_pic_reg ());
-    else
-      emit_move_insn (pic_offset_table_rtx, gen_rtx_MEM (SImode, sp_reg));
-    DONE;
-  }
+;; Load pic register with push/pop of stack.
+(define_insn "mn10300_load_pic0"
+  [(set (match_operand:SI 0 "register_operand" "=a")
+	(unspec:SI [(const_int 0)] UNSPEC_GOT))
+   (clobber (reg:SI MDR_REG))
+   (clobber (reg:CC CC_REG))]
+  ""
+{
+  operands[1] = gen_rtx_SYMBOL_REF (VOIDmode, GOT_SYMBOL_NAME);
+  return ("add -4,sp\;"
+	  "calls .LPIC%=\n"
+          ".LPIC%=:\;"
+	  "movm (sp),[%0]\;"
+	  "add %1-(.LPIC%=-.),%0");
+}
+  [(set_attr "timings" "88")]
 )
 
-(define_insn "call_next_insn"
-  [(parallel
-    [(set (mem:SI (reg:SI SP_REG)) (pc))
-     (use (match_operand 0 "" ""))])]
-  "reload_completed"
-  "calls %0\;%0:"
-  [(set_attr "timings" "44")]
-)
-
-(define_expand "add_GOT_to_pic_reg"
-  [(parallel [(set (reg:SI PIC_REG)
-		   (plus:SI
-		    (reg:SI PIC_REG)
-		    (const:SI
-		     (unspec:SI [(minus:SI
-			       (match_dup 1)
-			       (const (minus:SI
-				       (const (match_operand:SI 0 "" ""))
-				       (pc))))
-			      ] UNSPEC_PIC))))
-	      (clobber (reg:CC CC_REG))
-	      ])
-  ]
-  ""
-  "operands[1] = gen_rtx_SYMBOL_REF (VOIDmode, GOT_SYMBOL_NAME);"
-)
-
-(define_expand "add_GOT_to_any_reg"
-  [(parallel [(set (match_operand:SI 0 "" "")
-		   (plus:SI
-		    (match_operand:SI 1 "" "")
-		    (const
-		     (unspec [(minus:SI
-			       (match_dup 3)
-			       (const (minus:SI
-				       (const (match_operand:SI 2 "" ""))
-				       (pc))))
-			      ] UNSPEC_PIC))))
-	      (clobber (reg:CC CC_REG))
-	     ])
-  ]
+;; Load pic register re-using existing stack space.
+(define_insn "mn10300_load_pic1"
+  [(set (match_operand:SI 0 "register_operand" "=a")
+	(unspec:SI [(const_int 0)] UNSPEC_GOT))
+   (clobber (mem:SI (reg:SI SP_REG)))
+   (clobber (reg:SI MDR_REG))
+   (clobber (reg:CC CC_REG))]
   ""
-  "operands[3] = gen_rtx_SYMBOL_REF (VOIDmode, GOT_SYMBOL_NAME);"
+{
+  operands[1] = gen_rtx_SYMBOL_REF (VOIDmode, GOT_SYMBOL_NAME);
+  return ("calls .LPIC%=\n"
+	  ".LPIC%=:\;"
+          "mov (sp),%0\;"
+          "add %1-(.LPIC%=-.),%0");
+}
+  [(set_attr "timings" "66")]
 )
-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 00/28] mn10300 cleanup + compare-elim, v2
  2011-01-10 20:33 [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Richard Henderson
                   ` (27 preceding siblings ...)
  2011-01-10 20:44 ` [PATCH 19/28] mn10300: tidy pic address loading Richard Henderson
@ 2011-01-11 14:20 ` Nick Clifton
  2011-01-11 16:45   ` Richard Henderson
  2011-01-11 18:31 ` Richard Henderson
  29 siblings, 1 reply; 90+ messages in thread
From: Nick Clifton @ 2011-01-11 14:20 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, law, Richard Henderson

Hi Richard,

> Aka, how I spent my xmas vacation.  ;-)

Thanks dude. :-)

> It may now be too late for the inclusion of the compare-elim
> pass in 4.6, but I thought I'd post it anyway.  Some of the
> target cleanup work might still go in, and I certainly don't
> want Nick to duplicate work if he gets back to work on the port.

You have perfect timing - I was just about to start in on this again.

> Comments appreciated.


>    mn10300: delete ASM_PN_FORMAT
> Is there any real reason for this?

No.  I think that it is a hang over from basing the v850 port on a much 
older port.

Aside: I could not find ASM_PN_FORMAT documented anywhere in gcc/doc/*. 
  I did find the description of the ASM_FORMAT_PRIVATE_NAME macro, but 
no hint that ASM_PN_FORMAT could be used instead.


>    mn10300: fp insn cleanup

Just a very minor point:

> -   (clobber (reg:CC_FLOAT CC_REG))
> -  ]
> +   (clobber (reg:CC_FLOAT CC_REG))]

Is this a formatting requirement ?  It makes more sense to me to treat 
closing parentheses in the same way as they are treated in C code - ie 
with them on a line on their own directly underneath their corresponding 
opening parenthesis.  If it is a requirement though, then please accept 
my apologies for formatting the code incorrectly.


Anyway thank you very much for doing this work and I hope that you will 
be checking the patches in soon.

Cheers
   Nick

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 01/28] mn10300: Better definition of INCOMING_RETURN_ADDR_RTX.
  2011-01-10 20:32 ` [PATCH 01/28] mn10300: Better definition of INCOMING_RETURN_ADDR_RTX Richard Henderson
@ 2011-01-11 14:45   ` Jeff Law
  0 siblings, 0 replies; 90+ messages in thread
From: Jeff Law @ 2011-01-11 14:45 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, Richard Henderson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/10/11 13:31, Richard Henderson wrote:
> From: Richard Henderson <rth@twiddle.net>
> 
> The new definition is more useful to the unwinder.
> ---
>  gcc/config/mn10300/mn10300.h |    5 ++++-
>  1 files changed, 4 insertions(+), 1 deletions(-)
> 
> diff --git a/gcc/config/mn10300/mn10300.h b/gcc/config/mn10300/mn10300.h
> index 67516b6..edc17f5 100644
> --- a/gcc/config/mn10300/mn10300.h
> +++ b/gcc/config/mn10300/mn10300.h
> @@ -548,7 +548,10 @@ struct cum_arg
>     ? gen_rtx_MEM (Pmode, arg_pointer_rtx) \
>     : (rtx) 0)
>  
> -#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (Pmode, MDR_REGNUM)
> +/* The return address is saved both in the stack and in MDR.  Using
> +   the stack location is handiest for what unwinding needs.  */
> +#define INCOMING_RETURN_ADDR_RTX \
> +  gen_rtx_MEM (VOIDmode, gen_rtx_REG (VOIDmode, STACK_POINTER_REGNUM))
>  \f
>  /* Maximum number of registers that can appear in a valid memory address.  */
>  
Seems reasonable.

Jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNLGyCAAoJEBRtltQi2kC7kN4H/2uZItrFa8y8tG80dtmlwcUs
jib9TXFH/KFH0ZPmC5Vg6xPinmAbs3LgGpVpxsqIn4Pa8bWECC7IelKTrp/xBz14
KGLb85UIeDp7KRiROR0Ym4KL84fDSFIx2ecefK8MdoIloJRk+xk9ky3vIoNWuHVV
4ghPOyFVpPSJ5HYREaKJ8BRDmgBhWm9w9RJ/HZeYkgz7PfdaXgY8CnGMTAFoclcP
AudmZekYI65PwQ4n7PKByQ4eoErvY/Se0pKJ1BP2jJO5+jPeEBWJAq1rStdTanrl
jmCzwedmvOAlm4HHY8RcxNQvE+PUKUQeQ0Td6RG3buthtRHW/UtsV+UwqjAdDns=
=Yf48
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 06/28] mn10300: fp insn cleanup
  2011-01-10 20:33 ` [PATCH 06/28] mn10300: fp insn cleanup Richard Henderson
@ 2011-01-11 14:46   ` Jeff Law
  0 siblings, 0 replies; 90+ messages in thread
From: Jeff Law @ 2011-01-11 14:46 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, Richard Henderson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/10/11 13:31, Richard Henderson wrote:
> From: Richard Henderson <rth@twiddle.net>
> 
> Delete integer-mode abssf2, negsf2; these will be handled
> by the middle-end now.  Delete unnecessary expanders.
OK.
Jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNLG0gAAoJEBRtltQi2kC7RdUH/1jap7OJYj0kffDf6U4ZG9QA
gMy8eaS7TX/syrBdHWmZF3QGtgctWzvEao3MlSBsUtDs+UO+zNFIduQ+xQskNAyi
WHxhlomMbBn2d7UfVAzOsqA+XWLe8aPotNQ4QsxFq+JZpBkqDOfoClpc0Qz3JWOI
RiolLwJGp66d8Lkri3hSD5/wa1e8SPdQ0QnY6ZhVbXYoZxIlQWacMJql9JU7QWqM
tdnsJh8neo4ogAEuNpuZfMnrixGbRrglvfD81ynpmW9o3fYgY56wBJaYRIz5z1VR
UDnr4YUR/U0sIZF56A8tkOJeIwaQXpVX1b5ITiBRWumS7i+wkDLh6Xge2+p4AzU=
=Yd+F
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 02/28] mn10300: disable test tree-ssa/vrp47.c
  2011-01-10 20:33 ` [PATCH 02/28] mn10300: disable test tree-ssa/vrp47.c Richard Henderson
@ 2011-01-11 14:46   ` Jeff Law
  0 siblings, 0 replies; 90+ messages in thread
From: Jeff Law @ 2011-01-11 14:46 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, Richard Henderson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/10/11 13:31, Richard Henderson wrote:
> From: Richard Henderson <rth@twiddle.net>
> 
> ---
>  gcc/testsuite/gcc.dg/tree-ssa/vrp47.c |    2 +-
>  1 files changed, 1 insertions(+), 1 deletions(-)
> 
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp47.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp47.c
> index 25b7720..3def90c 100644
> --- a/gcc/testsuite/gcc.dg/tree-ssa/vrp47.c
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp47.c
> @@ -3,7 +3,7 @@
>  /* Skip on S/390 and avr.  Lower values in BRANCH_COST lead to two conditional
>     jumps when evaluating an && condition.  VRP is not able to optimize
>     this.  */
> -/* { dg-do compile { target { ! "mips*-*-* s390*-*-*  avr-*-*" } } } */
> +/* { dg-do compile { target { ! "mips*-*-* s390*-*-*  avr-*-* mn10300-*-*" } } } */
>  /* { dg-options "-O2 -fdump-tree-vrp -fdump-tree-dom" } */
>  /* { dg-options "-O2 -fdump-tree-vrp -fdump-tree-dom -march=i586" { target { i?86-*-* && ilp32 } } } */
>  
OK.
Jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNLGyeAAoJEBRtltQi2kC7DPsH/ArCj7yzooGDnjjYDGrxn8Cm
CEN/E3aLhzvEsooRuvHqD2jv6C4ndAD68k2T7RE6Sq3oYHQEyyQI4+BMyMQRBeZ4
aGxqpt7XbV7F1Kl5doFItGNytQ6oudqjTWA3rZ7Jm5H70ym+cbI9P6nDky5UydIv
Xask5A4ESu1P2tAUSmpBo0NcOJmTfUiF6XD0HOFoQcEQBagHv1SHofnLyUdbMVUK
w2aIdqUxUFa7bVlDqBG4xQ9B+PePwiRNx5TKJKstRpUtelMwpFWaUhYHmDIIspDI
G85SB0dRtxNrE/2OO4WzFFktLhEobPkTsgvBcVB9mHKDO8T6+YEuaF+5Mjm/GGs=
=2gxO
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 03/28] mn10300: delete ASM_PN_FORMAT
  2011-01-10 20:34 ` [PATCH 03/28] mn10300: delete ASM_PN_FORMAT Richard Henderson
@ 2011-01-11 14:46   ` Jeff Law
  0 siblings, 0 replies; 90+ messages in thread
From: Jeff Law @ 2011-01-11 14:46 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, Richard Henderson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/10/11 13:31, Richard Henderson wrote:
> From: Richard Henderson <rth@twiddle.net>
> 
> Is there any real reason for this?  It causes testsuite failures
> because the pattern doesn't match many of the dumps.
> ---
>  gcc/config/mn10300/mn10300.h |    3 +++
>  1 files changed, 3 insertions(+), 0 deletions(-)
> 
> diff --git a/gcc/config/mn10300/mn10300.h b/gcc/config/mn10300/mn10300.h
> index edc17f5..468c031 100644
> --- a/gcc/config/mn10300/mn10300.h
> +++ b/gcc/config/mn10300/mn10300.h
> @@ -656,7 +656,10 @@ struct cum_arg
>  #define ASM_OUTPUT_LABELREF(FILE, NAME) \
>    asm_fprintf (FILE, "%U%s", (*targetm.strip_name_encoding) (NAME))
>  
> +/* ??? Is there any real reason for this?  It mucks up pattern matching
> +   in the tree-ssa.exp testsuite.
>  #define ASM_PN_FORMAT "%s___%lu"
> +*/
>  
>  /* This is how we tell the assembler that two symbols have the same value.  */
>  
I can't think of a reason.  It's something Kaveh added almost 10 years
ago...

Jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNLGz2AAoJEBRtltQi2kC7cf0H/0WX2zkuHYEEnSITUHJipVwB
0GdGY95IoHArtDbZCMri9YPPMNvjuaQRppTusxNjBpKrg+krCxZYcZKuaUrwYj4w
RogfiL16TP0NW8Q1Ur602ryboNJY9jWxFx+P38PkL2YAu5TpH5Fv0CY40D6egSSz
qlpjG8fcV/k+qLwZU1reVRRLzBVdN/A47hlWogeYyC1uFJK0q9A8+yFm/huOt7Sh
2J2lBCGJ95OTwaIFjbuHCec7nootM4U7qW5nE6PYSb4Vb6ea/fsFiRs+t8S6yiPa
xIEbJ4qKjpdjkM6Ywnn2qC8QZzkgDIelFwKRzoY/lqvanNYOv5QEMrK3y3UgWss=
=Qa/n
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 07/28] mn10300: Add attribute enabled.
  2011-01-10 20:34 ` [PATCH 07/28] mn10300: Add attribute enabled Richard Henderson
@ 2011-01-11 14:47   ` Jeff Law
  0 siblings, 0 replies; 90+ messages in thread
From: Jeff Law @ 2011-01-11 14:47 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, Richard Henderson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/10/11 13:31, Richard Henderson wrote:
> From: Richard Henderson <rth@twiddle.net>
> 
> This will allow merging am33 and mn103 patterns for which the
> set of alternatives can't be merged via constraint letters.
OK.
jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNLG01AAoJEBRtltQi2kC76T4H/RvzdDfXvErG7YkLeeWn9VzD
JTJZ8d11c7O4PjKpqjhsqSlKerz+xYUbXMRyJJhDUR8pnLqo/37tR0mErfCuLmNe
1yfw0VhTporzcONSfcZGaZbSB336yoKEDyo+vouyD+E6VIuKrKQ1462Mh6CZajMG
Q8qA6zQKUCXXph5LroJI0VHYaOMol3h1j9QYr50dNQcrwdIvOeTxEi3UD1jj3w2J
UjJcea/U1ULum4K3srY92MilOa9Db7FkT7761IH1dRTPiZP2Zy/iriiu4myj9dW9
mO+VI3Ib+FX1Ti5WtfowurgoN5DZA5UKHJbOT8o/s3D+Z9EgcakJu+cHr8lLf1Y=
=6qbw
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 05/28] mn10300: Fix debug offsets into the stack frame
  2011-01-10 20:34 ` [PATCH 05/28] mn10300: Fix debug offsets into the stack frame Richard Henderson
@ 2011-01-11 14:50   ` Jeff Law
  0 siblings, 0 replies; 90+ messages in thread
From: Jeff Law @ 2011-01-11 14:50 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, Richard Henderson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/10/11 13:31, Richard Henderson wrote:
> From: Richard Henderson <rth@twiddle.net>
> 
> We were using debugging hooks to semi-correct a mistake
> in the lack of ARG_POINTER_CFA_OFFSET.
OK.
Jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNLG3BAAoJEBRtltQi2kC7ZW8IAKcmLj1OVH7pnyZmVCrGHkGC
lMNpOq98uZoVo0ng1DtoPKXeZ+qG2Q2wpxwmEYmcVoVWyDa2PNAO2Il/tBIILkvS
iD7FT+mcb6zVW+gSglU0hxMhsyD9dVifnm/kd4vcaKr1d026ZHu3rILxQ6zP2lb7
WAtz92KBZEzyKAF/UOFrS8+hPIOTteDhviXO+Xui4+ZC5U6Tz7FcEW/r0Ep2I9kv
0uDe1NFCfWws9dIugC/G2xuZWs6quXG7EMRHjyjCM4f0AzG7D5w/2knYJ8JDZEsW
XiY0lv/jv+fBDEDFfxkGSr7mEhn5nyd8cmbbzgjl4iCyEOXR3G6oUc44uRrPYLc=
=Z2gx
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 04/28] mn10300: Emit the movm stores in the correct order.
  2011-01-10 20:32 ` [PATCH 04/28] mn10300: Emit the movm stores in the correct order Richard Henderson
@ 2011-01-11 14:53   ` Jeff Law
  2011-01-11 17:10     ` Richard Henderson
  0 siblings, 1 reply; 90+ messages in thread
From: Jeff Law @ 2011-01-11 14:53 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, Richard Henderson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/10/11 13:31, Richard Henderson wrote:
I'll assume that you verified the movm fix somehow?  I recall the
original mn103 docs being somewhat ambiguous in how movm was documented
leading to much confusion between the Matsushita engineers & myself
(particularly since GCC & the simulator were self-consistent, but
incorrect relative to the hardware).

I thought we had all that sorted out back in 1999 or so :-)


jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNLG5sAAoJEBRtltQi2kC788oH/RNhV2ANSm0gp3gWBJB3kRXI
NhKIpUizckowp5aI38yPK5xWbGrVkuWTGVSuzwDqZa8TLOfaj8jejo98v2VA5DN9
yPOu7FlNhA05gAv5PLJWka99YkDsfUZYDmcUkCdLBSJQEkWTjV0PCCQ/0BYKEw3d
yG1gexGpX/lVYZSRHAqHBFLqN+dwHZ5LpILLwP6ws9CeCzoMGfbVIeYoyHwjehME
DVxrpGszalz0G1kjeo2CZzdCCkaCNnxNJubjO9NVFtGORTvkCegTLnPvKJOz4R13
dq/hovoKPWc/VC1bXDjLy1iv55MtId8DICxNUu9gvfhOXAAt4mc9oigBwR7/z24=
=dtom
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 08/28] mn10300: Define the A and D constraints.
  2011-01-10 20:34 ` [PATCH 08/28] mn10300: Define the A and D constraints Richard Henderson
@ 2011-01-11 14:56   ` Jeff Law
  2011-01-11 16:44     ` Richard Henderson
  0 siblings, 1 reply; 90+ messages in thread
From: Jeff Law @ 2011-01-11 14:56 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, Richard Henderson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/10/11 13:31, Richard Henderson wrote:
> From: Richard Henderson <rth@twiddle.net>
> 
> This will allow combining am33 and mn103 alternatives
> without having to resort to the enabled attribute.
> 
> The existing 'A' constraint renamed to 'c'.  Thankfully
> this existing accumulator constraint doesn't appear in
> either newlib or eglibc sources.
Isn't this a user-visible change?  What about the kernel, didn't it have
an mn103 port and it'd be more likely to expose the old A constraint
than newlib/glibc IMHO.

At the least this probably ought to be documented.

jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNLG7VAAoJEBRtltQi2kC762AH/RLvvhQCLBQKegCr76T35eiE
RAYwAyQD5omvmcb+Q6p64CQfQOqNjj+6zv+KnPutNeoYTEwvrsHSw3j3xhLgiWI8
/OTZ8j7eulFyh7OqaMulpcUG2TNuATiyAkTg/kJ7j1vYTTue62IOCNds0gc70Jll
Bn/L14CrAhEd+vOJd0SPim3UQujxQl2np/UPtAhQ4Ou8QNlVxUf7IRjodJ2n/WiL
E2zjKL4sU8QSmWxIcVwiSlZnbK09ZjDwdVnRgD8ijeSwxHpEiG8R8nivZ9k7GazA
+cZba3dasPVR2a+M8jWl7vnp14HYCoA5eeQVLAvDNhozoW6QyPG+KEAvvlLQe68=
=Jqn0
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 09/28] mn10300: Remove bset/bclr patterns.
  2011-01-10 20:34 ` [PATCH 09/28] mn10300: Remove bset/bclr patterns Richard Henderson
@ 2011-01-11 14:57   ` Jeff Law
  0 siblings, 0 replies; 90+ messages in thread
From: Jeff Law @ 2011-01-11 14:57 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, Richard Henderson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/10/11 13:31, Richard Henderson wrote:
> From: Richard Henderson <rth@twiddle.net>
> 
> These instructions do not use normal addressing modes and are
> incorrectly implemented for that.  Corrections to legitimate
> addresses expose problems here.
> 
> Delete them for now.  To be re-instated later in the form of
> atomic operation builtins.
OK.  Never liked the code to support bset/bclr anyway.

jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNLG8RAAoJEBRtltQi2kC78RgH/1Mq18Q8+1zh63Q3tq8Ocqfy
Z/zHh98bIriRAXKDJQukiQHpGUlhMwPUcIJS8QOr/0JJV3MP7+hJi6oXu5Yy9RMG
boNIUN3lE6EzGT8pzmEMxqm+Qij4uChTZxLhz2f5G8KGSSGgYBRnHRoTegEnU1KC
wSVgcw1wIT/JT3wYMh0JXVk/FPZ+XaTL/Jvdv15noN3ZB9rF8eJRxwpL5x5rti14
HAqyp+QtPQqfuczbCdkWbX4Dw0QdRYLWpDVkPRzYvWj7AX6dETAS21vu71qxA/rR
YyIml+wAWLKPAblChqG3CVje91fJEbPvJeR7qgPN/BZfM22D2m5TIC5nv5rQxug=
=scCZ
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 11/28] mn10300: Clean up costing.
  2011-01-10 20:34 ` [PATCH 11/28] mn10300: Clean up costing Richard Henderson
@ 2011-01-11 15:02   ` Jeff Law
  0 siblings, 0 replies; 90+ messages in thread
From: Jeff Law @ 2011-01-11 15:02 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, Richard Henderson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/10/11 13:31, Richard Henderson wrote:
> From: Richard Henderson <rth@twiddle.net>
> 
> Address, register, memory and rtx costs bore little relation to reality.
OK.  FWIW, my memory was I tuned the costs strictly for size way back
when.  It's also possible I blindly missed all kinds of things.

jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNLG+KAAoJEBRtltQi2kC7x04H/R4GU8Q92lUbmhZ5VgOTcdDk
9f759Fv/vByJuOLtPGINS9l/DUq16Pe2VnQvB6cSTO32TLDm4TkZROQ6RYQlEwWr
kR//5HTfKsZj/QMx0fBSKzfYX/Ljrmzk/zF7USCIYF9P/78usbJ4DDCyXhJmPU72
V66tCaAb0XADI9wbzobadAuLP1Ou4p9izvEcjqsvVbPX1czeHriqyfS62mLSGB5G
YWwGZ0eSaZ/HfzuLei3PRAav8kozMBsh4wgZfNdUvIvxl5VdjRjrQLPe6hQh3wsG
TB41rKN/FKuK8ytcc5rQ5mMfOQDWkhS1AgAs0+1c6d+eCvxqWMoS7PAzb8PmvNI=
=JJEl
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 08/28] mn10300: Define the A and D constraints.
  2011-01-11 14:56   ` Jeff Law
@ 2011-01-11 16:44     ` Richard Henderson
  2011-01-11 18:53       ` Jeff Law
  0 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-11 16:44 UTC (permalink / raw)
  To: Jeff Law; +Cc: Richard Henderson, gcc-patches, nickc

On 01/11/2011 06:53 AM, Jeff Law wrote:
> Isn't this a user-visible change?  What about the kernel, didn't it have
> an mn103 port and it'd be more likely to expose the old A constraint
> than newlib/glibc IMHO.

It is user-visible.  I tried to think of another letter that would
make as much sense as the d/D pair, but I thought biting the bullet
and making a/A match the same way was easier to remember.

As for the kernel, it doesn't use A either.  Which isn't surprising
given that it doesn't do floating-point at all.


r~

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 00/28] mn10300 cleanup + compare-elim, v2
  2011-01-11 14:20 ` [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Nick Clifton
@ 2011-01-11 16:45   ` Richard Henderson
  0 siblings, 0 replies; 90+ messages in thread
From: Richard Henderson @ 2011-01-11 16:45 UTC (permalink / raw)
  To: Nick Clifton; +Cc: gcc-patches, law, Richard Henderson

On 01/11/2011 06:03 AM, Nick Clifton wrote:
>> -   (clobber (reg:CC_FLOAT CC_REG))
>> -  ]
>> +   (clobber (reg:CC_FLOAT CC_REG))]
> 
> Is this a formatting requirement ? It makes more sense to me to treat
> closing parentheses in the same way as they are treated in C code -
> ie with them on a line on their own directly underneath their
> corresponding opening parenthesis. If it is a requirement though,
> then please accept my apologies for formatting the code incorrectly.

Hum.  I don't know if it's a requirement, but it's certainly not how
all the other ports are done.

Perhaps it's just a lisp thing.  You format rtl like lisp, not like C.  ;-)


r~

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 04/28] mn10300: Emit the movm stores in the correct order.
  2011-01-11 14:53   ` Jeff Law
@ 2011-01-11 17:10     ` Richard Henderson
  0 siblings, 0 replies; 90+ messages in thread
From: Richard Henderson @ 2011-01-11 17:10 UTC (permalink / raw)
  To: Jeff Law; +Cc: gcc-patches, nickc, Richard Henderson

On 01/11/2011 06:51 AM, Jeff Law wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> 
> On 01/10/11 13:31, Richard Henderson wrote:
> I'll assume that you verified the movm fix somehow?  I recall the
> original mn103 docs being somewhat ambiguous in how movm was documented
> leading to much confusion between the Matsushita engineers & myself
> (particularly since GCC & the simulator were self-consistent, but
> incorrect relative to the hardware).

Well, the change matches both the documentation and the simulator.
I can only assume both match the hardware atm...  ;-)


r~

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 00/28] mn10300 cleanup + compare-elim, v2
  2011-01-10 20:33 [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Richard Henderson
                   ` (28 preceding siblings ...)
  2011-01-11 14:20 ` [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Nick Clifton
@ 2011-01-11 18:31 ` Richard Henderson
  29 siblings, 0 replies; 90+ messages in thread
From: Richard Henderson @ 2011-01-11 18:31 UTC (permalink / raw)
  To: gcc-patches; +Cc: nickc, law

I meant to also give for the record a rationale for some of the
changes from version 1.

The biggest change in the way I'm approaching the compare-elim pass
from the backend point-of-view is that the original suggestion for

(define_insn "arithsi3"
  [(match_parallel "clobber_or_set_CCZCmode"
     [(pattern)])]

works, *nearly*.  While it can properly match the clobber or the
set of the cc-reg with the pattern, what it misses is the auto-
generated recognition of the pattern *without* the clobber, plus
the num_clobbers_to_add quantity.  Without this, combine will 
pretty much fail to match anything, and we miss all sorts of
optimizations.

I thought about different ways to handle this.  The best idea that
I came up with was to extend the definition of define_predicate to
allow attributes.  Then one could write

(define_special_predicate "clobber_or_set_CCZCmode"
  (and (match_code "parallel")
       (match_test "whatever"))
  [(set_attr "num_clobbers_to_add" "1")])

which we could define to mean: match the internals of the match_parallel,
and take the num_clobbers_to_add quantity from the predicate.  It
seems like a plausible course of action, but it was more work than I
had time for over the break.

In the meantime I simply use two separate patterns, as is customary.

The second change for the compare-elim pass is to look for duplicate
compare instructions.  That is,

	cmp	x,y
	stuff-with-no-flags-clobber
	cmp	x,y

and, in particular, look across basic block boundaries.  This turned
out to be way more common than any other optimization that I could find.
For instance, this double compare happens against the high work in every
double-word comparison.  E.g.

	cmp	xh,yh
	blt	true
	cmp	xh,yh
	bne	false
	cmp	xl,yl
	blt	true

The desire to do both -- eliminate duplicate compares and eliminate the
original compare itself -- means that the pass has been rearranged:

First scan the entire function collecting all the compares and the uses.
Eliminate duplicates, and merge the set of uses.  Use the combined set 
of uses to determine the proper CC_MODE that can handle everything, and
only then attempt to eliminate the original compare.

We get to use df.h links to find the uses and (mostly) the insn that
may make the compare redundant.  Thus we have only one full scan over
all insns in the function while looking for the compare insns in the
first place.


r~

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 08/28] mn10300: Define the A and D constraints.
  2011-01-11 16:44     ` Richard Henderson
@ 2011-01-11 18:53       ` Jeff Law
  2011-01-11 19:31         ` Richard Henderson
  0 siblings, 1 reply; 90+ messages in thread
From: Jeff Law @ 2011-01-11 18:53 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Richard Henderson, gcc-patches, nickc

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/11/11 09:30, Richard Henderson wrote:
> On 01/11/2011 06:53 AM, Jeff Law wrote:
>> Isn't this a user-visible change?  What about the kernel, didn't it have
>> an mn103 port and it'd be more likely to expose the old A constraint
>> than newlib/glibc IMHO.
> 
> It is user-visible.  I tried to think of another letter that would
> make as much sense as the d/D pair, but I thought biting the bullet
> and making a/A match the same way was easier to remember.
> 
> As for the kernel, it doesn't use A either.  Which isn't surprising
> given that it doesn't do floating-point at all.
Oh, I mis-read what A had been used for.  I think documenting in the
release notes is all we really need to do for this.

jeff

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNLJ2bAAoJEBRtltQi2kC73fYH/i6Z6wlbDP84vFfzNTko8g5B
TO0RA1J1JLOXeZKjcztWOf9Ba/rSBvSk3dJlYklGCWRBX12IBtYD0JiV8382RB2Q
9aWBCJaMc80Y0ukTwIqIY/ZUOPSjzz0F+UqZyP0hFdPUJ5PJy1K6eEWXZnJtuZjS
HnbOMq8Y2EQ680E6PO3Mhoow9OM+v/HDeV6gIcYSoJwPatHDjxm7oZg5ErJZoY+q
fS3MM2ZJfgZesPu8D0z6MBXs4Ir8/JGFibs/ZJq9NfOZNuIIBFrtxaQX6gV5YToJ
+iMUNa9QbOoRHyBAE2dJEZVsn5PSon/4Tr8i/e9P4rNva0SjgupKG6ybEfEThA0=
=QgJ+
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 28/28] New -fcompare-elim pass.
  2011-01-10 20:34 ` [PATCH 28/28] New -fcompare-elim pass Richard Henderson
@ 2011-01-11 19:00   ` Nathan Froyd
  2011-01-11 19:24     ` Richard Henderson
  2011-01-12  9:07   ` Paolo Bonzini
  1 sibling, 1 reply; 90+ messages in thread
From: Nathan Froyd @ 2011-01-11 19:00 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, law, Richard Henderson

On Mon, Jan 10, 2011 at 12:31:57PM -0800, Richard Henderson wrote:
> +static unsigned int
> +execute_compare_elim_after_reload (void)
> +{
> +      /* Eliminate comparisons that are redundant with flags computation.  */
> +      for (i = 0; VEC_iterate (comparison_struct_p, all_compares, i, cmp); ++i)

Please use FOR_EACH_VEC_ELT here.

-Nathan

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 28/28] New -fcompare-elim pass.
  2011-01-11 19:00   ` Nathan Froyd
@ 2011-01-11 19:24     ` Richard Henderson
  0 siblings, 0 replies; 90+ messages in thread
From: Richard Henderson @ 2011-01-11 19:24 UTC (permalink / raw)
  To: Nathan Froyd; +Cc: Richard Henderson, gcc-patches, nickc, law

On 01/11/2011 10:30 AM, Nathan Froyd wrote:
> On Mon, Jan 10, 2011 at 12:31:57PM -0800, Richard Henderson wrote:
>> +static unsigned int
>> +execute_compare_elim_after_reload (void)
>> +{
>> +      /* Eliminate comparisons that are redundant with flags computation.  */
>> +      for (i = 0; VEC_iterate (comparison_struct_p, all_compares, i, cmp); ++i)
> 
> Please use FOR_EACH_VEC_ELT here.

Fixed locally, thanks.


r~

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 08/28] mn10300: Define the A and D constraints.
  2011-01-11 18:53       ` Jeff Law
@ 2011-01-11 19:31         ` Richard Henderson
  2011-01-11 20:59           ` Gerald Pfeifer
  2011-01-12  0:30           ` Jeff Law
  0 siblings, 2 replies; 90+ messages in thread
From: Richard Henderson @ 2011-01-11 19:31 UTC (permalink / raw)
  To: Jeff Law; +Cc: Richard Henderson, gcc-patches, nickc, gerald

[-- Attachment #1: Type: text/plain, Size: 175 bytes --]

On 01/11/2011 10:12 AM, Jeff Law wrote:
> Oh, I mis-read what A had been used for.  I think documenting in the
> release notes is all we really need to do for this.

Ok?


r~

[-- Attachment #2: z --]
[-- Type: text/plain, Size: 1044 bytes --]

Index: changes.html
===================================================================
RCS file: /cvs/gcc/wwwdocs/htdocs/gcc-4.6/changes.html,v
retrieving revision 1.85
diff -u -r1.85 changes.html
--- changes.html	9 Jan 2011 14:12:15 -0000	1.85
+++ changes.html	11 Jan 2011 19:19:13 -0000
@@ -597,6 +597,21 @@
     </li>
   </ul>
 
+<h3 id="mn10300">MN10300 / AM33</h3>
+  <ul>
+    <li>The inline assembly register constraint <code>"A"</code> has
+        been renamed <code>"c"</code>.  This constraint is used to
+        select a floating-point register that can be used as the
+        destination of a multiply-accumulate instruction.
+    </li>
+    <li>New inline assembly register constraints <code>"A"</code> and
+        <code>"D"</code> have been added.  These constraint letters
+        resolve to all general registers when compiling for AM33, and
+        resolve to address registers only or data registers only when
+        compiling for MN10300.
+    </li>
+  </ul>
+
 <h3 id="picochip">picochip</h3>
 
 <h3>PowerPC64</h3>

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 08/28] mn10300: Define the A and D constraints.
  2011-01-11 19:31         ` Richard Henderson
@ 2011-01-11 20:59           ` Gerald Pfeifer
  2011-01-12  0:30           ` Jeff Law
  1 sibling, 0 replies; 90+ messages in thread
From: Gerald Pfeifer @ 2011-01-11 20:59 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Jeff Law, Richard Henderson, gcc-patches, nickc

On Tue, 11 Jan 2011, Richard Henderson wrote:
>> Oh, I mis-read what A had been used for.  I think documenting in the
>> release notes is all we really need to do for this.
> Ok?

I cannot vouch for technical correctness, but text and markup look
good to me and it's easy to understand.

Gerald

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 08/28] mn10300: Define the A and D constraints.
  2011-01-11 19:31         ` Richard Henderson
  2011-01-11 20:59           ` Gerald Pfeifer
@ 2011-01-12  0:30           ` Jeff Law
  1 sibling, 0 replies; 90+ messages in thread
From: Jeff Law @ 2011-01-12  0:30 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Richard Henderson, gcc-patches, nickc, gerald

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/11/11 12:21, Richard Henderson wrote:
> On 01/11/2011 10:12 AM, Jeff Law wrote:
>> Oh, I mis-read what A had been used for.  I think documenting in the
>> release notes is all we really need to do for this.
> 
> Ok?
yes.
jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNLPP7AAoJEBRtltQi2kC7Z9EH+wVo39MxZpOVL+2svRes0wAQ
6txf9NibMYAZOwQWeqrElsVZeC7e6bDCxnrWTDpYaGpPD79DiDfA8PDtGHP7kZdz
9n5VrfHMQ7WrQXVwq51W7QAUurezXym6t+b1yrMgu+a3k6zmeAXUG1oMPSgcktYE
aOCe4dw7iCv/xRmbUMp5I9yWD1dO8vp0EX5FmivDQJbZML4BjdK4V87uJ4g7+Xnc
KIMIOfcNdVkmAL++Ze8lfSv8lL32qedSVv6gtSniqBCFk/QX1hTojHE7qmab13tq
8zOifiiKt/pY9CUhp6IVwSL+Ov3UuaX6iEON+pvIiqTOIv3+auWpKyfKQWuCe5c=
=yZjf
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 28/28] New -fcompare-elim pass.
  2011-01-10 20:34 ` [PATCH 28/28] New -fcompare-elim pass Richard Henderson
  2011-01-11 19:00   ` Nathan Froyd
@ 2011-01-12  9:07   ` Paolo Bonzini
  2011-01-12 20:34     ` Richard Henderson
  1 sibling, 1 reply; 90+ messages in thread
From: Paolo Bonzini @ 2011-01-12  9:07 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, law

> +  /* Find the DEF of the flags register.  It must be there.  */
> +  for (use_rec = DF_INSN_DEFS (insn); ; use_rec++)
> +    {
> +      use = *use_rec;
> +      if (DF_REF_TYPE (use) == DF_REF_REG_DEF
> +	  && DF_REF_REGNO (use) == targetm.flags_regnum)
> +	break;
> +    }

Can you rename these to def/def_rec?  For a moment I thought you were 
not using def-use chains because I found only DF_REF_CHAIN (use).

(My observations below actually override this comment).

> +      /* Note that df does not create use chains that cross basic blocks.

I don't think this is correct, as this is the very thing that is 
responsible for the chains problem's potential quadratic behavior.  Have 
you seen it in practice (the chain that doesn't cross basic blocks, not 
the quadratic behavior)?

This is basically the only case in which you'd rely on non-singleton 
chains, and you're solving it by punting anyway (i.e. via missing_uses). 
  This means this pass could be done just as easily without def-use chains.

During the forward walk you can record the last definition of CC in the 
basic block (which could start at last_cmp for an extended basic block). 
  Then, when you walk each insn's uses and look for a CC use.  If you 
find it, you know what it's last definition is.  That is, 
find_flags_uses_in_bb becomes something like maybe_record_flags_use and 
you would call it for all instructions, passing the last CC def.

> +  if (DF_REF_CHAIN (use) == NULL)
> +    return false;
> +
> +  def = DF_REF_CHAIN (use)->ref;

Here you should probably bail out if the use has multiple reaching 
definitions (i.e. DF_REF_CHAIN (use)->next != NULL).  It probably won't 
happen given how cbranch/cstore splitters work, but you never know.

> +     Note that this doesn't follow the USE-DEF chain from X, but
> +     since we already have to search for the previous clobber of
> +     the flags register, this wouldn't really be a problem.  */
> +
> +  /* Make sure that the flags are not clobbered in between the two
> +     instructions.  Unfortunately, we don't get DEF-DEF chains, so
> +     do this the old fashioned way.  */

Again, this is probably handled better without the use-def chains. 
(Chains are in the DF framework, but are rarely the best 
solution---especially if you're not limiting them to a region, e.g. a loop).

For a full-blown solution, we could generalize the 
singleton-use-def-chains code from fwprop and reuse it here.  Actually, 
I don't think you plan to move instructions in compare-elim, just like 
NOTICE_UPDATE_CC didn't.  So, the forward scan can remember, together 
with the last comparison insn, the last instruction that clobbered the 
flags.  Then whenever you find a comparison, you can already look at the 
shape of the last clobber; you then store if the comparison instruction 
is "mergeable", and if so with which insn.

Non-mergeable comparisons would still be recorded for the sake of 
eliminating duplicates.

> +  /* Succeed if the new instruction is valid.  */
> +  validate_change (dinsn, &XVECEXP (dpat, 0, 1), x, true);
> +  if (!apply_change_group ())
> +    return false;

Here you can test the return value of validate_change directly.

Thanks very much for this work, it is a very nice and readable pass, and 
probably one of the biggest steps towards eradication of cc0.

HTH,

Paolo

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 15/28] mn10300: Force lower-subreg pass to run.
  2011-01-10 20:33 ` [PATCH 15/28] mn10300: Force lower-subreg pass to run Richard Henderson
@ 2011-01-12 14:04   ` Jeff Law
  0 siblings, 0 replies; 90+ messages in thread
From: Jeff Law @ 2011-01-12 14:04 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, Richard Henderson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/10/11 13:31, Richard Henderson wrote:
> From: Richard Henderson <rth@twiddle.net>
> 
> There are a number of tests that fail -- generally ones involving
> generic vectorization -- at -O0 because we run out of registers.
> The lower-subreg pass cleans things up sufficiently to allow these
> tests to succeed.
OK.
Jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNLbR0AAoJEBRtltQi2kC7Px0H/RRI+fS9ohL7lImU37bvgdLS
KJaaEbF5HBMRiuMjixsy8aaZjQeF1QUIm/wTAqT+AnyevjZjWMIPBy9fBk2MSJXR
6UEzAM3PxgZw/f3x5E16fDRAOH11IpmeKnSRaLWPqMakHw+4swm4ITOVgBpr+Dqe
p5hNmxYumlZUzZZ3YBXLQjNgV2Ioo0BAPlfuQh2ERt3RWVxV+VU3E18L8xw9bwvk
kyIFr/mbVc4rB8OE4Zkh5VeGV+P68E4oL1ZTyEqwhn8eEnShKCVoIu1ePdR3tJoF
yt7asjiB1JMurOUwhW4j1h5+hM3OuuG6x28/Rca/KJ/t48Yl+GIqJJHIzhJ65Cg=
=Gjp1
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 10/28] mn10300: Clean up trampoline handling
  2011-01-10 20:33 ` [PATCH 10/28] mn10300: Clean up trampoline handling Richard Henderson
@ 2011-01-12 14:04   ` Jeff Law
  0 siblings, 0 replies; 90+ messages in thread
From: Jeff Law @ 2011-01-12 14:04 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, Richard Henderson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/10/11 13:31, Richard Henderson wrote:
> From: Richard Henderson <rth@twiddle.net>
> 
> The old code was failing in the testsuite.  I didn't try to
> debug exactly why, since the existing code was needlessly
> complex.
OK.
jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNLbRFAAoJEBRtltQi2kC7GTUH/3ndw5YXuPKi9InW9MaWEyBy
V9uLC4Fb4/5VqANO2mmyUlc/6e+a9qLWVooPNzpmIv6BpCAM5aNnrlf6vlMOSbjH
sx9HagXdR5XI8L5RdcS3Hl7CBbBBxTOdja9RLBSTZJoAOeSUHc3JN24a6IaIYfDD
LoEKsmOiO2rgfelvSi/0T4jSDAjSz/2WFMwrQuaHKZhncUAAoVMppU6MyRmrng1R
eVYjpSNAFjj2y5U6I/uu0g6agcx2ilzk7b9xNXR/N4gmOQTFUqu8DJQC9+7uu6El
p5i4+Rui7Eq/ZlRqd9eyAcn7pSKykrbFWxJWhHh4daiDtL+n1XRAiqb3MOWvwwE=
=c7kB
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 21/28] mn10300: Add clzsi2.
  2011-01-10 20:33 ` [PATCH 21/28] mn10300: Add clzsi2 Richard Henderson
@ 2011-01-12 14:05   ` Jeff Law
  0 siblings, 0 replies; 90+ messages in thread
From: Jeff Law @ 2011-01-12 14:05 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, Richard Henderson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/10/11 13:31, Richard Henderson wrote:
> From: Richard Henderson <rth@twiddle.net>
> 
> ---
>  gcc/config/mn10300/mn10300.md |   23 +++++++++++++++++++++++
>  1 files changed, 23 insertions(+), 0 deletions(-)
OK.
jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNLbTyAAoJEBRtltQi2kC7O2MH/3TG9kbnngCXWAZjVuL1dWQm
rgp7Snldrk9DQQpNH346tuCfS9h+jH5zk+9gNq2jiGnRFYcMQULJceDMdPh4YeIh
LHq4Uz3MNv7JiJpOidVedsubPAxZuoWkA7A87fijtArMGJ1xy9kzZt0ecqINB4pl
fpQJqbuqXlRJvc9YpN74APVWoSLHb8PaB2U5+GThvNuQt3l6uRBSDrkeI6D8xS2C
P2oBlbDTJMiESE21lQrqqQ1Tv74uIeFwXrJMzTmjoKyhftAQSdzZzXSyDJSVlz8e
yTMEquBQ2OWIztO6cSIg9mweoVffkxhvjWDlSxeMaPw9bC0i2KdolQdSb3fiUP8=
=ZR1P
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 20/28] mn10300: Emit clr.
  2011-01-10 20:33 ` [PATCH 20/28] mn10300: Emit clr Richard Henderson
@ 2011-01-12 14:05   ` Jeff Law
  0 siblings, 0 replies; 90+ messages in thread
From: Jeff Law @ 2011-01-12 14:05 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, Richard Henderson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/10/11 13:31, Richard Henderson wrote:
> From: Richard Henderson <rth@twiddle.net>
> 
> ---
>  gcc/config/mn10300/mn10300.md |   25 +++++++++++++++++++++++++
>  1 files changed, 25 insertions(+), 0 deletions(-)
OK.
jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNLbTTAAoJEBRtltQi2kC7v98IAJTsY7x9kuA+6N37Of9VLwVg
qsQoRFJVEM/OHWFlo6+xUltfpRPcLAeiH7erkgWYKFZggMJcglqwSi3rBDrRkFyL
M9a1g1Hh0XUfsjQCIL/lA3/Qdlco/i1mFo8nBY0thpuFBxLitAUzVrVgVLWX+qQD
8S9ISL3kcVxDrbEdTtPDTjNrJXLZjxrqfw8XwbmdqKPhexZCzHtPwJ0mKn2ykecW
4iigmCjUZoshvrNM3Zr4gsKX9eEZXMXCxnDBHvoPaWQt+MTC/ZpcI0xngOo7ihQ+
QC8Mevn7yrZXYyxEacpIb4if146QamH4IkK8jHipAghmbPh3uCmC9vGBB+UY0zU=
=hx8G
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 25/28] mn10300: Use reg_or_am33_const_operand in mulsi3.
  2011-01-10 20:33 ` [PATCH 25/28] mn10300: Use reg_or_am33_const_operand in mulsi3 Richard Henderson
@ 2011-01-12 14:06   ` Jeff Law
  2011-01-12 18:07     ` Richard Henderson
  0 siblings, 1 reply; 90+ messages in thread
From: Jeff Law @ 2011-01-12 14:06 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, Richard Henderson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/10/11 13:31, Richard Henderson wrote:
> From: Richard Henderson <rth@twiddle.net>
> 
> ---
>  gcc/config/mn10300/mn10300.md |   16 ++++++++--------
>  1 files changed, 8 insertions(+), 8 deletions(-)
OK.
jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNLbUvAAoJEBRtltQi2kC7FsYH/injrpjRcyRl0/odCExWV2LS
1IEkUccRPMs18UdxZgsUfFCzX26Koq1g88e7xJbUS46Gbbuf5n2t960yEcPfiN0n
b+Y4Rjg/rcQ54leEADlNOSszyT9Qm7ejlsW+ciR9o6lGkmbk8VB+zz9944BQy6yU
+Hrjqc74gQl4Q68qpC+3lxHlxO1MfUXmlQZ7aBOHgiQIjs3RMrlvBXbtu6qXDDt7
dCVgx2BpRA2QjVbIcxxna1fis7sZLnYstn6Cw81WQKKnTfRIOaY0wcwl5YqQ2vcT
+nwqgD1uQ7vW5cXA3oWjmBxR+9ZKMl7Sh6VwFSJSgyAig45fusllfxwky0yCmLs=
=cWr7
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 23/28] mn10300: Add delegitimize_address hook.
  2011-01-10 20:33 ` [PATCH 23/28] mn10300: Add delegitimize_address hook Richard Henderson
@ 2011-01-12 14:06   ` Jeff Law
  0 siblings, 0 replies; 90+ messages in thread
From: Jeff Law @ 2011-01-12 14:06 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, Richard Henderson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/10/11 13:31, Richard Henderson wrote:
> From: Richard Henderson <rth@twiddle.net>
> 
> This suppresses warnings generated by the dwarf2 output
> routines about uninterpretable addresses.
> ---
>  gcc/config/mn10300/mn10300.c |   62 ++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 62 insertions(+), 0 deletions(-)
OK.
jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNLbUPAAoJEBRtltQi2kC7Of0H/R/R++i0z0YBK87OGMisflhH
VURiYW1+q+5SshgFRSu/n0cUcEGO1VSRWsgz9TtDuCt71Sm5VjsdWIVa/6Nrk9Pr
A1dExTlSUkD+NUCfhcuXqG9GB4+XHLQ+RWnzM74LLnHsM4oPOvDsPjNQrLmxJraP
LTomaSUilXfj/bopDHkWI7ZuwUN0enS3tGyi7kVMoBANL70bV4wFhSFOAMg6Xs6g
cxReZekNYETj16aowq3A8jMOspdLnJQMh7XXZaNARZAPCbtqe1z/TkBo8FQK/hVp
qCbFIr2H6D5eOtrg6s/LMUataY5DuYf3FJW+zUOY/xj5tflYlKiAQCvlKukDN24=
=8DAR
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 26/28] mn10300: Auto-clobber the flags in asms.
  2011-01-10 20:34 ` [PATCH 26/28] mn10300: Auto-clobber the flags in asms Richard Henderson
@ 2011-01-12 14:22   ` Jeff Law
  0 siblings, 0 replies; 90+ messages in thread
From: Jeff Law @ 2011-01-12 14:22 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, Richard Henderson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/10/11 13:31, Richard Henderson wrote:
> From: Richard Henderson <rth@twiddle.net>
> 
> ---
>  gcc/config/mn10300/mn10300.c |   18 ++++++++++++++++++
>  1 files changed, 18 insertions(+), 0 deletions(-)
OK.
Jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNLbVGAAoJEBRtltQi2kC7OyEIAKE/EDyz/lZwHuZcR0m0ShNE
MZuqeRZUByZB2MMocemReGye7kh+4306TAUBRl9dAm6fV84CydDTiJBc2SnfMOGK
BX1N8AZbyhpLHFcSJ43Q3URGI/oWPB5hGQP0AOQGpoIQy/42W12Yz3aUDHqUGaKU
YqyDF4iNIEiLfBXHHFs1NnHSMFGnwjLMjJ3+BVKOBfXlpPENMg+wQvOLe/65AFVL
s6rUZbEPVGIHspF/0vg4T0ZzySER9cbFDMqXW+bgdcgMh4ahMkO4OoMJ416CB4pR
Z3xiXmahnhRbWqoI+b4YGz0FmA/Xq/GpZhP+EXUfd5HmgEo3zk0X2kSqMfiQh5c=
=dboo
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 27/28] mn10300: Add support in longlong.h.
  2011-01-10 20:33 ` [PATCH 27/28] mn10300: Add support in longlong.h Richard Henderson
@ 2011-01-12 14:31   ` Jeff Law
  2011-01-12 18:10     ` Richard Henderson
  0 siblings, 1 reply; 90+ messages in thread
From: Jeff Law @ 2011-01-12 14:31 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, Richard Henderson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/10/11 13:31, Richard Henderson wrote:
> From: Richard Henderson <rth@twiddle.net>
> 
> This greatly helps out the DImode division, and to a lesser
> extent the DImode multiplication routines in libgcc2.c.
OK.
jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNLbV1AAoJEBRtltQi2kC7csoH/0Sngi+AhO/FG/+Cyf095wg2
yqA24oL+6Qp15+4ce4CVcj2GDWwA7DytIf0GHg9BdI7qRhznnj1yEKC6hbkxy3yD
YpHW87UK6D5xMbgM9uhIpx1rwsn5xGCOQjIzjqJ1d3Zd0FOuhTFeMYnlqKVe3kmo
/AAk7v+tXhDDc2zXZ5qQ99Za/x28fucPzJwcYKv27JCmkAH4leP/ES62HvEo27O2
P/VIOI0MpNCphyoC01dielNdZ8UJsl5Tyi1SreNT3V/FQOTDtNQX4O5897FCmbLW
pulamCH2xpqjtrQIiMPuZ3hRd1ksBHTP8SGeV7sER0eZA5ahdjuMB9MtzaQyZzo=
=kCWq
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 25/28] mn10300: Use reg_or_am33_const_operand in mulsi3.
  2011-01-12 14:06   ` Jeff Law
@ 2011-01-12 18:07     ` Richard Henderson
  2011-01-12 18:11       ` Jeff Law
  0 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-12 18:07 UTC (permalink / raw)
  To: Jeff Law; +Cc: gcc-patches, nickc, Richard Henderson

On 01/12/2011 06:05 AM, Jeff Law wrote:
> OK.

Thanks.  Blocked on [17/28], the multiply cleanup patch.


r~

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 27/28] mn10300: Add support in longlong.h.
  2011-01-12 14:31   ` Jeff Law
@ 2011-01-12 18:10     ` Richard Henderson
  0 siblings, 0 replies; 90+ messages in thread
From: Richard Henderson @ 2011-01-12 18:10 UTC (permalink / raw)
  To: Jeff Law; +Cc: gcc-patches, nickc, Richard Henderson

On 01/12/2011 06:06 AM, Jeff Law wrote:
>> This greatly helps out the DImode division, and to a lesser
>> extent the DImode multiplication routines in libgcc2.c.
> OK.

Thanks.  Blocked on [16/28] Expose MDR register, and to a
lesser extent [24/28] Implement adddi3.


r~

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 25/28] mn10300: Use reg_or_am33_const_operand in mulsi3.
  2011-01-12 18:07     ` Richard Henderson
@ 2011-01-12 18:11       ` Jeff Law
  0 siblings, 0 replies; 90+ messages in thread
From: Jeff Law @ 2011-01-12 18:11 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, Richard Henderson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/12/11 11:01, Richard Henderson wrote:
> On 01/12/2011 06:05 AM, Jeff Law wrote:
>> OK.
> 
> Thanks.  Blocked on [17/28], the multiply cleanup patch.
Yea, I figured there was going to be some blockages.  I'm going to be
looking at the bigger patches during bootstrap/testing downtimes.

jeff


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNLe3vAAoJEBRtltQi2kC7kMEH/3pjwXzLl55jHn+A/ubjnUsL
tfN/DQHVj2SPR+1uPOGAtKld889AVlAzpJ7eCDZVnvHKVLCyYTrNxZq57yM5nS3Y
+UrYGqveQLv2ycTprKD9IWqexlt4WJ5lDHuGC4rzLm7+2Q33JxxqzUnd0lqaIPFS
Kbntxg3tfDC9+labu5PJ6YkbsPC4qDj94PfGX5xiinuuFt6C1TvxAqMjmU7kK2nm
89BxU6OjINLa/ttMdsdZWz5H2L0Pnw63yxsg0CJ1SYZaAHUg3sn8xCAjDYBmW4jl
FLXzps6YCDJWVfZjvIsnN+BP1J6UCp994VehqHAPYBfTNOqpTUFLeR88iUOmUo4=
=4N+K
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 28/28] New -fcompare-elim pass.
  2011-01-12  9:07   ` Paolo Bonzini
@ 2011-01-12 20:34     ` Richard Henderson
  2011-01-13  9:04       ` Paolo Bonzini
  0 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-12 20:34 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: gcc-patches, nickc, law

On 01/12/2011 12:31 AM, Paolo Bonzini wrote:
>> +      /* Note that df does not create use chains that cross basic blocks.
> 
> I don't think this is correct, as this is the very thing that is
> responsible for the chains problem's potential quadratic behavior.
> Have you seen it in practice (the chain that doesn't cross basic
> blocks, not the quadratic behavior)?

No, I thought I'd correctly read the code to determine that.  Of course,
with the code that I'm currently generating from mn10300 we'll never see
a cross-block occurrence, but I expect other targets to easily do so.

For instance, in the RX target I expect that we'll generate e.g. UNLT
with an UNORDERED branch and a LT branch, and that we'll only generate
one compare out of the post-reload splitter to do so.

> During the forward walk you can record the last definition of CC in
> the basic block (which could start at last_cmp for an extended basic
> block). Then, when you walk each insn's uses and look for a CC use.
> If you find it, you know what it's last definition is. That is,
> find_flags_uses_in_bb becomes something like maybe_record_flags_use
> and you would call it for all instructions, passing the last CC def.

An interesting idea.

>> +  if (DF_REF_CHAIN (use) == NULL)
>> +    return false;
>> +
>> +  def = DF_REF_CHAIN (use)->ref;
> 
> Here you should probably bail out if the use has multiple reaching
> definitions (i.e. DF_REF_CHAIN (use)->next != NULL). It probably
> won't happen given how cbranch/cstore splitters work, but you never
> know.

Good idea, though this has nothing to do with cbranch/cstore.  This
is finding the DEF for the register use inside the compare.

>> +     Note that this doesn't follow the USE-DEF chain from X, but
>> +     since we already have to search for the previous clobber of
>> +     the flags register, this wouldn't really be a problem.  */
>> +
>> +  /* Make sure that the flags are not clobbered in between the two
>> +     instructions.  Unfortunately, we don't get DEF-DEF chains, so
>> +     do this the old fashioned way.  */
> 
> Again, this is probably handled better without the use-def chains.
> (Chains are in the DF framework, but are rarely the best
> solution---especially if you're not limiting them to a region, e.g. a
> loop).

Err, I'm not using use-def chains for this.  I'm using reg_set_between_p.
I'm a bit confused about your statement here.

>> +  /* Succeed if the new instruction is valid.  */
>> +  validate_change (dinsn, &XVECEXP (dpat, 0, 1), x, true);
>> +  if (!apply_change_group ())
>> +    return false;
> 
> Here you can test the return value of validate_change directly.

True enough.

I'm a bit confused about the stance in regards to chains.  Should I 
attempt to avoid them entirely, so that I never add the problem?

I guess I can implement try_eliminate_compare by:

  * In find_comparisons_in_bb, remember the previous insn that
    clobbers CC_REG.  Record that in struct comparison.prev_clobber.

  * In try_eliminate_compare, if prev_clobber is not set, then we
    don't know where CC_REG was previously set, so we cannot eliminate.

  * The SET in prev_clobber must be the comparison.in_a register.
    If it isn't, then we cannot eliminate.

  * Use reg_set_between_p to verify that comparison.in_a is not
    modified between prev_clobber and comparison.insn.

It's that last step that seems a bit... odd, but not wrong exactly.
But is it odd enough to warrant using chains?



r~

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 28/28] New -fcompare-elim pass.
  2011-01-12 20:34     ` Richard Henderson
@ 2011-01-13  9:04       ` Paolo Bonzini
  2011-01-17 22:42         ` [RFC, v2] " Richard Henderson
  0 siblings, 1 reply; 90+ messages in thread
From: Paolo Bonzini @ 2011-01-13  9:04 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, law

On 01/12/2011 08:44 PM, Richard Henderson wrote:
> On 01/12/2011 12:31 AM, Paolo Bonzini wrote:
>>> +      /* Note that df does not create use chains that cross basic blocks.
>>
>> I don't think this is correct, as this is the very thing that is
>> responsible for the chains problem's potential quadratic behavior.
>> Have you seen it in practice (the chain that doesn't cross basic
>> blocks, not the quadratic behavior)?
>
> No, I thought I'd correctly read the code to determine that.

Chains are based on the output of reaching definitions, they do not care 
about whether the defs are in the same basic block or not.

>>> +  if (DF_REF_CHAIN (use) == NULL)
>>> +    return false;
>>> +
>>> +  def = DF_REF_CHAIN (use)->ref;
>>
>> Here you should probably bail out if the use has multiple reaching
>> definitions (i.e. DF_REF_CHAIN (use)->next != NULL). It probably
>> won't happen given how cbranch/cstore splitters work, but you never
>> know.
>
> Good idea, though this has nothing to do with cbranch/cstore.  This
> is finding the DEF for the register use inside the compare.

Oops, right.

>>> +     Note that this doesn't follow the USE-DEF chain from X, but
>>> +     since we already have to search for the previous clobber of
>>> +     the flags register, this wouldn't really be a problem.  */
>>> +
>>> +  /* Make sure that the flags are not clobbered in between the two
>>> +     instructions.  Unfortunately, we don't get DEF-DEF chains, so
>>> +     do this the old fashioned way.  */
>>
>> Again, this is probably handled better without the use-def chains.
>> (Chains are in the DF framework, but are rarely the best
>> solution---especially if you're not limiting them to a region, e.g. a
>> loop).
>
> Err, I'm not using use-def chains for this.  I'm using reg_set_between_p.
> I'm a bit confused about your statement here.

You're right, what I meant was "since you are anyway resorting to the 
old fashioned way, you can probably handle everything better without the 
use-def chains".

> I'm a bit confused about the stance in regards to chains.  Should I
> attempt to avoid them entirely, so that I never add the problem?

It's an expensive problem when applied to the entire function, so it is 
better to avoid it.  I'm not saying this cannot be delayed to 4.7 if the 
pass goes in now (it's almost a target-specific pass now, so it probably 
could).

> I guess I can implement try_eliminate_compare by:
>
>    * In find_comparisons_in_bb, remember the previous insn that
>      clobbers CC_REG.  Record that in struct comparison.prev_clobber.
>
>    * In try_eliminate_compare, if prev_clobber is not set, then we
>      don't know where CC_REG was previously set, so we cannot eliminate.
>
>    * The SET in prev_clobber must be the comparison.in_a register.
>      If it isn't, then we cannot eliminate.
>
>    * Use reg_set_between_p to verify that comparison.in_a is not
>      modified between prev_clobber and comparison.insn.

Exactly.

> It's that last step that seems a bit... odd, but not wrong exactly.
> But is it odd enough to warrant using chains?

I'd say no because you're doing the same right now.  USE-DEF chains get 
you to a clobber, and then reg_set_between_p confirms whether that 
clobber is the prev_clobber.

If you really want to remove the reg_set_between_p, you can of course 
record the SET of prev_clobber, and reset prev_clobber if an insn sets 
that register.  But I think it's more clumsy and not enough more 
efficient than what you outlined.

Paolo

^ permalink raw reply	[flat|nested] 90+ messages in thread

* [RFC, v2] New -fcompare-elim pass
  2011-01-13  9:04       ` Paolo Bonzini
@ 2011-01-17 22:42         ` Richard Henderson
  2011-01-18 10:06           ` Paolo Bonzini
  0 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-17 22:42 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: gcc-patches, nickc, law

[-- Attachment #1: Type: text/plain, Size: 2987 bytes --]

Version 2, based on Paolo's comments from v1.  Changes:

(0) The USE-DEF and DEF-USE chains are gone.

(1) A PREV_CLOBBER insn is recorded during the single scan
    of the function.  This insn is the insn previous to the
    compare which (A) clobbers the flags and (B) is of a
    shape amenable to compare elimination.

    If the insn previous to the compare that clobbers the
    flags is not amenable to elimination -- e.g. a call --
    we don't bother recording it, and later know that we
    shouldn't try.

(2) Uses of the compare are also found during that single scan.
    Some, ahem, highly questionable assumptions that had been
    made about how DEF-USE chains are or are not created are gone.
    I check the DF_LIVE_BB_INFO now, combined with the shape of
    the CFG to determine if there's a use of the flags that 
    escapes the extended basic block.

(3) try_eliminate_compare has been rewritten along the lines we
    discussed previously, although instead of reg_set_between_p...

(4) Porting the RX target to the compare-elimination pass was
    very helpful.  If showed that there's a phase ordering problem,
    that fortunately can be worked around with a little bit of effort.

    Consider libgcc _absvdi3.o, as of split2:

(insn 76 75 74 4 (parallel [
            (set (reg:SI 4 r4 [38])
                (minus:SI (minus:SI (reg:SI 4 r4 [38])
                        (reg:SI 2 r2 [orig:37 a+4 ] [37]))
                    (geu:SI (reg:CC 16 cc)
                        (const_int 0 [0]))))
            (clobber (reg:CC 16 cc))
        ]) libgcc2.c:265 76 {sbb_internal}
     (nil))

(insn 74 76 77 4 (set (reg:SI 2 r2 [orig:33 w+4 ] [33])
        (reg:SI 4 r4 [38])) libgcc2.c:265 22 {*movsi_internal}
     (nil))

(insn 77 74 78 4 (set (reg:CC 16 cc)
        (compare:CC (reg:SI 2 r2 [orig:33 w+4 ] [33])
            (const_int 0 [0]))) libgcc2.c:267 1 {*cmpsi}
     (nil))

    For RX, subtract-with-borrow (sbb) is a two-address insn, and
    so RA has little choice but to add an output reload (insn 74)
    in order to satisfy the matching constraint and put the result
    into the proper register.

    If we were to run this pass after pass_cprop_hardreg, this
    sequence would be tidied up such that the compare (insn 77)
    would have R4 as an input, and so we would immediately see the
    corresponding arithmetic (insn 76) and perform the elimination.

    However, pass_cprop_hardreg currently runs much later.  In
    particular, after pass_peephole2.  Now, peep2 is where we would
    like to make transformations like "mov 0,r" -> "xor r,r" iff
    the flags are not already live at that location.  In order to
    satisfy both, we'd have to shuffle lots of passes around with
    the attendant problem of determining if we've pessimized 
    something else.

    Instead, simply look for copy insns while we're stepping back
    looking to be sure that the input to the compare isn't 
    changed since PREV_CLOBBER.


Comments?


r~

[-- Attachment #2: compare-elim.c --]
[-- Type: text/plain, Size: 18421 bytes --]

/* Post-reload compare elimination.
   Copyright (C) 2010, 2011
   Free Software Foundation, Inc.

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.

GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */

/* There is a set of targets whose general-purpose move or addition
   instructions clobber the flags.  These targets cannot split their
   CBRANCH/CSTORE etc patterns before reload is complete, lest reload
   itself insert instructions in between the flags setter and user.
   Because these targets cannot split the compare from the use, they
   cannot make use of the comparison elimination offered by the combine pass.

   This is a small pass intended to provide comparison elimination similar to
   what is available via NOTICE_UPDATE_CC for cc0 targets.  This should help
   encourage cc0 targets to convert to an explicit post-reload representation
   of the flags.

   This pass assumes:

   (0) CBRANCH/CSTORE etc have been split in pass_split_after_reload.

   (1) All comparison patterns are represented as

	[(set (reg:CC) (compare:CC (reg) (immediate)))]

   (2) All insn patterns that modify the flags are represented as

	[(set (reg) (operation)
	 (clobber (reg:CC))]

   (3) If an insn of form (2) can usefully set the flags, there is
       another pattern of the form

	[(set (reg) (operation)
	 (set (reg:CCM) (compare:CCM (operation) (immediate)))]

       The mode CCM will be chosen as if by SELECT_CC_MODE.
*/

#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "rtl.h"
#include "tm_p.h"
#include "insn-config.h"
#include "recog.h"
#include "flags.h"
#include "basic-block.h"
#include "tree-pass.h"
#include "target.h"
#include "df.h"
#include "domwalk.h"

\f
/* These structures describe a comparison and how it is used.  */

/* The choice of maximum 3 uses comes from wanting to eliminate the two
   duplicate compares from a three-way branch on the sign of a value.
   This is also sufficient to eliminate the duplicate compare against the
   high-part of a double-word comparison.  */
#define MAX_CMP_USE 3

struct comparison_use
{
  /* The instruction in which the result of the compare is used.  */
  rtx insn;
  /* The location of the flags register within the use.  */
  rtx *loc;
  /* The comparison code applied against the flags register.  */
  enum rtx_code code;
};

struct comparison
{
  /* The comparison instruction.  */
  rtx insn;

  /* The insn prior to the comparison insn that clobbers the flags.  */
  rtx prev_clobber;

  /* The two values being compared.  These will be either REGs or
     constants.  */
  rtx in_a, in_b;

  /* Information about how this comparison is used.  */
  struct comparison_use uses[MAX_CMP_USE];

  /* The original CC_MODE for this comparison.  */
  enum machine_mode orig_mode;

  /* The number of uses identified for this comparison.  */
  unsigned short n_uses;

  /* True if not all uses of this comparison have been identified.
     This can happen either for overflowing the array above, or if
     the flags register is used in some unusual context.  */
  bool missing_uses;

  /* True if its inputs are still valid at the end of the block.  */
  bool inputs_valid;
};
  
typedef struct comparison *comparison_struct_p;
DEF_VEC_P(comparison_struct_p);
DEF_VEC_ALLOC_P(comparison_struct_p, heap);

static VEC(comparison_struct_p, heap) *all_compares;

/* Look for a "conforming" comparison, as defined above.  If valid, return
   the rtx for the COMPARE itself.  */

static rtx
conforming_compare (rtx insn)
{
  rtx set, src, dest;

  set = single_set (insn);
  if (set == NULL)
    return NULL;

  src = SET_SRC (set);
  if (GET_CODE (src) != COMPARE)
    return NULL;

  dest = SET_DEST (set);
  if (!REG_P (dest) || REGNO (dest) != targetm.flags_regnum)
    return NULL;

  if (REG_P (XEXP (src, 0))
      && REG_P (XEXP (src, 0))
      && (REG_P (XEXP (src, 1)) || CONSTANT_P (XEXP (src, 1))))
    return src;

  return NULL;
}

/* Look for a pattern of the "correct" form for an insn with a flags clobber
   for which we may be able to eliminate a compare later.  We're not looking
   to validate any inputs at this time, merely see that the basic shape is
   correct.  The term "arithmetic" may be somewhay misleading...  */

static bool
arithmetic_flags_clobber_p (rtx insn)
{
  rtx pat, x;

  if (!NONJUMP_INSN_P (insn))
    return false;
  pat = PATTERN (insn);
  if (extract_asm_operands (pat))
    return false;

  if (GET_CODE (pat) == PARALLEL && XVECLEN (pat, 0) == 2)
    {
      x = XVECEXP (pat, 0, 0);
      if (GET_CODE (x) != SET)
	return false;
      x = SET_DEST (x);
      if (!REG_P (x))
	return false;

      x = XVECEXP (pat, 0, 1);
      if (GET_CODE (x) == CLOBBER)
	{
	  x = XEXP (x, 0);
	  if (REG_P (x) && REGNO (x) == targetm.flags_regnum)
	    return true;
	}
    }

  return false;
}

/* Look for uses of FLAGS in INSN.  If we find one we can analyze, record
   it in CMP; otherwise indicate that we've missed a use.  */

static void
find_flags_uses_in_insn (struct comparison *cmp, rtx insn)
{
  df_ref *use_rec, use;

  /* If we've already lost track of uses, don't bother collecting more.  */
  if (cmp->missing_uses)
    return;

  /* Find a USE of the flags register.  */
  for (use_rec = DF_INSN_USES (insn); (use = *use_rec) != NULL; use_rec++)
    if (DF_REF_REGNO (use) == targetm.flags_regnum)
      {
	rtx x, *loc;

	/* If this is an unusual use, quit.  */
	if (DF_REF_TYPE (use) != DF_REF_REG_USE)
	  goto fail;

	/* If we've run out of slots to record uses, quit.  */
	if (cmp->n_uses == MAX_CMP_USE)
	  goto fail;

	/* Unfortunately, the location of the flags register, while
	   present in the reference structure, doesn't help.  We need
	   to find the comparison code that is outer to the actual
	   flags use.  */
	loc = DF_REF_LOC (use);
	x = PATTERN (insn);
	if (GET_CODE (x) == PARALLEL)
	  x = XVECEXP (x, 0, 0);
	x = SET_SRC (x);
	if (GET_CODE (x) == IF_THEN_ELSE)
	  x = XEXP (x, 0);
	if (COMPARISON_P (x)
	    && loc == &XEXP (x, 0)
	    && XEXP (x, 1) == const0_rtx)
	  {
	    /* We've found a use of the flags that we understand.  */
	    struct comparison_use *cuse = &cmp->uses[cmp->n_uses++];
	    cuse->insn = insn;
	    cuse->loc = loc;
	    cuse->code = GET_CODE (x);
	  }
	else
	  goto fail;
      }
  return;

 fail:
  /* We failed to recognize this use of the flags register.  */
  cmp->missing_uses = true;
}

/* Identify comparison instructions within BB.  If the last compare in the BB
   is valid at the end of the block, install it in BB->AUX.  Called via 
   walk_dominators_tree.  */

static void
find_comparisons_in_bb (struct dom_walk_data *data ATTRIBUTE_UNUSED,
			basic_block bb)
{
  struct comparison *last_cmp;
  rtx insn, next, last_clobber;
  bool last_cmp_valid;
  bitmap killed;

  killed = BITMAP_ALLOC (NULL);

  /* The last comparison that was made.  Will be reset to NULL
     once the flags are clobbered.  */
  last_cmp = NULL;

  /* True iff the last comparison has not been clobbered, nor
     have its inputs.  Used to eliminate duplicate compares.  */
  last_cmp_valid = false;

  /* The last insn that clobbered the flags, if that insn is of
     a form that may be valid for eliminating a following compare.
     To be reset to NULL once the flags are set otherwise.  */
  last_clobber = NULL;

  /* Propagate the last live comparison throughout the extended basic block.  */
  if (single_pred_p (bb))
    {
      last_cmp = (struct comparison *) single_pred (bb)->aux;
      if (last_cmp)
	last_cmp_valid = last_cmp->inputs_valid;
    }

  for (insn = BB_HEAD (bb); insn; insn = next)
    {
      rtx src;

      next = (insn == BB_END (bb) ? NULL_RTX : NEXT_INSN (insn));
      if (!NONDEBUG_INSN_P (insn))
	continue;

      src = conforming_compare (insn);
      if (src)
	{
	  /* Eliminate a compare that's redundant with the previous.  */
	  if (last_cmp_valid
	      && rtx_equal_p (last_cmp->in_a, XEXP (src, 0))
	      && rtx_equal_p (last_cmp->in_b, XEXP (src, 1)))
	    {
	      delete_insn (insn);
	      continue;
	    }

          last_cmp = XCNEW (struct comparison);
	  last_cmp->insn = insn;
	  last_cmp->prev_clobber = last_clobber;
	  last_cmp->in_a = XEXP (src, 0);
	  last_cmp->in_b = XEXP (src, 1);
	  last_cmp->orig_mode = GET_MODE (SET_DEST (single_set (insn)));
	  VEC_safe_push (comparison_struct_p, heap, all_compares, last_cmp);

	  /* It's unusual, but be prepared for comparison patterns that
	     also clobber an input, or perhaps a scratch.  */
	  last_clobber = NULL;
	  last_cmp_valid = true;
	  bitmap_clear (killed);
	  df_simulate_find_defs (insn, killed);
	}
      else
	{
	  /* Notice if this instruction kills the flags register.  */
	  bitmap_clear (killed);
	  df_simulate_find_defs (insn, killed);
	  if (bitmap_bit_p (killed, targetm.flags_regnum))
	    {
	      /* See if this insn could be the "clobber" that eliminates
		 a future comparison.   */
	      if (arithmetic_flags_clobber_p (insn))
		last_clobber = insn;
	      else
		last_clobber = NULL;

	      /* In either case, the previous compare is no longer valid.  */
	      last_cmp = NULL;
	      last_cmp_valid = false;
	      continue;
	    }

	  /* Notice if this insn uses the flags register.  */
	  if (last_cmp)
	    find_flags_uses_in_insn (last_cmp, insn);
	}

      /* Notice if any of the inputs to the comparison have changed.  */
      if (last_cmp
	  && (bitmap_bit_p (killed, REGNO (last_cmp->in_a))
	      || (REG_P (last_cmp->in_b)
		  && bitmap_bit_p (killed, REGNO (last_cmp->in_b)))))
	last_cmp_valid = false;
    }

  BITMAP_FREE (killed);

  /* Remember the live comparison for subsequent members of
     the extended basic block.  */
  if (last_cmp)
    {
      bb->aux = last_cmp;
      last_cmp->inputs_valid = last_cmp_valid;

      /* Look to see if the flags register is live outgoing here, and
	 incoming to any successor not part of the extended basic block.  */
      if (bitmap_bit_p (&DF_LIVE_BB_INFO (bb)->out, targetm.flags_regnum))
	{
	  edge e;
	  edge_iterator ei;

	  FOR_EACH_EDGE (e, ei, bb->succs)
	    {
	      basic_block dest = e->dest;
	      if (bitmap_bit_p (&DF_LIVE_BB_INFO (dest)->in,
				targetm.flags_regnum)
		  && !single_pred_p (dest))
		{
		  last_cmp->missing_uses = true;
		  break;
		}
	    }
	}
    }
}

/* Find all comparisons in the function.  */

static void
find_comparisons (void)
{
  struct dom_walk_data data;

  memset (&data, 0, sizeof(data));
  data.dom_direction = CDI_DOMINATORS;
  data.before_dom_children = find_comparisons_in_bb;

  calculate_dominance_info (CDI_DOMINATORS);

  init_walk_dominator_tree (&data);
  walk_dominator_tree (&data, ENTRY_BLOCK_PTR);
  fini_walk_dominator_tree (&data);

  clear_aux_for_blocks ();
  free_dominance_info (CDI_DOMINATORS);
}

/* Select an alternate CC_MODE for a comparison insn comparing A and B.
   Note that inputs are almost certainly different than the IN_A and IN_B
   stored in CMP -- we're called while attempting to eliminate the compare
   after all.  Return the new FLAGS rtx if successful, else return NULL.  */

static rtx
maybe_select_cc_mode (struct comparison *cmp, rtx a, rtx b)
{
  enum machine_mode sel_mode;
  const int n = cmp->n_uses;
  rtx flags = NULL;

#ifndef SELECT_CC_MODE
  /* Minimize code differences when this target macro is undefined.  */
  return NULL;
#define SELECT_CC_MODE(A,B,C) (gcc_unreachable (), VOIDmode)
#endif

  /* If we don't have access to all of the uses, we can't validate.  */
  if (cmp->missing_uses || n == 0)
    return NULL;

  /* Find a new mode that works for all of the uses.  Special case the
     common case of exactly one use.  */
  if (n == 1)
    {
      sel_mode = SELECT_CC_MODE (cmp->uses[0].code, a, b);
      if (sel_mode != cmp->orig_mode)
	{
	  flags = gen_rtx_REG (sel_mode, targetm.flags_regnum);
	  validate_change (cmp->uses[0].insn, cmp->uses[0].loc, flags, true);
	}
    }
  else
    {
      int i;

      sel_mode = SELECT_CC_MODE (cmp->uses[0].code, a, b);
      for (i = 1; i < n; ++i)
	{
	  enum machine_mode new_mode;
	  new_mode = SELECT_CC_MODE (cmp->uses[i].code, a, b);
	  if (new_mode != sel_mode)
	    {
	      sel_mode = targetm.cc_modes_compatible (sel_mode, new_mode);
	      if (sel_mode == VOIDmode)
		return NULL;
	    }
	}
      
      if (sel_mode != cmp->orig_mode)
	{
	  flags = gen_rtx_REG (sel_mode, targetm.flags_regnum);
	  for (i = 0; i < n; ++i)
	    validate_change (cmp->uses[i].insn, cmp->uses[i].loc, flags, true);
	}
    }

  return flags;
}

/* Attempt to find an instruction prior to CMP that can be used to compute the
   same flags value as the comparison itself.  Return true if successful.  */

static bool
try_eliminate_compare (struct comparison *cmp)
{
  rtx x, insn, bb_head, flags, in_a, cmp_src;

  /* We must have found an interesting "clobber" preceeding the compare.  */
  if (cmp->prev_clobber == NULL)
    return false;

  /* ??? For the moment we don't handle comparisons for which IN_B
     is a register.  We accepted these during initial comparison 
     recognition in order to eliminate duplicate compares.
     An improvement here would be to handle x = a - b; if (a < b).  */
  if (!CONSTANT_P (cmp->in_b))
    return false;

  /* Verify that PREV_CLOBBER defines IN_A, and that IN_A is not clobbered
     in between.  Given that this target requires this pass, we can assume
     that most insns do clobber the flags, and so the distance between the
     compare and the clobber is likely to be small.  */
  /* ??? This is one point at which one could argue that DF_REF_CHAIN would
     be useful, but it is thought to be too heavy-weight a solution here.  */

  in_a = cmp->in_a;
  insn = cmp->insn;
  bb_head = BB_HEAD (BLOCK_FOR_INSN (insn));
  for (insn = PREV_INSN (insn);
       insn != cmp->prev_clobber;
       insn = PREV_INSN (insn))
    {
      const int abnormal_flags
	= (DF_REF_CONDITIONAL | DF_REF_PARTIAL | DF_REF_MAY_CLOBBER
	   | DF_REF_MUST_CLOBBER | DF_REF_SIGN_EXTRACT
	   | DF_REF_ZERO_EXTRACT | DF_REF_STRICT_LOW_PART
	   | DF_REF_PRE_POST_MODIFY);

      df_ref *def_rec, def;

      /* Note that the BB_HEAD is always either a note or a label, but in
	 any case it means that IN_A is defined outside the block.  */
      if (insn == bb_head)
	return false;
      if (NOTE_P (insn) || DEBUG_INSN_P (insn))
	continue;

      /* Find a possible def of IN_A in INSN.  */
      for (def_rec = DF_INSN_DEFS (insn); (def = *def_rec) != NULL; def_rec++)
	if (DF_REF_REGNO (def) == REGNO (in_a))
	  break;

      /* No definitions of IN_A; continue searching.  */
      if (def == NULL)
	continue;

      /* Bail if this is not a totally normal set of IN_A.  */
      if (DF_REF_IS_ARTIFICIAL (def))
	return false;
      if (DF_REF_FLAGS (def) & abnormal_flags)
	return false;

      /* We've found an insn between the compare and the clobber that sets
	 IN_A.  Given that pass_cprop_hardreg has not yet run, we still find
	 situations in which we can usefully look through a copy insn.  */
      x = single_set (insn);
      if (x == NULL)
	return false;
      in_a = SET_SRC (x);
      if (!REG_P (in_a))
	return false;
    }

  /* We've reached PREV_CLOBBER without finding a modification of IN_A.
     Validate that PREV_CLOBBER itself does in fact refer to IN_A.  Do
     recall that we've already validated the shape of PREV_CLOBBER.  */
  x = XVECEXP (PATTERN (insn), 0, 0);
  if (!rtx_equal_p (SET_DEST (x), in_a))
    return false;
  cmp_src = SET_SRC (x);
  
  /* Determine if we ought to use a different CC_MODE here.  */
  flags = maybe_select_cc_mode (cmp, cmp_src, cmp->in_b);
  if (flags == NULL)
    flags = gen_rtx_REG (cmp->orig_mode, targetm.flags_regnum);

  /* Generate a new comparison for installation in the setter.  */
  x = copy_rtx (cmp_src);
  x = gen_rtx_COMPARE (GET_MODE (flags), x, cmp->in_b);
  x = gen_rtx_SET (VOIDmode, flags, x);

  /* Succeed if the new instruction is valid.  */
  validate_change (insn, &XVECEXP (PATTERN (insn), 0, 1), x, true);
  if (!apply_change_group ())
    return false;
 
  /* Success.  Delete the compare insn...  */
  delete_insn (cmp->insn);

  /* ... and any notes that are now irrelevant due to multi-stores. */
  x = find_regno_note (insn, REG_UNUSED, targetm.flags_regnum);
  if (x)
    remove_note (insn, x);
  x = find_reg_note (insn, REG_EQUAL, NULL);
  if (x)
    remove_note (insn, x);
  x = find_reg_note (insn, REG_EQUIV, NULL);
  if (x)
    remove_note (insn, x);

  return true;
}

/* Main entry point to the pass.  */

static unsigned int
execute_compare_elim_after_reload (void)
{
  df_set_flags (DF_DEFER_INSN_RESCAN);
  df_live_add_problem ();
  df_analyze ();

  gcc_checking_assert (all_compares == NULL);

  /* Locate all comparisons and their uses, and eliminate duplicates.  */
  find_comparisons ();
  if (all_compares)
    {
      struct comparison *cmp;
      size_t i;

      /* Eliminate comparisons that are redundant with flags computation.  */
      FOR_EACH_VEC_ELT (comparison_struct_p, all_compares, i, cmp)
	{
	  try_eliminate_compare (cmp);
	  XDELETE (cmp);
	}

      VEC_free (comparison_struct_p, heap, all_compares);
      all_compares = NULL;

      df_analyze ();
    }

  return 0;
}

static bool
gate_compare_elim_after_reload (void)
{
  return (flag_compare_elim_after_reload
	  && targetm.flags_regnum != INVALID_REGNUM);
}

struct rtl_opt_pass pass_compare_elim_after_reload =
{
 {
  RTL_PASS,
  "cmpelim",				/* name */
  gate_compare_elim_after_reload,	/* gate */
  execute_compare_elim_after_reload,	/* execute */
  NULL,					/* sub */
  NULL,					/* next */
  0,					/* static_pass_number */
  TV_NONE,				/* tv_id */
  0,					/* properties_required */
  0,					/* properties_provided */
  0,					/* properties_destroyed */
  0,					/* todo_flags_start */
  TODO_df_finish
  | TODO_df_verify
  | TODO_verify_rtl_sharing
  | TODO_dump_func
  | TODO_ggc_collect			/* todo_flags_finish */
 }
};

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [RFC, v2] New -fcompare-elim pass
  2011-01-17 22:42         ` [RFC, v2] " Richard Henderson
@ 2011-01-18 10:06           ` Paolo Bonzini
  2011-01-21 17:54             ` [RFC, v3] " Richard Henderson
  0 siblings, 1 reply; 90+ messages in thread
From: Paolo Bonzini @ 2011-01-18 10:06 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, law

On 01/17/2011 11:26 PM, Richard Henderson wrote:
> Version 2, based on Paolo's comments from v1.
>
> Comments?

Just a few nits:

1) a comment above maybe_select_cc_mode and above its call, stating that 
the function starts a change group, would be nice.  I missed this in the 
previous review.  Given the very nice comments in the code, it would be 
a nice touch.

2) Here:

>       src = conforming_compare (insn);
>       if (src)
> 	{
> 	  ...
> 	  bitmap_clear (killed);
> 	  df_simulate_find_defs (insn, killed);
> 	}
>       else
> 	{
> 	  /* Notice if this instruction kills the flags register.  */
> 	  bitmap_clear (killed);
> 	  df_simulate_find_defs (insn, killed);

The bitmap_clear/df_simulate_find_defs can be hoisted above the if.  The 
only case where we don't use the result is when we delete a redundant 
compare, and it's definitely not the common case.  This would make it 
clearer that KILLED is not used for any kind of real "simulation", but 
only as a quick way to query the array of DEFs for the presence of a 
register.

3) Just to take back that clock cycle lost in the above change, here:

>       if (last_cmp
> 	  && (bitmap_bit_p (killed, REGNO (last_cmp->in_a))
> 	      || (REG_P (last_cmp->in_b)
> 		  && bitmap_bit_p (killed, REGNO (last_cmp->in_b)))))
> 	last_cmp_valid = false;

You can change LAST_CMP to LAST_CMP_VALID.  LAST_CMP will never be NULL 
as long as LAST_CMP_VALID is true, but you may save some bitmap accesses.

4) Not a task for now, but perhaps some DF functions could be provided 
also in a form that operates on HARD_REG_SETs for improved performance. 
  Just a reminder to myself.


Besides this, "seems to be perfect".

Paolo

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 12/28] mn10300: Re-write move patterns.
  2011-01-10 20:33 ` [PATCH 12/28] mn10300: Re-write move patterns Richard Henderson
@ 2011-01-18 17:12   ` Jeff Law
  2011-01-18 18:30     ` Richard Henderson
  2011-01-18 19:18     ` Richard Henderson
  0 siblings, 2 replies; 90+ messages in thread
From: Jeff Law @ 2011-01-18 17:12 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, Richard Henderson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/10/11 13:31, Richard Henderson wrote:
> From: Richard Henderson <rth@twiddle.net>
> 
> Use the "D" and "A" constraints, and the enabled attribute to
> unify all ofthe integer move patterns.  Delete the fake double
> word move patterns; let the middle-end generate subregs as required.
> 
> Unfortunately, this somehow exposes a register pressure problem
> with the udivmod pattern.  This is properly fixed with subsequent
> patches that expose the MDR register.
> 
> In the meantime it is highly desirable to to preserve bisect-ability
> of the patch series, so disable this pattern for AM30.
Ideally we'd like to zap alternative 0 in the movxx patterns (nop move
register to itself).  IIRC such moves can occur in unoptimized compilations.

The mn103 series can't encode a reg->reg copy where the source and
destination registers are the same.  That situation tells the decoder
that the instruction is a multi-byte instruction and that it must look
at subsequent bytes to determine exactly what the instruction does.

IIRC returning an empty string for that case didn't work because the
empty string had some kind of special meaning in final.  (This was 13 or
14 years ago, so please forgive the IIRC's :-)

The net result is I think you have to return something for those
alternatives rather than an empty string.


It also seems to me that for movqi/movhi we want to severely disparage
the address regs on the mn103.  IIRC for the base mn103 we would trigger
reload failures if we didn't expose a0-a3 to the movqi/movhi patterns.
However, while the a0-a3 regs can hold such values, they can't be used
in arithmetic/logicals/etc in QI/HI mode.  So to avoid pessimizing code
we exposed a0-a3 in the QI/HI mode moves, but ignored them for register
class preferencing and severely disparaged them for reloading.

It also looks like you lost the movu am33 variant for movqi/movhi.  I
don't recall anything about that alternative, but I can hazard a guess
that movu is smaller than the more generic mov instruction for certain
constants.

I suspect losing the fmov variant for movqi/movhi is a good thing :-)
Presumably we ensure that the FP registers can't hold HImode/QImode
values elsewhere ;-)

It looks like you lost movu for the base mn103 in the movsi pattern and
for all the parts in the movsf pattern (it may not matter there).

The DI/DF mode stuff looks good.  We might regress a little for certain
specific constants, but it shouldn't be too bad.

Jeff







> ---
>  gcc/config/mn10300/mn10300.md |  930 ++++++++---------------------------------
>  1 files changed, 166 insertions(+), 764 deletions(-)
> 
> diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md
> index 04ec1b1..6e0e1a2 100644
> --- a/gcc/config/mn10300/mn10300.md
> +++ b/gcc/config/mn10300/mn10300.md
> @@ -181,107 +181,42 @@
>    [(set (match_operand:QI 0 "nonimmediate_operand")
>  	(match_operand:QI 1 "general_operand"))]
>    ""
> -  "
>  {
>    /* One of the ops has to be in a register.  */
>    if (!register_operand (operand0, QImode)
>        && !register_operand (operand1, QImode))
> -    operands[1] = copy_to_mode_reg (QImode, operand1);
> -}")
> -
> -(define_insn "*am33_movqi"
> -  [(set (match_operand:QI 0 "nonimmediate_operand"
> -			  ;; 0       1      2      3     4       5
> -			  "=d*x*a*f, d*x*a, d*x*a, m,   *f,      d*x*a")
> -	(match_operand:QI 1 "general_operand"
> -			   "0,       d*xai, m,     d*xa, d*xa*f, *f"))]
> -  "TARGET_AM33
> -   && (register_operand (operands[0], QImode)
> -       || register_operand (operands[1], QImode))"
> -  "*
> -  {
> -    switch (which_alternative)
> -      {
> -      case 0:
> -        return \"nop\";
> -      case 1:
> -        gcc_assert (! CONST_DOUBLE_P (operands[1]));
> -
> -        if (REGNO_REG_CLASS (true_regnum (operands[0])) == EXTENDED_REGS
> -	    && CONST_INT_P (operands[1]))
> -	  {
> -	    HOST_WIDE_INT val = INTVAL (operands[1]);
> -
> -	    if (((val & 0x80) && ! (val & 0xffffff00))
> -	        || ((val & 0x800000) && ! (val & 0xff000000)))
> -	      return \"movu %1,%0\";
> -	  }
> -        return \"mov %1,%0\";
> -      case 2:
> -      case 3:
> -        return \"movbu %1,%0\";
> -      case 4:
> -      case 5:
> -        return \"fmov %1,%0\";
> -      default:
> -        gcc_unreachable ();
> -      }
> -  }"
> -  [(set_attr_alternative "timings"
> -			 [(const_int 11)
> -			  (if_then_else (eq_attr "cpu" "am34")
> -					(const_int 11) (const_int 22))
> -			  (if_then_else (eq_attr "cpu" "am34")
> -					(const_int 13) (const_int 24))
> -			  (if_then_else (eq_attr "cpu" "am34")
> -					(const_int 13) (const_int 24))
> -			  (if_then_else (eq_attr "cpu" "am34")
> -					(const_int 47) (const_int 25))
> -			  (if_then_else (eq_attr "cpu" "am34")
> -					(const_int 47) (const_int 25))
> -			 ])
> -  ]
> -)
> +    operands[1] = force_reg (QImode, operand1);
> +})
>  
> -(define_insn "*mn10300_movqi"
> -  [(set (match_operand:QI 0 "nonimmediate_operand" "=d*a,d,d,!*a,d*a,d,m")
> -	(match_operand:QI 1 "general_operand"       "0,  I,i,i,  da, m,d"))]
> -  "register_operand (operands[0], QImode)
> -   || register_operand (operands[1], QImode)"
> -  "*
> +(define_insn "*movqi_internal"
> +  [(set (match_operand:QI 0 "nonimmediate_operand" "=*r,D*r,D*r,D,m")
> +	(match_operand:QI 1 "general_operand"      "  0,D*r,  i,m,D"))]
> +  "(register_operand (operands[0], QImode)
> +    || register_operand (operands[1], QImode))"
>  {
>    switch (which_alternative)
>      {
>      case 0:
> -      return \"nop\";
> +      return "";
>      case 1:
>      case 2:
> +      return "mov %1,%0";
>      case 3:
>      case 4:
> -      gcc_assert (! CONST_DOUBLE_P (operands[1]));
> -      return \"mov %1,%0\";
> -    case 5:
> -    case 6:
> -      return \"movbu %1,%0\";
> +      return "movbu %1,%0";
>      default:
>        gcc_unreachable ();
>      }
> -}"
> +}
>    [(set_attr_alternative "timings"
> -			 [(const_int 11)
> -			  (const_int 11)
> -			  (if_then_else (eq_attr "cpu" "am34")
> -			  		(const_int 11) (const_int 22))
> -			  (if_then_else (eq_attr "cpu" "am34")
> -			  		(const_int 11) (const_int 22))
> -			  (if_then_else (eq_attr "cpu" "am34")
> -			  		(const_int 11) (const_int 22))
> -			  (if_then_else (eq_attr "cpu" "am34")
> -			  		(const_int 13) (const_int 24))
> -			  (if_then_else (eq_attr "cpu" "am34")
> -			  		(const_int 13) (const_int 24))
> -			 ])
> -  ]
> +	 [(const_int 11)
> +	  (const_int 11)
> +	  (const_int 11)
> +	  (if_then_else (eq_attr "cpu" "am34")
> +			(const_int 13) (const_int 24))
> +	  (if_then_else (eq_attr "cpu" "am34")
> +			(const_int 11) (const_int 22))
> +	 ])]
>  )
>  
>  ;; movhi
> @@ -290,107 +225,48 @@
>    [(set (match_operand:HI 0 "nonimmediate_operand")
>  	(match_operand:HI 1 "general_operand"))]
>    ""
> -  "
>  {
>    /* One of the ops has to be in a register.  */
>    if (!register_operand (operand1, HImode)
>        && !register_operand (operand0, HImode))
> -    operands[1] = copy_to_mode_reg (HImode, operand1);
> -}")
> -
> -(define_insn "*am33_movhi"
> -  [(set (match_operand:HI 0 "nonimmediate_operand"
> -			  ;; 0       1       2      3     4         5
> -			  "=d*x*a*f, d*x*a,  d*x*a, m,    *f,       d*x*a")
> -	(match_operand:HI 1 "general_operand"
> -			  "0,        d*x*ai, m,     d*x*a, d*x*a*f, *f"))]
> -  "TARGET_AM33
> -   && (register_operand (operands[0], HImode)
> -       || register_operand (operands[1], HImode))"
> -  "*
> -{
> -  switch (which_alternative)
> -    {
> -    case 0:
> -      return \"nop\";
> -    case 1:
> -      gcc_assert (! CONST_DOUBLE_P (operands[1]));
> -
> -      if (REGNO_REG_CLASS (true_regnum (operands[0])) == EXTENDED_REGS
> -	  && CONST_INT_P (operands[1]))
> -	{
> -	  HOST_WIDE_INT val = INTVAL (operands[1]);
> -
> -	  if (((val & 0x80) && ! (val & 0xffffff00))
> -	      || ((val & 0x800000) && ! (val & 0xff000000)))
> -	    return \"movu %1,%0\";
> -	}
> -      return \"mov %1,%0\";
> -    case 2:
> -    case 3:
> -      return \"movhu %1,%0\";
> -    case 4:
> -    case 5:
> -      return \"fmov %1,%0\";
> -    default:
> -      gcc_unreachable ();
> -    }
> -}"
> -  [(set_attr_alternative "timings"
> -			 [(const_int 11)
> -			  (if_then_else (eq_attr "cpu" "am34")
> -			  		(const_int 11) (const_int 22))
> -			  (if_then_else (eq_attr "cpu" "am34")
> -			  		(const_int 13) (const_int 24))
> -			  (if_then_else (eq_attr "cpu" "am34")
> -			  		(const_int 13) (const_int 24))
> -			  (if_then_else (eq_attr "cpu" "am34")
> -			  		(const_int 47) (const_int 25))
> -			  (if_then_else (eq_attr "cpu" "am34")
> -			  		(const_int 47) (const_int 25))
> -			 ])
> -  ]
> -)
> +    operands[1] = force_reg (HImode, operand1);
> +})
>  
> -(define_insn "*mn10300_movhi"
> -  [(set (match_operand:HI 0 "nonimmediate_operand" "=d*a,d,d,!*a,d*a,d,m")
> -	(match_operand:HI 1 "general_operand"       "0,  I,i,i,  da, m,d"))]
> -  "register_operand (operands[0], HImode)
> -   || register_operand (operands[1], HImode)"
> -  "*
> +(define_insn "*movhi_internal"
> +  [(set (match_operand:HI 0 "nonimmediate_operand" "=*r,D*r,D*r,D,m")
> +	(match_operand:HI 1 "general_operand"      "  0,  i,D*r,m,D"))]
> +  "(register_operand (operands[0], HImode)
> +    || register_operand (operands[1], HImode))"
>  {
>    switch (which_alternative)
>      {
>      case 0:
> -      return \"nop\";
> +      return "";
>      case 1:
> +      if (TARGET_AM33
> +	  && CONST_INT_P (operands[1])
> +	  && IN_RANGE (INTVAL (operands[1]), 0x80, 0xff))
> +	return "movu %1,%0";
> +      /* FALLTHRU */
>      case 2:
> +      return "mov %1,%0";
>      case 3:
>      case 4:
> -      gcc_assert (! CONST_DOUBLE_P (operands[1]));
> -      return \"mov %1,%0\";
> -    case 5:
> -    case 6:
> -      return \"movhu %1,%0\";
> +      return "movhu %1,%0";
>      default:
>        gcc_unreachable ();
>      }
> -}"
> +}
>    [(set_attr_alternative "timings"
> -			 [(const_int 11)
> -			  (const_int 11)
> -			  (if_then_else (eq_attr "cpu" "am34")
> -			  		(const_int 11) (const_int 22))
> -			  (if_then_else (eq_attr "cpu" "am34")
> -			  		(const_int 11) (const_int 22))
> -			  (if_then_else (eq_attr "cpu" "am34")
> -			  		(const_int 11) (const_int 22))
> -			  (if_then_else (eq_attr "cpu" "am34")
> -			  		(const_int 13) (const_int 24))
> -			  (if_then_else (eq_attr "cpu" "am34")
> -			  		(const_int 13) (const_int 24))
> -			 ])
> -  ]
> +	 [(const_int 11)
> +	  (const_int 11)
> +	  (if_then_else (eq_attr "cpu" "am34")
> +	  		(const_int 11) (const_int 22))
> +	  (if_then_else (eq_attr "cpu" "am34")
> +	  		(const_int 13) (const_int 24))
> +	  (if_then_else (eq_attr "cpu" "am34")
> +	  		(const_int 11) (const_int 22))
> +	 ])]
>  )
>  
>  ;; movsi and helpers
> @@ -450,12 +326,11 @@
>    [(set (match_operand:SI 0 "nonimmediate_operand")
>  	(match_operand:SI 1 "general_operand"))]
>    ""
> -  "
>  {
>    /* One of the ops has to be in a register.  */
>    if (!register_operand (operand1, SImode)
>        && !register_operand (operand0, SImode))
> -    operands[1] = copy_to_mode_reg (SImode, operand1);
> +    operands[1] = force_reg (SImode, operand1);
>    if (flag_pic)
>      {
>        rtx temp;
> @@ -486,594 +361,118 @@
>  				      0, OPTAB_LIB_WIDEN);
>  	}
>      }
> -}")
> +})
>  
>  (define_insn "*movsi_internal"
>    [(set (match_operand:SI 0 "nonimmediate_operand"
> -			  "=dax, dax,  m,   dax, ax,!*y")
> +			  "=r,r,r,m,r, A,*y,*y")
>  	(match_operand:SI 1 "general_operand"
> -			  "0,    Idax, dax, im, !*y, ax"))
> -  ]
> +			  " 0,i,r,r,m,*y, A, i"))]
>    "register_operand (operands[0], SImode)
>     || register_operand (operands[1], SImode)"
> -  "*
> -  {
> -    if (which_alternative == 0)
> -      return \"nop\";
> -
> -    gcc_assert (! CONST_DOUBLE_P (operands[1]));
> -
> -    if (REGNO_REG_CLASS (true_regnum (operands[0])) == EXTENDED_REGS
> -        && CONST_INT_P (operands[1]))
> -      {
> -        HOST_WIDE_INT val = INTVAL (operands[1]);
> -
> -        if (((val & 0x80) && ! (val & 0xffffff00))
> -            || ((val & 0x800000) && ! (val & 0xff000000)))
> -          return \"movu %1, %0\";
> -      }
> -
> -    return \"mov %1, %0\";
> -  }"
> -  [(set_attr_alternative "timings"
> -			 [(const_int 11)
> -			  (if_then_else (eq_attr "cpu" "am34")
> -					(const_int 13) (const_int 24))
> -			  (if_then_else (eq_attr "cpu" "am34")
> -					(const_int 13) (const_int 24))
> -			  (if_then_else (eq_attr "cpu" "am34")
> -					(const_int 13) (const_int 24))
> -			  (if_then_else (eq_attr "cpu" "am34")
> -					(const_int 13) (const_int 24))
> -			  (if_then_else (eq_attr "cpu" "am34")
> -					(const_int 13) (const_int 24))
> -			 ])
> -  ]
> +{
> +  switch (which_alternative)
> +    {
> +    case 0:
> +      return "";
> +    case 1: /* imm-reg*/
> +      if (TARGET_AM33 && CONST_INT_P (operands[1]))
> +	{
> +	  HOST_WIDE_INT val = INTVAL (operands[1]);
> +	  if (IN_RANGE (val, 0x80, 0xff)
> +	      || IN_RANGE (val, 0x800000, 0xffffff))
> +	    return "movu %1,%0";
> +	}
> +      /* FALLTHRU */
> +    case 2:  /* reg-reg */
> +    case 3:  /* reg-mem */
> +    case 4:  /* mem-reg */
> +    case 5:  /* sp-reg */
> +    case 6:  /* reg-sp */
> +    case 7:  /* imm-sp */
> +      return "mov %1,%0";
> +    default:
> +      gcc_unreachable ();
> +    }
> +}
> +  [(set_attr "isa" "*,*,*,*,*,*,*,am33")
> +   (set_attr_alternative "timings"
> +	 [(const_int 11)
> +	  (const_int 22)
> +	  (const_int 11)
> +	  (if_then_else (eq_attr "cpu" "am34")
> +			(const_int 11) (const_int 22))
> +	  (if_then_else (eq_attr "cpu" "am34")
> +			(const_int 13) (const_int 24))
> +	  (if_then_else (eq_attr "cpu" "am34")
> +			(const_int 11) (const_int 22))
> +	  (if_then_else (eq_attr "cpu" "am34")
> +			(const_int 13) (const_int 24))
> +	  (const_int 11)
> +	 ])]
>  )
>  
>  (define_expand "movsf"
>    [(set (match_operand:SF 0 "nonimmediate_operand")
>  	(match_operand:SF 1 "general_operand"))]
> -  ""
> -  "
> +  "TARGET_AM33_2"
>  {
>    /* One of the ops has to be in a register.  */
>    if (!register_operand (operand1, SFmode)
>        && !register_operand (operand0, SFmode))
> -    operands[1] = copy_to_mode_reg (SFmode, operand1);
> -}")
> +    operands[1] = force_reg (SFmode, operand1);
> +})
>  
>  (define_insn "*movsf_internal"
> -  [(set (match_operand:SF 0 "nonimmediate_operand"
> -			  ;; 0    1    2       3     4     5
> -			  "=fdxa, dxa, f,      dxaQ, daxm, dax")
> -	(match_operand:SF 1 "general_operand"
> -			  " 0,    G,   fdxaQF, f,    dax,  daxFm"))
> -  ]
> -  "register_operand (operands[0], SFmode)
> -   || register_operand (operands[1], SFmode)"
> -  "*
> -  {
> -    switch (which_alternative)
> -      {
> -      case 0:
> -        return \"nop\";
> -      /* case 1: below.  */
> -      case 2:
> -      case 3:
> -        return \"fmov %1, %0\";
> -      case 1:
> -      case 4:
> -      case 5:
> -        if (REGNO_REG_CLASS (true_regnum (operands[0])) == EXTENDED_REGS
> -	    && CONST_INT_P (operands[1]))
> -	  {
> -	    HOST_WIDE_INT val = INTVAL (operands[1]);
> -
> -	    if (((val & 0x80) && ! (val & 0xffffff00))
> -	        || ((val & 0x800000) && ! (val & 0xff000000)))
> -	      return \"movu %1, %0\";
> -	  }
> -        return \"mov %1, %0\";
> -      default:
> -        gcc_unreachable ();
> -      }
> -  }"
> -  [(set_attr_alternative "timings"
> -			 [(const_int 11)
> -			  (if_then_else (eq_attr "cpu" "am34")
> -					(const_int 13) (const_int 24))
> -			  (if_then_else (eq_attr "cpu" "am34")
> -					(const_int 47) (const_int 25))
> -			  (if_then_else (eq_attr "cpu" "am34")
> -					(const_int 47) (const_int 25))
> -			  (if_then_else (eq_attr "cpu" "am34")
> -					(const_int 13) (const_int 24))
> -			  (if_then_else (eq_attr "cpu" "am34")
> -					(const_int 13) (const_int 24))
> -			 ])
> -  ]
> -)
> -
> -(define_expand "movdi"
> -  [(set (match_operand:DI 0 "nonimmediate_operand")
> -	(match_operand:DI 1 "general_operand"))]
> -  ""
> -  "
> -{
> -  /* One of the ops has to be in a register.  */
> -  if (!register_operand (operand1, DImode)
> -      && !register_operand (operand0, DImode))
> -    operands[1] = copy_to_mode_reg (DImode, operand1);
> -}")
> -
> -
> -(define_insn "*movdi_internal"                   ;;   0 1  2  3 4   5   6  7 8  9
> -  [(set (match_operand:DI 0 "nonimmediate_operand" "=dx,ax,dx,a,dxm,dxm,a, a,dx,a")
> -	(match_operand:DI 1 "general_operand"        "0,0, I, I,dx, a,  dx,a,im,im"))]
> -  "register_operand (operands[0], DImode)
> -   || register_operand (operands[1], DImode)"
> -  "*
> +  [(set (match_operand:SF 0 "nonimmediate_operand" "=rf,r,f,r,f,r,f,r,m,f,Q")
> +	(match_operand:SF 1 "general_operand"	   "  0,F,F,r,f,f,r,m,r,Q,f"))]
> +  "TARGET_AM33_2
> +   && (register_operand (operands[0], SFmode)
> +       || register_operand (operands[1], SFmode))"
>  {
> -  long val[2];
> -  REAL_VALUE_TYPE rv;
> -
>    switch (which_alternative)
>      {
> -      case 0:
> -      case 1:
> -	return \"nop\";
> -
> -      case 2:
> -	return \"mov 0, %L0\;mov 0, %H0\";
> -
> -      case 3:
> -	if (rtx_equal_p (operands[0], operands[1]))
> -	  return \"sub %L1,%L0\;mov %L0,%H0\";
> -	else
> -	  return \"mov %1,%L0\;mov %L0,%H0\";
> -      case 4:
> -      case 5:
> -      case 6:
> -      case 7:
> -      case 8:
> -      case 9:
> -	if (CONST_INT_P (operands[1]))
> -	  {
> -	    rtx low, high;
> -	    split_double (operands[1], &low, &high);
> -	    val[0] = INTVAL (low);
> -	    val[1] = INTVAL (high);
> -	  }
> -	if (CONST_DOUBLE_P (operands[1]))
> -	  {
> -	    if (GET_MODE (operands[1]) == DFmode)
> -	      {
> -		REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
> -		REAL_VALUE_TO_TARGET_DOUBLE (rv, val);
> -	      }
> -	    else if (GET_MODE (operands[1]) == VOIDmode
> -		     || GET_MODE (operands[1]) == DImode)
> -	      {
> -		val[0] = CONST_DOUBLE_LOW (operands[1]);
> -		val[1] = CONST_DOUBLE_HIGH (operands[1]);
> -	      }
> -	  }
> -
> -	if (MEM_P (operands[1])
> -	    && reg_overlap_mentioned_p (operands[0], XEXP (operands[1], 0)))
> -	  {
> -	    rtx temp = operands[0];
> -
> -	    while (GET_CODE (temp) == SUBREG)
> -	      temp = SUBREG_REG (temp);
> -
> -	    gcc_assert (REG_P (temp));
> -
> -	    if (reg_overlap_mentioned_p (gen_rtx_REG (SImode, REGNO (temp)),
> -					 XEXP (operands[1], 0)))
> -	      return \"mov %H1,%H0\;mov %L1,%L0\";
> -	    else
> -	      return \"mov %L1,%L0\;mov %H1,%H0\";
> -
> -	  }
> -	else if (MEM_P (operands[1])
> -		 && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))
> -		 && REGNO_REG_CLASS (REGNO (operands[0])) == ADDRESS_REGS)
> -	  {
> -	    rtx xoperands[2];
> -
> -	    xoperands[0] = operands[0];
> -	    xoperands[1] = XEXP (operands[1], 0);
> -
> -	    output_asm_insn (\"mov %1,%L0\;mov (4,%L0),%H0\;mov (%L0),%L0\",
> -			     xoperands);
> -	    return \"\";
> -	  }
> -	else
> -	  {
> -	    if ((CONST_INT_P (operands[1])
> -		 || CONST_DOUBLE_P (operands[1]))
> -		&& val[0] == 0)
> -	      {
> -		if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
> -		  output_asm_insn (\"mov 0, %L0\", operands);
> -		else
> -		  output_asm_insn (\"mov %L1,%L0\", operands);
> -	      }
> -	    else if ((CONST_INT_P (operands[1])
> -		      || CONST_DOUBLE_P (operands[1]))
> -		     && (REGNO_REG_CLASS (true_regnum (operands[0]))
> -			 == EXTENDED_REGS)
> -		     && (((val[0] & 0x80) && ! (val[0] & 0xffffff00))
> -			 || ((val[0] & 0x800000) && ! (val[0] & 0xff000000))))
> -	      output_asm_insn (\"movu %L1,%L0\", operands);
> -	    else
> -	      output_asm_insn (\"mov %L1,%L0\", operands);
> -
> -	    if ((CONST_INT_P (operands[1])
> -		 || CONST_DOUBLE_P (operands[1]))
> -		&& val[1] == 0)
> -	      {
> -		if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
> -		  output_asm_insn (\"mov 0, %H0\", operands);
> -		else
> -		  output_asm_insn (\"mov %H1,%H0\", operands);
> -	      }
> -	    else if ((CONST_INT_P (operands[1])
> -		      || CONST_DOUBLE_P (operands[1]))
> -		     && val[0] == val[1])
> -	      output_asm_insn (\"mov %L0,%H0\", operands);
> -	    else if ((CONST_INT_P (operands[1])
> -		      || CONST_DOUBLE_P (operands[1]))
> -		     && (REGNO_REG_CLASS (true_regnum (operands[0]))
> -			 == EXTENDED_REGS)
> -		     && (((val[1] & 0x80) && ! (val[1] & 0xffffff00))
> -			 || ((val[1] & 0x800000) && ! (val[1] & 0xff000000))))
> -	      output_asm_insn (\"movu %H1,%H0\", operands);
> -	    else
> -	      output_asm_insn (\"mov %H1,%H0\", operands);
> -	    return \"\";
> -	  }
> -    default:
> -      gcc_unreachable ();
> -    }
> -  }"
> -  ;; The timing of "37" is an approximation of the worst case sceanario.
> -  [(set_attr_alternative "timings"
> -			 [(const_int 11)
> -			  (const_int 11)
> -			  (const_int 22)
> -			  (const_int 22)
> -			  (const_int 37)
> -			  (const_int 37)
> -			  (const_int 37)
> -			  (const_int 37)
> -			  (const_int 37)
> -			  (const_int 37)
> -			 ])
> -  ]
> -)
> -
> -(define_expand "movdf"
> -  [(set (match_operand:DF 0 "nonimmediate_operand")
> -	(match_operand:DF 1 "general_operand"))]
> -  ""
> -  "
> -{
> -  /* One of the ops has to be in a register.  */
> -  if (!register_operand (operand1, DFmode)
> -      && !register_operand (operand0, DFmode))
> -    operands[1] = copy_to_mode_reg (DFmode, operand1);
> -}")
> -
> -(define_insn "*am33_2_movdf"
> -  [(set (match_operand:DF 0 "nonimmediate_operand"
> -			  ;; 0   1   2    3    4 5 6   7   8  9 10 11
> -			  "=fdax,dax,fdxa,f,   f,Q,dxm,dxm,a, a,dx,a")
> -	(match_operand:DF 1 "general_operand"
> -			  " 0,   G,  f,   dxaF,Q,f,dx, a,  dx,a,Fm,Fm"))]
> -  "TARGET_AM33_2
> -   && (register_operand (operands[0], DFmode)
> -       || register_operand (operands[1], DFmode))"
> -  "*
> -  {
> -    long val[2];
> -    REAL_VALUE_TYPE rv;
> -
> -    switch (which_alternative)
> -      {
> -      case 0:
> -	return \"nop\";
> -
> -      case 1:
> -	return \"mov 0, %L0\; mov 0, %H0\";
> -
> -      case 2:
> -      case 3:
> -        return \"fmov %L1, %L0\; fmov %H1, %H0\";
> -
> -      case 4:
> -	if (MEM_P (operands[1])
> -	    && CONST_INT_P (XEXP (operands[1], 0))
> -	    && (INTVAL (XEXP (operands[1], 0)) & 7) == 0)
> -	  return \"fmov %D1, %D0\";
> -	else
> -          return \"fmov %L1, %L0\; fmov %H1, %H0\";
> -
> -      case 5:
> -	if (MEM_P (operands[0])
> -	    && CONST_INT_P (XEXP (operands[0], 0))
> -	    && (INTVAL (XEXP (operands[0], 0)) & 7) == 0)
> -	  return \"fmov %D1, %D0\";
> -	else
> -          return \"fmov %L1, %L0\; fmov %H1, %H0\";
> -
> -      case 6:
> -      case 7:
> -      case 8:
> -      case 9:
> -      case 10:
> -      case 11:
> -	if (CONST_INT_P (operands[1]))
> -	  {
> -	    rtx low, high;
> -	    split_double (operands[1], &low, &high);
> -	    val[0] = INTVAL (low);
> -	    val[1] = INTVAL (high);
> -	  }
> -	if (CONST_DOUBLE_P (operands[1]))
> -	  {
> -	    if (GET_MODE (operands[1]) == DFmode)
> -	      {
> -		REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
> -		REAL_VALUE_TO_TARGET_DOUBLE (rv, val);
> -	      }
> -	    else if (GET_MODE (operands[1]) == VOIDmode
> -		     || GET_MODE (operands[1]) == DImode)
> -	      {
> -		val[0] = CONST_DOUBLE_LOW (operands[1]);
> -		val[1] = CONST_DOUBLE_HIGH (operands[1]);
> -	      }
> -	  }
> -
> -	if (MEM_P (operands[1])
> -	    && reg_overlap_mentioned_p (operands[0], XEXP (operands[1], 0)))
> -	  {
> -	    rtx temp = operands[0];
> -
> -	    while (GET_CODE (temp) == SUBREG)
> -	      temp = SUBREG_REG (temp);
> -
> -	    gcc_assert (REG_P (temp));
> -
> -	    if (reg_overlap_mentioned_p (gen_rtx_REG (SImode, REGNO (temp)),
> -					 XEXP (operands[1], 0)))
> -	      return \"mov %H1, %H0\; mov %L1, %L0\";
> -	    else
> -	      return \"mov %L1, %L0\; mov %H1, %H0\";
> -
> -	  }
> -	else if (MEM_P (operands[1])
> -		 && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))
> -		 && REGNO_REG_CLASS (REGNO (operands[0])) == ADDRESS_REGS)
> -	  {
> -	    rtx xoperands[2];
> -
> -	    xoperands[0] = operands[0];
> -	    xoperands[1] = XEXP (operands[1], 0);
> -
> -	    output_asm_insn (\"mov %1, %L0\; mov (4, %L0), %H0\; mov (%L0), %L0\",
> -			     xoperands);
> -	    return \"\";
> -	  }
> -	else
> -	  {
> -	    if ((CONST_INT_P (operands[1])
> -		 || CONST_DOUBLE_P (operands[1]))
> -		&& val[0] == 0)
> -	      {
> -		if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
> -		  output_asm_insn (\"mov 0, %L0\", operands);
> -		else
> -		  output_asm_insn (\"mov %L1,%L0\", operands);
> -	      }
> -	    else if ((CONST_INT_P (operands[1])
> -		      || CONST_DOUBLE_P (operands[1]))
> -		     && (REGNO_REG_CLASS (true_regnum (operands[0]))
> -			 == EXTENDED_REGS)
> -		     && (((val[0] & 0x80) && ! (val[0] & 0xffffff00))
> -			 || ((val[0] & 0x800000) && ! (val[0] & 0xff000000))))
> -	      output_asm_insn (\"movu %L1, %L0\", operands);
> -	    else
> -	      output_asm_insn (\"mov %L1, %L0\", operands);
> -
> -	    if ((CONST_INT_P (operands[1])
> -		 || CONST_DOUBLE_P (operands[1]))
> -		&& val[1] == 0)
> -	      {
> -		if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
> -		  output_asm_insn (\"mov 0, %H0\", operands);
> -		else
> -		  output_asm_insn (\"mov %H1, %H0\", operands);
> -	      }
> -	    else if ((CONST_INT_P (operands[1])
> -		      || CONST_DOUBLE_P (operands[1]))
> -		     && val[0] == val[1])
> -	      output_asm_insn (\"mov %L0,%H0\", operands);
> -	    else if ((CONST_INT_P (operands[1])
> -		      || CONST_DOUBLE_P (operands[1]))
> -		     && (REGNO_REG_CLASS (true_regnum (operands[0]))
> -			 == EXTENDED_REGS)
> -		     && (((val[1] & 0x80) && ! (val[1] & 0xffffff00))
> -			 || ((val[1] & 0x800000) && ! (val[1] & 0xff000000))))
> -	      output_asm_insn (\"movu %H1, %H0\", operands);
> -	    else
> -	      output_asm_insn (\"mov %H1, %H0\", operands);
> -	    return \"\";
> -	  }
> +    case 0:
> +      return "";
> +    case 1:
> +    case 3:
> +    case 7:
> +    case 8:
> +      return "mov %1,%0";
> +    case 2:
> +    case 4:
> +    case 5:
> +    case 6:
> +    case 9:
> +    case 10:
> +      return "fmov %1,%0";
>      default:
>        gcc_unreachable ();
>      }
> -  }"
> -  ;; The timing of "37" is an approximation of the worst case sceanario.
> +}
>    [(set_attr_alternative "timings"
> -			 [(const_int 11)
> -			  (const_int 22)
> -			  (const_int 22)
> -			  (const_int 22)
> -			  (const_int 22)
> -			  (const_int 37)
> -			  (const_int 37)
> -			  (const_int 37)
> -			  (const_int 37)
> -			  (const_int 37)
> -			  (const_int 37)
> -			  (const_int 37)
> -			 ])
> -  ]
> +		 [(const_int 11)
> +		  (const_int 22)
> +		  (if_then_else (eq_attr "cpu" "am34")
> +				(const_int 47) (const_int 25))
> +		  (const_int 11)
> +		  (if_then_else (eq_attr "cpu" "am34")
> +				(const_int 13) (const_int 14))
> +		  (if_then_else (eq_attr "cpu" "am34")
> +				(const_int 13) (const_int 12))
> +		  (if_then_else (eq_attr "cpu" "am34")
> +				(const_int 13) (const_int 14))
> +		  (if_then_else (eq_attr "cpu" "am34")
> +				(const_int 13) (const_int 24))
> +		  (if_then_else (eq_attr "cpu" "am34")
> +				(const_int 13) (const_int 24))
> +		  (if_then_else (eq_attr "cpu" "am34")
> +				(const_int 13) (const_int 24))
> +		  (if_then_else (eq_attr "cpu" "am34")
> +				(const_int 13) (const_int 24))
> +		 ])]
>  )
>  
> -(define_insn "*mn10300_movdf"
> -  [(set (match_operand:DF 0 "nonimmediate_operand"
> -			  ;;0    1    2    3    4   5  6   7
> -			  "=dxa, dax, dxm, dxm, a,  a, dx, a")
> -	(match_operand:DF 1 "general_operand"
> -			  " 0,   G,   dx,  a,   dx, a, Fm, Fm"))]
> -  "register_operand (operands[0], DFmode)
> -   || register_operand (operands[1], DFmode)"
> -  "*
> -  {
> -    long val[2];
> -    REAL_VALUE_TYPE rv;
> -
> -    switch (which_alternative)
> -      {
> -      case 0:
> -	return \"nop\";
> -
> -      case 1:
> -	return \"mov 0, %L0\; mov 0, %H0\";
> -
> -      case 2:
> -      case 3:
> -      case 4:
> -      case 5:
> -      case 6:
> -      case 7:
> -	if (CONST_INT_P (operands[1]))
> -	  {
> -	    rtx low, high;
> -	    split_double (operands[1], &low, &high);
> -	    val[0] = INTVAL (low);
> -	    val[1] = INTVAL (high);
> -	  }
> -        if (CONST_DOUBLE_P (operands[1]))
> -	  {
> -	    if (GET_MODE (operands[1]) == DFmode)
> -	      {
> -		REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
> -		REAL_VALUE_TO_TARGET_DOUBLE (rv, val);
> -	      }
> -	    else if (GET_MODE (operands[1]) == VOIDmode
> -		     || GET_MODE (operands[1]) == DImode)
> -	      {
> -		val[0] = CONST_DOUBLE_LOW (operands[1]);
> -		val[1] = CONST_DOUBLE_HIGH (operands[1]);
> -	      }
> -	  }
> -
> -	if (MEM_P (operands[1])
> -	    && reg_overlap_mentioned_p (operands[0], XEXP (operands[1], 0)))
> -	  {
> -	    rtx temp = operands[0];
> -
> -	    while (GET_CODE (temp) == SUBREG)
> -	      temp = SUBREG_REG (temp);
> -
> -	    gcc_assert (REG_P (temp));
> -
> -	    if (reg_overlap_mentioned_p (gen_rtx_REG (SImode, REGNO (temp)),
> -					 XEXP (operands[1], 0)))
> -	      return \"mov %H1, %H0\; mov %L1, %L0\";
> -	    else
> -	      return \"mov %L1, %L0\; mov %H1, %H0\";
> -	  }
> -	else if (MEM_P (operands[1])
> -		 && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))
> -		 && REGNO_REG_CLASS (REGNO (operands[0])) == ADDRESS_REGS)
> -	  {
> -	    rtx xoperands[2];
> -
> -	    xoperands[0] = operands[0];
> -	    xoperands[1] = XEXP (operands[1], 0);
> -
> -	    output_asm_insn (\"mov %1, %L0\; mov (4, %L0), %H0\; mov (%L0), %L0\",
> -			     xoperands);
> -	    return \"\";
> -	  }
> -	else
> -	  {
> -	    if ((CONST_INT_P (operands[1])
> -		 || CONST_DOUBLE_P (operands[1]))
> -		&& val[0] == 0)
> -	      {
> -		if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
> -		  output_asm_insn (\"mov 0, %L0\", operands);
> -		else
> -		  output_asm_insn (\"mov %L1, %L0\", operands);
> -	      }
> -	    else if ((CONST_INT_P (operands[1])
> -		      || CONST_DOUBLE_P (operands[1]))
> -		     && (REGNO_REG_CLASS (true_regnum (operands[0]))
> -			 == EXTENDED_REGS)
> -		     && (((val[0] & 0x80) && ! (val[0] & 0xffffff00))
> -			 || ((val[0] & 0x800000) && ! (val[0] & 0xff000000))))
> -	      output_asm_insn (\"movu %L1, %L0\", operands);
> -	    else
> -	      output_asm_insn (\"mov %L1, %L0\", operands);
> -
> -	    if ((CONST_INT_P (operands[1])
> -		 || CONST_DOUBLE_P (operands[1]))
> -		&& val[1] == 0)
> -	      {
> -		if (REGNO_REG_CLASS (REGNO (operands[0])) == DATA_REGS)
> -		  output_asm_insn (\"mov 0, %H0\", operands);
> -		else
> -		  output_asm_insn (\"mov %H1, %H0\", operands);
> -	      }
> -	    else if ((CONST_INT_P (operands[1])
> -		      || CONST_DOUBLE_P (operands[1]))
> -		     && val[0] == val[1])
> -	      output_asm_insn (\"mov %L0, %H0\", operands);
> -	    else if ((CONST_INT_P (operands[1])
> -		      || CONST_DOUBLE_P (operands[1]))
> -		     && (REGNO_REG_CLASS (true_regnum (operands[0]))
> -			 == EXTENDED_REGS)
> -		     && (((val[1] & 0x80) && ! (val[1] & 0xffffff00))
> -			 || ((val[1] & 0x800000) && ! (val[1] & 0xff000000))))
> -	      output_asm_insn (\"movu %H1, %H0\", operands);
> -	    else
> -	      output_asm_insn (\"mov %H1, %H0\", operands);
> -	    return \"\";
> -	  }
> -    default:
> -      gcc_unreachable ();
> -    }
> -  }"
> -  ;; Timings of "37" is approximation of the worst case sceanario.
> -  [(set_attr_alternative "timings"
> -			 [(const_int 11)
> -			  (const_int 22)
> -			  (const_int 37)
> -			  (const_int 37)
> -			  (const_int 37)
> -			  (const_int 37)
> -			  (const_int 37)
> -			  (const_int 37)
> -			 ])
> -  ]
> -)
>  \f
>  ;; ----------------------------------------------------------------------
>  ;; ADD INSTRUCTIONS
> @@ -1363,42 +762,23 @@
>    	      		 	       (const_int 24) (const_int 23)))]
>  )
>  
> -(define_expand "udivmodsi4"
> -  [(parallel [(set (match_operand:SI          0 "register_operand")
> -		   (udiv:SI (match_operand:SI 1 "general_operand")
> -			    (match_operand:SI 2 "general_operand")))
> -	      (set (match_operand:SI          3 "register_operand")
> -		   (umod:SI (match_dup 1) (match_dup 2)))
> -	      (clobber (reg:CC CC_REG))
> -	     ])
> -  ]
> -  ""
> -  "{
> -    if (!register_operand (operands[1], SImode))
> -      operands[1] = copy_to_mode_reg (SImode, operands[1]);
> -    if (!register_operand (operands[2], SImode))
> -      operands[2] = copy_to_mode_reg (SImode, operands[2]);
> -   }"
> -)
> -
> -(define_insn "*udivmodsi4"
> -  [(set (match_operand:SI          0 "register_operand" "=dx")
> +;; ??? This pattern causes too-high register pressure for MN103.
> +;; ??? To be fixed by exposing the MDR register properly.
> +(define_insn "udivmodsi4"
> +  [(set (match_operand:SI          0 "register_operand" "=D")
>  	(udiv:SI (match_operand:SI 1 "register_operand" "0")
> -		 (match_operand:SI 2 "register_operand" "dx")))
> +		 (match_operand:SI 2 "register_operand" "D")))
>     (set (match_operand:SI          3 "register_operand" "=&d")
>  	(umod:SI (match_dup 1) (match_dup 2)))
> -   (clobber (reg:CC CC_REG))
> -  ]
> -  ""
> -  "*
> +   (clobber (reg:CC CC_REG))]
> +  "TARGET_AM33"
>  {
> -  output_asm_insn (\"sub %3,%3\;mov %3,mdr\", operands);
> -
> +  output_asm_insn ("clr %3\;ext %3", operands);
>    if (find_reg_note (insn, REG_UNUSED, operands[3]))
> -    return \"divu %2,%0\";
> +    return "divu %2,%0";
>    else
> -    return \"divu %2,%0\;mov mdr,%3\";
> -}"
> +    return "divu %2,%0\;mov mdr,%3";
> +}
>    ;; Timings:  AM33   AM34
>    ;;  SUB       1/1    1/1
>    ;;  MOV       1/1    1/1
> @@ -1410,6 +790,28 @@
>    	      		 	       (const_int 4546) (const_int 4142)))]
>  )
>  
> +;; ??? In the meantime MN103 can use these two patterns,
> +;; which reduce the register pressure by one.
> +(define_insn "udivsi3"
> +  [(set (match_operand:SI          0 "register_operand" "=&d")
> +	(udiv:SI (match_operand:SI 1 "register_operand" "d")
> +		 (match_operand:SI 2 "register_operand" "d")))
> +   (clobber (reg:CC CC_REG))]
> +  "!TARGET_AM33"
> +  "clr %0\;ext %0\;mov %1,%0\;divu %2,%0"
> +  [(set_attr "timings" "4142")]
> +)
> +
> +(define_insn "umodsi3"
> +  [(set (match_operand:SI          0 "register_operand" "=&d")
> +	(umod:SI (match_operand:SI 1 "register_operand" "d")
> +		 (match_operand:SI 2 "register_operand" "d")))
> +   (clobber (reg:CC CC_REG))]
> +  "!TARGET_AM33"
> +  "clr %0\;ext %0\;mov %1,%0\;divu %2,%0\;mov mdr,%0"
> +  [(set_attr "timings" "4142")]
> +)
> +
>  (define_insn "divmodsi4"
>    [(set (match_operand:SI          0 "register_operand" "=dx")
>  	(div:SI (match_operand:SI  1 "register_operand"  "0")

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNNce0AAoJEBRtltQi2kC7xYMH/2Ak9sB1KWEPkb7r2XSC5Gvu
vZ/TjCQ+glV53LBJNtDzBo4D2QGrY576ex5aYRjmwsmwKItnjAezIIJk2VHRxXVv
7lsTpG8qT2iNbj8NQW8g30Vh6SGok7zd3vNZ4t7YztHV89LDSOmaRwtGktiTDhPu
F9k+CBqqFeZukAGDTYGHLFw1XHqsJJ57X9WzCOiS14zRAFiIeWCnqbZgDk/VRRuL
XJn0EPCCGDiBfh2L/2BmVGYfZ3Cmfzg5WvDij63UPXaVTocRMORsR231UA3eoo+P
fJ2s293SncpGCAdieJZZs1Kb/qu0Gj35VS9Xo+mKvOIf6DS1ybCqFFHkj/4AIjc=
=S+LB
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 13/28] mn10300: cleanup secondary reloads
  2011-01-10 20:32 ` [PATCH 13/28] mn10300: cleanup secondary reloads Richard Henderson
@ 2011-01-18 17:14   ` Jeff Law
  2011-01-18 18:35     ` Richard Henderson
  0 siblings, 1 reply; 90+ messages in thread
From: Jeff Law @ 2011-01-18 17:14 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, Richard Henderson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/10/11 13:31, Richard Henderson wrote:
> From: Richard Henderson <rth@twiddle.net>
> 
> Handles output reloads for QI/HImode properly; previously we were
> only handing input reloads properly.
> 
> Handles reloads involving the stack pointer better; note that the
> AM33 allows copying SP to DATA_REGS as well as ADDRESS and EXTENDED.
I'm not sure I understand the change to the preferred_reload_class.
ADDRESS_OR_EXTENDED_REGS seems to be more appropriate than
BASE_REG_CLASS.  Maybe the tighter preferred class is giving you better
code?

It looks OK though.

jeff

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNNckSAAoJEBRtltQi2kC7tjIIALMkhJE+jSlm8wlYlEdL7Q93
TkGpWbaXYHEXBh9dNblUMlaGY/Gz2f+eVu7mnzgrvmIBHbB8mBhznT2uMB92tLZw
DtsoCGsUfTJJx+o0Yz3PQIoMwEz6gGLsKAQgZneAPbS4QQrJq4wSvkP5No6bV1/k
qAylRwkst0Yy2/MjZC2NKW3KFZcmHD28vOJuQZM7+DZuU7EHZ3zJ94ndGYLlYTqy
Cb0fCuufWvxCHuCCJAjMUQBGXPiExyJ5MVzEP+cq+pQ5tCVJGv137kgNB8kwRvfG
AY71UE93iUI8n9X108fV8mU3YHLnxmyDvBR0Mt47U21cifJIb1XvHvxEOa5S4QU=
=ohpC
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 14/28] mn10300: Cleanup legitimate addresses
  2011-01-10 20:34 ` [PATCH 14/28] mn10300: Cleanup legitimate addresses Richard Henderson
@ 2011-01-18 17:14   ` Jeff Law
  0 siblings, 0 replies; 90+ messages in thread
From: Jeff Law @ 2011-01-18 17:14 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, Richard Henderson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/10/11 13:31, Richard Henderson wrote:
> From: Richard Henderson <rth@twiddle.net>
> 
> Allow REG+REG and POST_MODIFY addressing for AM33.  Fix AM33 base and
> index register classes.  Remove a bunch of register class combinations
> that aren't really useful after this cleanup.
OK.

Clearly this depends on the preferred_reload_class change, so I'll trust
you'll do the right thing WRT my question on the preferred_reload_class
changes.

Extra credit if you peek at REGNO_POINTER to allow reg+reg addressing in
the future :-)

jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNNcn5AAoJEBRtltQi2kC79qIH/17drTERdVn41INGhoYwLkrO
7Bsy+gNidShGN5MMYOsnlmn4g4uA+Y8G79NlBfQUo23j2ljMRvZ9SDknqXg00yho
dUk5hKovG94MEoLdocA35RQ64DjDIGqoRJJJakZkOnxV+deLW67Mzo8vAkoU5WhO
NpQYt9H3OunZiKwO5zVm89qma3f5bWyv8iaKWE+mY1rMEXOf6P852eFRO+cELi95
0RWtNLZJkgbka2PpPRh1vXmqJGqehlaJm+7dlP9vZbN3xXUApr8RljXjNdBT2V8n
Cz1pbhXFWZJX5QUIfXEEL/P7QHONIjX4vIrEZYl+klLM0npLlz+uiJezjXUUp7M=
=+XAW
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 16/28] mn10300: Expose the MDR register to register allocation.
  2011-01-10 20:39 ` [PATCH 16/28] mn10300: Expose the MDR register to register allocation Richard Henderson
@ 2011-01-18 17:56   ` Jeff Law
  0 siblings, 0 replies; 90+ messages in thread
From: Jeff Law @ 2011-01-18 17:56 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, Richard Henderson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/10/11 13:31, Richard Henderson wrote:
> From: Richard Henderson <rth@twiddle.net>
> 
> Note that nothing uses the "z" constraint yet except the one
> move pattern; this merely defines the register class properly.
OK.
Jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNNcoiAAoJEBRtltQi2kC7X2sH+gO1N8yq5bR6hXL2dJP58P+9
JCzhDvfBi8643YD7mxkLqOLTnOPundGQrsOrtYqZho+jk/+YjRYrZTE1khwwFp5f
+IJatC+p9yCIukhp6SO5w6G8LspKZspRuipamuRBb5wrmsJJf9JV7bU67/PrNCAm
aFRlxzwmWJLKqyBj7bCyiJdDiMDq1LlzWUrpaZC3/GylJ0zE4TiKkJF3y8U/MY0W
PcpF2R3oRCUOPgzE+XWkIoDb/O+A4cDG/my6GAUQhRKBv99l9lCKOP1uvsFFKE/c
RAZtLxrIQsbO3pqEpocFIcbHdfXPHfjwQamKjQC0w0jB5v+8MOlqUTPN++cY2FU=
=p+Go
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 17/28] mn10300: Explicitly represent MDR in multiply and divide.
  2011-01-10 20:34 ` [PATCH 17/28] mn10300: Explicitly represent MDR in multiply and divide Richard Henderson
@ 2011-01-18 18:13   ` Jeff Law
  0 siblings, 0 replies; 90+ messages in thread
From: Jeff Law @ 2011-01-18 18:13 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, Richard Henderson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/10/11 13:31, Richard Henderson wrote:
> From: Richard Henderson <rth@twiddle.net>
> 
> Note that the mulsidi3_internal pattern is structured so
> as to let the lower-subregs pass fully split the result.
OK
jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNNcpSAAoJEBRtltQi2kC71b8H/3rj+M77p8W7QBZ735ETWIMV
VlzPlU6v4XMeA/y55wsYp5majf2X/xXlQVPV5tBKTpoyspHggDX5zQYa7w3YbM3e
DpiZCoRlt+H/MlqSaqxx7f8r0+5+pbapdorW4UTtoexjqVMlM7Lnx3lOye7AVad3
bWuQ29jco1LrRGRJW8qpSdhDGitWvVkZNxBgg7tNdUj8zeRsGGPjSGTVqImZOYBw
KdIc2Tg6qV+SGuy2pRdnQ7Bhe9oj6Y4l2T0AadGvUHm4VsAtdOlSJNWlGjiGjNLw
4zwlQL0Zptha+4bKUxFEHSu9q3nqsPaGF47JydVX03oolFmOnJK79uOk971UD5s=
=gHKO
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 22/28] mn10300: Emit retf instruction
  2011-01-10 20:34 ` [PATCH 22/28] mn10300: Emit retf instruction Richard Henderson
@ 2011-01-18 18:18   ` Jeff Law
  0 siblings, 0 replies; 90+ messages in thread
From: Jeff Law @ 2011-01-18 18:18 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, Richard Henderson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/10/11 13:31, Richard Henderson wrote:
> From: Richard Henderson <rth@twiddle.net>
> 
> Now that we properly track the life of MDR, we can emit
> the RETF instruction if MDR has not been modified.  This
> insn is 3-4 cycles faster since the return address is
> already loaded.
OK.
Jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNNcpsAAoJEBRtltQi2kC7+o4IAJnPdT5ZGk5kqD6JDx8fBuTJ
DgKBewXPLF6XyEXaG4iEuBPEbmyElaxOQF6ikIsZOMhfbjG+OmFQDSSOpBLBbQ6j
RTyFNwwD7paXgLc6X13xuIiTfU06DtEQqUPuM4ntLtqFfkk7A4vTyfTGJzX2t6w6
7yci/3MLc6OASefo89bBgL2g9fqGA9f16TVVLw3+PQlzxPQFR1yHgD9d5HTezo1V
W19B5wCSkE/lDLWbXCdVKYhNLBcwdFiZRgr5vc4O2uN3Gty54QQpkYS+g5bLov6E
j7+q3aaHkw+gRBNG6eoEFD10hnmplAo26LxoWsFdwETCfDUIrpWBKYy7fXHCjDg=
=j0iq
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 12/28] mn10300: Re-write move patterns.
  2011-01-18 17:12   ` Jeff Law
@ 2011-01-18 18:30     ` Richard Henderson
  2011-01-19 16:12       ` Jeff Law
  2011-01-18 19:18     ` Richard Henderson
  1 sibling, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-18 18:30 UTC (permalink / raw)
  To: Jeff Law; +Cc: gcc-patches, nickc, Richard Henderson

On 01/18/2011 09:02 AM, Jeff Law wrote:
> IIRC returning an empty string for that case didn't work because the
> empty string had some kind of special meaning in final.  (This was 13 or
> 14 years ago, so please forgive the IIRC's :-)
> 
> The net result is I think you have to return something for those
> alternatives rather than an empty string.

Not since I've been working on GCC.  We do this a lot -- emit stuff by
hand then return "" to tell final that nothing else need be output.  If
you insist, we can continue to return nop here, but I don't think it's
necessary.

> It also seems to me that for movqi/movhi we want to severely disparage
> the address regs on the mn103.  IIRC for the base mn103 we would trigger
> reload failures if we didn't expose a0-a3 to the movqi/movhi patterns.
> However, while the a0-a3 regs can hold such values, they can't be used
> in arithmetic/logicals/etc in QI/HI mode.  So to avoid pessimizing code
> we exposed a0-a3 in the QI/HI mode moves, but ignored them for register
> class preferencing and severely disparaged them for reloading.

I have ignored them for register class preferencing:

> +(define_insn "*movqi_internal"
> +  [(set (match_operand:QI 0 "nonimmediate_operand" "=*r,D*r,D*r,D,m")
> +	   (match_operand:QI 1 "general_operand"      "  0,D*r,  i,m,D"))]

Note that for mn103, D*r resolves to a DATA_REGS preference, with
GENERAL_REGS used for the legal register set.

As for pessimising, I'm not sure what else really needs to be done, given
that the only other operation for which Q/HImode is valid is extension.

> It also looks like you lost the movu am33 variant for movqi/movhi.  I
> don't recall anything about that alternative, but I can hazard a guess
> that movu is smaller than the more generic mov instruction for certain
> constants.

It is still present in movhi:

>      case 1:
> +      if (TARGET_AM33
> +	  && CONST_INT_P (operands[1])
> +	  && IN_RANGE (INTVAL (operands[1]), 0x80, 0xff))
> +	return "movu %1,%0";

What I dropped were the useless extra tests for movu.  There's no point
in loading 0x80 via movu when -128 via mov is 1 byte smaller for QImode.

> It looks like you lost movu for the base mn103 in the movsi pattern and
> for all the parts in the movsf pattern (it may not matter there).

Err, base mn103 doesn't have movu at all.

As for movsf, movu would only be usable for a small set of subnormal
operands.  Combine that with wanting to load that subnormal into an
integer register, as opposed to a floating-point register, and I think
that is rare enough not to be useful.

It does look as if I'm missing an EXTENDED_REGISTER check there in some
of the tests; the sizes of mov imm vary a bit between data, addr, and
extended register sets...


r~

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 13/28] mn10300: cleanup secondary reloads
  2011-01-18 17:14   ` Jeff Law
@ 2011-01-18 18:35     ` Richard Henderson
  2011-01-18 18:49       ` Jeff Law
  0 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-18 18:35 UTC (permalink / raw)
  To: Jeff Law; +Cc: gcc-patches, nickc, Richard Henderson

On 01/18/2011 09:08 AM, Jeff Law wrote:
> I'm not sure I understand the change to the preferred_reload_class.
> ADDRESS_OR_EXTENDED_REGS seems to be more appropriate than
> BASE_REG_CLASS.  Maybe the tighter preferred class is giving you better
> code?

I don't understand ADDRESS_OR_EXTENDED_REGS.  Once you leave the
slightly smaller encoding of ADDRESS_REGS, the encoding accepts
DATA_REGS just as easily as EXTENDED_REGS.

So I see no reason to exclude DATA_REGS from the mix.

I used BASE_REG_CLASS as that is already defined such that we get
GENERAL_REGS in AM33 mode and ADDRESS_REGS in MN103 mode.


r~

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 13/28] mn10300: cleanup secondary reloads
  2011-01-18 18:35     ` Richard Henderson
@ 2011-01-18 18:49       ` Jeff Law
  2011-01-18 19:12         ` Richard Henderson
  0 siblings, 1 reply; 90+ messages in thread
From: Jeff Law @ 2011-01-18 18:49 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, Richard Henderson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/18/11 11:18, Richard Henderson wrote:
> On 01/18/2011 09:08 AM, Jeff Law wrote:
>> I'm not sure I understand the change to the preferred_reload_class.
>> ADDRESS_OR_EXTENDED_REGS seems to be more appropriate than
>> BASE_REG_CLASS.  Maybe the tighter preferred class is giving you better
>> code?
> 
> I don't understand ADDRESS_OR_EXTENDED_REGS.  Once you leave the
> slightly smaller encoding of ADDRESS_REGS, the encoding accepts
> DATA_REGS just as easily as EXTENDED_REGS.
I agree -- there's definitely something odd here.  It may have been a
mis-guided attempt at providing the proper set of union classes that the
old allocator/reload desired.  My memory is just too foggy on a lot of
this stuff.  I'm certainly willing to go with your implementation as I
can't put my finger on the purpose behind ADDRESS_OR_EXTENDED_REGS.


>
> So I see no reason to exclude DATA_REGS from the mix.
> 
> I used BASE_REG_CLASS as that is already defined such that we get
> GENERAL_REGS in AM33 mode and ADDRESS_REGS in MN103 mode.
Doesn't BASE_REG_CLASS include SP_REGS, which are highly restricted in
how they can be used?

jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNNdxTAAoJEBRtltQi2kC7VSAH+wXW56apbxyDjCrCoC8HKkQj
9IpueDNd85BiieVhdlT1vhDKlOoL46vusR1ef1BgPRou2Qo1GDfrvWxkUP/dng7u
N1kH/F3tFh1fL3d0ieMrih871Yoh9XCsJLXRQlm2l4ctXBGPcEpyAgWWSUiGi/5s
waBC545NF+td+Ad0hKgG64LLRq/nqG+XRncmji3uWLdjIiT73OyVYSbfwOyThCr8
jfZP3sLk75xLtytwQJ9jZLOyo70P2p7Y8A8uvWAgftcpD/RbD5OqPQIM4t4PWGQI
jCpi2s0LLqmGk6xfUIR8O9YHq3BY+IlDaSbuta6gRVtxiW6FOgKtV43h4z2yPwE=
=cK4O
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 13/28] mn10300: cleanup secondary reloads
  2011-01-18 18:49       ` Jeff Law
@ 2011-01-18 19:12         ` Richard Henderson
  2011-01-19 15:41           ` Jeff Law
  0 siblings, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-18 19:12 UTC (permalink / raw)
  To: Jeff Law; +Cc: Richard Henderson, gcc-patches, nickc

On 01/18/2011 10:30 AM, Jeff Law wrote:
>> I used BASE_REG_CLASS as that is already defined such that we get
>> GENERAL_REGS in AM33 mode and ADDRESS_REGS in MN103 mode.
> Doesn't BASE_REG_CLASS include SP_REGS, which are highly restricted in
> how they can be used?

Hmm, true.

In this specific place we're looking for a place to move SP_REG.
I suppose a "move" of SP to SP would be ok, so long as it turns
out to be valid for everything else?  Or should I go ahead and
be safe and choose the class that excludes SP?


r~

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 12/28] mn10300: Re-write move patterns.
  2011-01-18 17:12   ` Jeff Law
  2011-01-18 18:30     ` Richard Henderson
@ 2011-01-18 19:18     ` Richard Henderson
  2011-01-19 15:48       ` Jeff Law
  1 sibling, 1 reply; 90+ messages in thread
From: Richard Henderson @ 2011-01-18 19:18 UTC (permalink / raw)
  To: Jeff Law; +Cc: gcc-patches, nickc, Richard Henderson

On 01/18/2011 09:02 AM, Jeff Law wrote:
> It also looks like you lost the movu am33 variant for movqi/movhi.  I
> don't recall anything about that alternative, but I can hazard a guess
> that movu is smaller than the more generic mov instruction for certain
> constants.

I propose the following incremental patch, with commentary.


r~


diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md
index 680d55e..aee5eb7 100644
--- a/gcc/config/mn10300/mn10300.md
+++ b/gcc/config/mn10300/mn10300.md
@@ -253,9 +253,13 @@
     case 0:
       return "";
     case 1:
+      /* Note that "MOV imm8,An" is already zero-extending, and is 2 bytes.
+	 We have "MOV imm16,Dn" at 3 bytes.  The only win for the 4 byte
+	 movu is for an 8-bit unsigned move into Rn.  */
       if (TARGET_AM33
 	  && CONST_INT_P (operands[1])
-	  && IN_RANGE (INTVAL (operands[1]), 0x80, 0xff))
+	  && IN_RANGE (INTVAL (operands[1]), 0x80, 0xff)
+	  && REGNO_EXTENDED_P (REGNO (operands[0])))
 	return "movu %1,%0";
       /* FALLTHRU */
     case 2:
@@ -386,7 +390,12 @@
     case 0:
       return "";
     case 1: /* imm-reg*/
-      if (TARGET_AM33 && CONST_INT_P (operands[1]))
+      /* See movhi for a discussion of sizes for 8-bit movu.  Note that the
+	 24-bit movu is 6 bytes, which is the same size as the full 32-bit
+	 mov form for An and Dn.  So again movu is only a win for Rn.  */
+      if (TARGET_AM33
+	  && CONST_INT_P (operands[1])
+	  && REGNO_EXTENDED_P (REGNO (operands[0])))
 	{
 	  HOST_WIDE_INT val = INTVAL (operands[1]);
 	  if (IN_RANGE (val, 0x80, 0xff)

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 13/28] mn10300: cleanup secondary reloads
  2011-01-18 19:12         ` Richard Henderson
@ 2011-01-19 15:41           ` Jeff Law
  2011-01-19 16:55             ` Richard Henderson
  0 siblings, 1 reply; 90+ messages in thread
From: Jeff Law @ 2011-01-19 15:41 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Richard Henderson, gcc-patches, nickc

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/18/11 11:35, Richard Henderson wrote:
> On 01/18/2011 10:30 AM, Jeff Law wrote:
>>> I used BASE_REG_CLASS as that is already defined such that we get
>>> GENERAL_REGS in AM33 mode and ADDRESS_REGS in MN103 mode.
>> Doesn't BASE_REG_CLASS include SP_REGS, which are highly restricted in
>> how they can be used?
> 
> Hmm, true.
> 
> In this specific place we're looking for a place to move SP_REG.
> I suppose a "move" of SP to SP would be ok, so long as it turns
> out to be valid for everything else?  Or should I go ahead and
> be safe and choose the class that excludes SP?
I think the safe thing to do is use a class which excludes SP; it may
not matter in the end, but we already know that works.  We could mark it
as a future TODO to just use BASE_REG_CLASS.

Jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNNwPQAAoJEBRtltQi2kC7CuIH/R9U3WzHpiZT7FX1qvtV0HJN
a5DlbS1T5lGo6P/iZHPrr25Qf40p3aUVOkL0Mf7K96jrYBPpzWJr/ELEHja2Hpn8
aQxq7XzSCwY39ZKcin1U5/0gLzDCXnm+rkNQqx2M5+IZOMUn6RHg4tER52+61C21
i9xKnIxkXTwmHMuAX8cAveILUubxpq4Fx8Qe+aBb0Kj57Uvmphypj2o9HcoEiVDJ
AkyrtJZyZ74eW5jBTSJVkT/WR+2q5F26sZfoAKqW2IP4hLCyRNGwO7Zf+8dcetL8
Fw6BNe7GujMh1J98dSZHjFtFKMk8fx18gxGiPygdnQkpWIJSVn3s3f2QUDBxnxc=
=UUub
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 12/28] mn10300: Re-write move patterns.
  2011-01-18 19:18     ` Richard Henderson
@ 2011-01-19 15:48       ` Jeff Law
  0 siblings, 0 replies; 90+ messages in thread
From: Jeff Law @ 2011-01-19 15:48 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, Richard Henderson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/18/11 11:54, Richard Henderson wrote:
> On 01/18/2011 09:02 AM, Jeff Law wrote:
>> It also looks like you lost the movu am33 variant for movqi/movhi.  I
>> don't recall anything about that alternative, but I can hazard a guess
>> that movu is smaller than the more generic mov instruction for certain
>> constants.
> 
> I propose the following incremental patch, with commentary.
OK.
jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNNwP6AAoJEBRtltQi2kC7YeAIAJlTlM9nco/gaaorKhVt3mD6
HVv0txu1KwKU4qLcej0QM6VFIwZCcyRpu+FQh59P3e2UT9nkFpJZht7f1XOJOJNY
iP1SiNxdXUnqmlg/jkOjertHiaMRQFhC2AQeT/4fYorrP9RoBoRM1esK+Q9C/mYV
cVV1fRXfwyLrkuP4ghBqbphgjQ9Aq3biIKUj9j8UCQwHhjctL3vREJhk5W+/5mcz
iSKN9GKzKq2P74OOBCT/VM5AMn8+S72+OmKRwB5dHhWdhrdyPaiw/2IOckPRXm4I
pnXSlHEUwYWhRV+gvIRs5EQAp3W3VBd7qeSmNaM9dVMOfsMX1mrX1cZIImRaIy8=
=Ve1G
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 12/28] mn10300: Re-write move patterns.
  2011-01-18 18:30     ` Richard Henderson
@ 2011-01-19 16:12       ` Jeff Law
  2011-01-19 19:21         ` Hans-Peter Nilsson
  0 siblings, 1 reply; 90+ messages in thread
From: Jeff Law @ 2011-01-19 16:12 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, Richard Henderson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/18/11 11:13, Richard Henderson wrote:
> On 01/18/2011 09:02 AM, Jeff Law wrote:
>> IIRC returning an empty string for that case didn't work because the
>> empty string had some kind of special meaning in final.  (This was 13 or
>> 14 years ago, so please forgive the IIRC's :-)
>>
>> The net result is I think you have to return something for those
>> alternatives rather than an empty string.
> 
> Not since I've been working on GCC.  We do this a lot -- emit stuff by
> hand then return "" to tell final that nothing else need be output.  If
> you insist, we can continue to return nop here, but I don't think it's
> necessary.
I'll go with your call on this one.  There was certainly some reason I
didn't do this before, but I simply can't remember what it was...    I
thought I'd documented this nonsense thoroughly in a long block comment,
but I can't seem to find it anywhere.


> 
> As for pessimising, I'm not sure what else really needs to be done, given
> that the only other operation for which Q/HImode is valid is extension.
I think what may have tended to happen is with the '!' for A regs was
that we could use an address register for a source/destination in a
movqi/movhi since it didn't need reloads.  In some cases that's
sufficient to keep reload happy.

I'm willing to hope that Bernd's work from 1998 & IRA would minimize the
chances of running into those problems again.  On top of that, I suspect
nobody is still using the base mn103 anymore.

There's also the slim possibility that this was a mn102 problem and I
carried the changes into the mn103 port.



> 
>> It also looks like you lost the movu am33 variant for movqi/movhi.  I
>> don't recall anything about that alternative, but I can hazard a guess
>> that movu is smaller than the more generic mov instruction for certain
>> constants.
> 
> It is still present in movhi:
> 
>>      case 1:
>> +      if (TARGET_AM33
>> +	  && CONST_INT_P (operands[1])
>> +	  && IN_RANGE (INTVAL (operands[1]), 0x80, 0xff))
>> +	return "movu %1,%0";
> 
> What I dropped were the useless extra tests for movu.  There's no point
> in loading 0x80 via movu when -128 via mov is 1 byte smaller for QImode.
Ok.  As I mentioned, I don't have any recollection of movu, so if your
sequence is smaller, that's all good :-)

Jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNNwo5AAoJEBRtltQi2kC78i8H/RX3QLkdkriMLgoqxrXOcSL5
K9uGc/icLZfhGiDyNXuQ5gQV8PaczETw5WKu9IJImh7Kh25Lm8Ekn2hcmxn04uoJ
nB5D+sl7ro+80Dev/tsCU/qawvz7YY9WCbEueOlMo9Yo5MHiCJ0hAHv+cBO8w2xM
dEyMy6fBZ9BE7NuUwRnu24BbR90VnNrNUbSfR1s5LOWuj1+5amU0TkPQdJ18wOjp
C+djO8OPNjgrc3qIklBUhRKdaYnMuS+KkRd2SszqRBft5o7Ue7XPfzUhdfnjzmUU
Blyo1qzDviuGXNNgVpJVU5rFCf/LtmJCj8gnb34AW008UEQbwIuJrK/clO9QPGk=
=Wtn5
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 19/28] mn10300: tidy pic address loading
  2011-01-10 20:44 ` [PATCH 19/28] mn10300: tidy pic address loading Richard Henderson
@ 2011-01-19 16:44   ` Jeff Law
  0 siblings, 0 replies; 90+ messages in thread
From: Jeff Law @ 2011-01-19 16:44 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, Richard Henderson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/10/11 13:31, Richard Henderson wrote:
> From: Richard Henderson <rth@twiddle.net>
> 
> There's little reason to greatly complicate things by splitting
> the pic_load patterns and using complex rtl to make it work out.
> Instead, use the %= marker to generate unique numbers and emit
> the entire load_pic sequence at once.
> 
> At the same time, collect all references to outgoing_args_size
> into mn10300_frame_size, and all computations of register save
> area size into mn10300_initial_offset.
OK.
Jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNNxJRAAoJEBRtltQi2kC7f7kIAJk/omUcSXn7RPp0cewz5Pzu
IiLn+WHkfuGz//WWz9TCk/Wl6xW6mIrf9mWtfwl75SpA6Hqnixm0504rEv2LNPvW
BjtIVk+Db/59uRfS2+0BcZsCeFAbwlRKCM9+GgSO58pio578uc3vk19ASRfPwte0
wDtyami7YZ8n73kdjjh2fBUQBrYrLnI6pBxqTslP3YqHfUTzGMTUrX+miRHLcOkM
S8BDg/XkpDEKwlkoLKvnlAPVZZUOEHi21mDT8W42ByUYj3Snooc3Lrlk2W7JmWPp
oFIYJLe4cK+JsV1Vpnc8XRChKOfE1b0JlZBJCalDa/enxLqGdbIQaNQVMaDfOL4=
=lVpl
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 13/28] mn10300: cleanup secondary reloads
  2011-01-19 15:41           ` Jeff Law
@ 2011-01-19 16:55             ` Richard Henderson
  0 siblings, 0 replies; 90+ messages in thread
From: Richard Henderson @ 2011-01-19 16:55 UTC (permalink / raw)
  To: Jeff Law; +Cc: Richard Henderson, gcc-patches, nickc

On 01/19/2011 07:31 AM, Jeff Law wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> 
> On 01/18/11 11:35, Richard Henderson wrote:
>> On 01/18/2011 10:30 AM, Jeff Law wrote:
>>>> I used BASE_REG_CLASS as that is already defined such that we get
>>>> GENERAL_REGS in AM33 mode and ADDRESS_REGS in MN103 mode.
>>> Doesn't BASE_REG_CLASS include SP_REGS, which are highly restricted in
>>> how they can be used?
>>
>> Hmm, true.
>>
>> In this specific place we're looking for a place to move SP_REG.
>> I suppose a "move" of SP to SP would be ok, so long as it turns
>> out to be valid for everything else?  Or should I go ahead and
>> be safe and choose the class that excludes SP?
> I think the safe thing to do is use a class which excludes SP; it may
> not matter in the end, but we already know that works.  We could mark it
> as a future TODO to just use BASE_REG_CLASS.

Right.  I've changed these lines to 

  return (TARGET_AM33 ? GENERAL_REGS : ADDRESS_REGS)

in my tree.


r~

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 18/28] mn10300: Cleanup all arithmetic.
  2011-01-10 20:34 ` [PATCH 18/28] mn10300: Cleanup all arithmetic Richard Henderson
@ 2011-01-19 16:58   ` Jeff Law
  0 siblings, 0 replies; 90+ messages in thread
From: Jeff Law @ 2011-01-19 16:58 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, Richard Henderson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/10/11 13:31, Richard Henderson wrote:
> From: Richard Henderson <rth@twiddle.net>
> 
> For addition and logicals, define an operation-plus-flags update pattern
> in preparation for compare elimination.  In addition, clean up the way
> we compare and validate CC_MODEs.  Define NEG in terms of NOT; this is
> smaller and allows a non-clobbering destination alternative.
s/chosing/choosing/g

Otherwise OK.

jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNNxUpAAoJEBRtltQi2kC7a5oH/2a/rff/tHv7nUeyqAjylJQL
jg+A6S5r7TmnQSpP0SvdaE8KGYUPS1cy55nAVSXnfAckdXvmngbIEccOA1hMz90l
NLP5UKy//9P8UMK3X+21OnWjZMIjlsQv2BpmwKfWWz2A31xwc68KtgdTjLYPql/C
e70EA+TwCQBtaGhnIGXoPm3nwBCTGTzYMHO+hkmZ5Q2M4G8dMQtxl398dN8kBy1n
lNHIPYux2i4Vg0Ipp+aiedI95QQR+nDofq8min4+IMpplgMnIZW/TT5Fqtf2GEu8
KqEyyJlAUhOybk5u7ba06TeBAjcVt7gkOx3g95iD8HeG6fs5VM5TGFvdOq3zDDw=
=shvV
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 24/28] mn10300: Implement adddi3, subdi3.
  2011-01-10 20:34 ` [PATCH 24/28] mn10300: Implement adddi3, subdi3 Richard Henderson
@ 2011-01-19 18:45   ` Jeff Law
  0 siblings, 0 replies; 90+ messages in thread
From: Jeff Law @ 2011-01-19 18:45 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, nickc, Richard Henderson

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 01/10/11 13:31, Richard Henderson wrote:
> From: Richard Henderson <rth@twiddle.net>
> 
> Via expander, pre- and post-reload patterns.  The pre-reload
> pattern is defined to allow lower_subregs totally split the
> DImode values.
OK.
jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJNNyqbAAoJEBRtltQi2kC7jzUH/2XQYA6baim2SkfMbHqyuVXE
wkzYgkqspnal3GQh+07gtomVyaYFcaH5G6VG2XiSkS/Nb779EJ2V/AqLkAyc76K9
36DraGc7uiEXzNt4DByuqch2LcNiwsAWbpjOuB5BhmhKAUGxy2Ztd0JTi7WhVBg7
p9rW15wmcum4ckAV+XaQZkiChoC7JKyuVB41U9fZU8SnSoOEMKga/7MeaD4kbPpZ
5nY+3/kfmv+ZeC6u87xwUW5AkTOcQ84kGXAfpJnbeoYWLuQ7303Hi8xRDl7CyYRg
pyARIfLWPAPntQ5TBaCdHPeLneTQSuosRUM1pjPFwKCdlBlLr7VFX6HlOclqTIw=
=u7h7
-----END PGP SIGNATURE-----

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [PATCH 12/28] mn10300: Re-write move patterns.
  2011-01-19 16:12       ` Jeff Law
@ 2011-01-19 19:21         ` Hans-Peter Nilsson
  0 siblings, 0 replies; 90+ messages in thread
From: Hans-Peter Nilsson @ 2011-01-19 19:21 UTC (permalink / raw)
  To: Jeff Law; +Cc: gcc-patches

On Wed, 19 Jan 2011, Jeff Law wrote:
> On 01/18/11 11:13, Richard Henderson wrote:
> > On 01/18/2011 09:02 AM, Jeff Law wrote:
> >> IIRC returning an empty string for that case didn't work because the
> >> empty string had some kind of special meaning in final.  (This was 13 or
> >> 14 years ago, so please forgive the IIRC's :-)
> >>
> >> The net result is I think you have to return something for those
> >> alternatives rather than an empty string.
> >
> > Not since I've been working on GCC.  We do this a lot -- emit stuff by
> > hand then return "" to tell final that nothing else need be output.  If
> > you insist, we can continue to return nop here, but I don't think it's
> > necessary.
> I'll go with your call on this one.  There was certainly some reason I
> didn't do this before, but I simply can't remember what it was...    I
> thought I'd documented this nonsense thoroughly in a long block comment,
> but I can't seem to find it anywhere.

Regarding the special-empty-string-meaning, maybe you were
thinking of branch patterns that should return NULL when, for
CC0 targets, e.g. cc_status indicates an invalid removal of a
compare insn, such that final_scan_insn has to put it back:

	/* If the C code returns 0, it means that it is a jump insn
	   which follows a deleted test insn, and that test insn
	   needs to be reinserted.  */

(Whoops, not inside #ifdef HAVE_cc0; dunno when else it can happen.)

brgds, H-P

^ permalink raw reply	[flat|nested] 90+ messages in thread

* [RFC, v3] New -fcompare-elim pass
  2011-01-18 10:06           ` Paolo Bonzini
@ 2011-01-21 17:54             ` Richard Henderson
  2011-01-21 18:07               ` Richard Guenther
                                 ` (2 more replies)
  0 siblings, 3 replies; 90+ messages in thread
From: Richard Henderson @ 2011-01-21 17:54 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: gcc-patches, nickc, law, rguenther

[-- Attachment #1: Type: text/plain, Size: 472 bytes --]

On 01/18/2011 12:45 AM, Paolo Bonzini wrote:
> Besides this, "seems to be perfect".

Heh.  Anyway, here's v3, with comments from v2 addressed.

I realize that neither mn10300 nor rx are even secondary targets.
However, this patch avoids a regression for these targets, and 
Nick did post a patch trying to address this (which I rejected)
at least as early as October.

Therefore I'm requesting that the Release Manager consider allowing
this pass at this late stage.


r~

[-- Attachment #2: commit-cmp-elim --]
[-- Type: text/plain, Size: 27094 bytes --]

commit 178103f7757ff207eea8eeed9a18f4e37d5ed4f1
Author: Richard Henderson <rth@twiddle.net>
Date:   Wed Jan 19 12:37:43 2011 -0800

    New -fcompare-elim pass.
    
    Version 3, with two rounds of comments from Paolo Bonzini.

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index db98cc8..34266f9 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1205,6 +1205,7 @@ OBJS-common = \
 	cfgrtl.o \
 	combine.o \
 	combine-stack-adj.o \
+	compare-elim.o \
 	convert.o \
 	coverage.o \
 	cse.o \
@@ -3353,6 +3354,9 @@ combine-stack-adj.o : combine-stack-adj.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
    $(TM_H) $(RTL_H) insn-config.h $(TIMEVAR_H) $(TREE_PASS_H) \
    $(RECOG_H) output.h $(REGS_H) hard-reg-set.h $(FLAGS_H) $(FUNCTION_H) \
    $(EXPR_H) $(BASIC_BLOCK_H) $(DIAGNOSTIC_CORE_H) $(TM_P_H) $(DF_H) $(EXCEPT_H) reload.h
+compare-elim.o : compare-elim.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+   $(TM_H) $(RTL_H) $(TM_P_H) insn-config.h $(RECOG_H) $(FLAGS_H) \
+   $(BASIC_BLOCK_H) $(TREE_PASS_H) $(TARGET_H) $(DF_H) domwalk.h
 ddg.o : ddg.c $(DDG_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TARGET_H) \
    $(DIAGNOSTIC_CORE_H) $(RTL_H) $(TM_P_H) $(REGS_H) $(FUNCTION_H) \
    $(FLAGS_H) insn-config.h $(INSN_ATTR_H) $(EXCEPT_H) $(RECOG_H) \
diff --git a/gcc/common.opt b/gcc/common.opt
index 7c93c83..12f41b1 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -853,6 +853,10 @@ fcompare-debug-second
 Common Driver RejectNegative Var(flag_compare_debug)
 Run only the second compilation of -fcompare-debug
 
+fcompare-elim
+Common Report Var(flag_compare_elim_after_reload) Optimization
+Perform comparison elimination after register allocation has finished
+
 fconserve-stack
 Common Var(flag_conserve_stack) Optimization
 Do not perform optimizations increasing noticeably stack usage
diff --git a/gcc/compare-elim.c b/gcc/compare-elim.c
new file mode 100644
index 0000000..0ddeb7f
--- /dev/null
+++ b/gcc/compare-elim.c
@@ -0,0 +1,641 @@
+/* Post-reload compare elimination.
+   Copyright (C) 2010, 2011
+   Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+/* There is a set of targets whose general-purpose move or addition
+   instructions clobber the flags.  These targets cannot split their
+   CBRANCH/CSTORE etc patterns before reload is complete, lest reload
+   itself insert these instructions in between the flags setter and user.
+   Because these targets cannot split the compare from the use, they
+   cannot make use of the comparison elimination offered by the combine pass.
+
+   This is a small pass intended to provide comparison elimination similar to
+   what is available via NOTICE_UPDATE_CC for cc0 targets.  This should help
+   encourage cc0 targets to convert to an explicit post-reload representation
+   of the flags.
+
+   This pass assumes:
+
+   (0) CBRANCH/CSTORE etc have been split in pass_split_after_reload.
+
+   (1) All comparison patterns are represented as
+
+	[(set (reg:CC) (compare:CC (reg) (immediate)))]
+
+   (2) All insn patterns that modify the flags are represented as
+
+	[(set (reg) (operation)
+	 (clobber (reg:CC))]
+
+   (3) If an insn of form (2) can usefully set the flags, there is
+       another pattern of the form
+
+	[(set (reg) (operation)
+	 (set (reg:CCM) (compare:CCM (operation) (immediate)))]
+
+       The mode CCM will be chosen as if by SELECT_CC_MODE.
+
+   Note that unlike NOTICE_UPDATE_CC, we do not handle memory operands.
+   This could be handled as a future enhancement.
+*/
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "rtl.h"
+#include "tm_p.h"
+#include "insn-config.h"
+#include "recog.h"
+#include "flags.h"
+#include "basic-block.h"
+#include "tree-pass.h"
+#include "target.h"
+#include "df.h"
+#include "domwalk.h"
+
+\f
+/* These structures describe a comparison and how it is used.  */
+
+/* The choice of maximum 3 uses comes from wanting to eliminate the two
+   duplicate compares from a three-way branch on the sign of a value.
+   This is also sufficient to eliminate the duplicate compare against the
+   high-part of a double-word comparison.  */
+#define MAX_CMP_USE 3
+
+struct comparison_use
+{
+  /* The instruction in which the result of the compare is used.  */
+  rtx insn;
+  /* The location of the flags register within the use.  */
+  rtx *loc;
+  /* The comparison code applied against the flags register.  */
+  enum rtx_code code;
+};
+
+struct comparison
+{
+  /* The comparison instruction.  */
+  rtx insn;
+
+  /* The insn prior to the comparison insn that clobbers the flags.  */
+  rtx prev_clobber;
+
+  /* The two values being compared.  These will be either REGs or
+     constants.  */
+  rtx in_a, in_b;
+
+  /* Information about how this comparison is used.  */
+  struct comparison_use uses[MAX_CMP_USE];
+
+  /* The original CC_MODE for this comparison.  */
+  enum machine_mode orig_mode;
+
+  /* The number of uses identified for this comparison.  */
+  unsigned short n_uses;
+
+  /* True if not all uses of this comparison have been identified.
+     This can happen either for overflowing the array above, or if
+     the flags register is used in some unusual context.  */
+  bool missing_uses;
+
+  /* True if its inputs are still valid at the end of the block.  */
+  bool inputs_valid;
+};
+  
+typedef struct comparison *comparison_struct_p;
+DEF_VEC_P(comparison_struct_p);
+DEF_VEC_ALLOC_P(comparison_struct_p, heap);
+
+static VEC(comparison_struct_p, heap) *all_compares;
+
+/* Look for a "conforming" comparison, as defined above.  If valid, return
+   the rtx for the COMPARE itself.  */
+
+static rtx
+conforming_compare (rtx insn)
+{
+  rtx set, src, dest;
+
+  set = single_set (insn);
+  if (set == NULL)
+    return NULL;
+
+  src = SET_SRC (set);
+  if (GET_CODE (src) != COMPARE)
+    return NULL;
+
+  dest = SET_DEST (set);
+  if (!REG_P (dest) || REGNO (dest) != targetm.flags_regnum)
+    return NULL;
+
+  if (REG_P (XEXP (src, 0))
+      && REG_P (XEXP (src, 0))
+      && (REG_P (XEXP (src, 1)) || CONSTANT_P (XEXP (src, 1))))
+    return src;
+
+  return NULL;
+}
+
+/* Look for a pattern of the "correct" form for an insn with a flags clobber
+   for which we may be able to eliminate a compare later.  We're not looking
+   to validate any inputs at this time, merely see that the basic shape is
+   correct.  The term "arithmetic" may be somewhat misleading...  */
+
+static bool
+arithmetic_flags_clobber_p (rtx insn)
+{
+  rtx pat, x;
+
+  if (!NONJUMP_INSN_P (insn))
+    return false;
+  pat = PATTERN (insn);
+  if (extract_asm_operands (pat))
+    return false;
+
+  if (GET_CODE (pat) == PARALLEL && XVECLEN (pat, 0) == 2)
+    {
+      x = XVECEXP (pat, 0, 0);
+      if (GET_CODE (x) != SET)
+	return false;
+      x = SET_DEST (x);
+      if (!REG_P (x))
+	return false;
+
+      x = XVECEXP (pat, 0, 1);
+      if (GET_CODE (x) == CLOBBER)
+	{
+	  x = XEXP (x, 0);
+	  if (REG_P (x) && REGNO (x) == targetm.flags_regnum)
+	    return true;
+	}
+    }
+
+  return false;
+}
+
+/* Look for uses of FLAGS in INSN.  If we find one we can analyze, record
+   it in CMP; otherwise indicate that we've missed a use.  */
+
+static void
+find_flags_uses_in_insn (struct comparison *cmp, rtx insn)
+{
+  df_ref *use_rec, use;
+
+  /* If we've already lost track of uses, don't bother collecting more.  */
+  if (cmp->missing_uses)
+    return;
+
+  /* Find a USE of the flags register.  */
+  for (use_rec = DF_INSN_USES (insn); (use = *use_rec) != NULL; use_rec++)
+    if (DF_REF_REGNO (use) == targetm.flags_regnum)
+      {
+	rtx x, *loc;
+
+	/* If this is an unusual use, quit.  */
+	if (DF_REF_TYPE (use) != DF_REF_REG_USE)
+	  goto fail;
+
+	/* If we've run out of slots to record uses, quit.  */
+	if (cmp->n_uses == MAX_CMP_USE)
+	  goto fail;
+
+	/* Unfortunately the location of the flags register, while present
+	   in the reference structure, doesn't help.  We need to find the
+	   comparison code that is outer to the actual flags use.  */
+	loc = DF_REF_LOC (use);
+	x = PATTERN (insn);
+	if (GET_CODE (x) == PARALLEL)
+	  x = XVECEXP (x, 0, 0);
+	x = SET_SRC (x);
+	if (GET_CODE (x) == IF_THEN_ELSE)
+	  x = XEXP (x, 0);
+	if (COMPARISON_P (x)
+	    && loc == &XEXP (x, 0)
+	    && XEXP (x, 1) == const0_rtx)
+	  {
+	    /* We've found a use of the flags that we understand.  */
+	    struct comparison_use *cuse = &cmp->uses[cmp->n_uses++];
+	    cuse->insn = insn;
+	    cuse->loc = loc;
+	    cuse->code = GET_CODE (x);
+	  }
+	else
+	  goto fail;
+      }
+  return;
+
+ fail:
+  /* We failed to recognize this use of the flags register.  */
+  cmp->missing_uses = true;
+}
+
+/* Identify comparison instructions within BB.  If the flags from the last
+   compare in the BB is live at the end of the block, install the compare
+   in BB->AUX.  Called via walk_dominators_tree.  */
+
+static void
+find_comparisons_in_bb (struct dom_walk_data *data ATTRIBUTE_UNUSED,
+			basic_block bb)
+{
+  struct comparison *last_cmp;
+  rtx insn, next, last_clobber;
+  bool last_cmp_valid;
+  bitmap killed;
+
+  killed = BITMAP_ALLOC (NULL);
+
+  /* The last comparison that was made.  Will be reset to NULL
+     once the flags are clobbered.  */
+  last_cmp = NULL;
+
+  /* True iff the last comparison has not been clobbered, nor
+     have its inputs.  Used to eliminate duplicate compares.  */
+  last_cmp_valid = false;
+
+  /* The last insn that clobbered the flags, if that insn is of
+     a form that may be valid for eliminating a following compare.
+     To be reset to NULL once the flags are set otherwise.  */
+  last_clobber = NULL;
+
+  /* Propagate the last live comparison throughout the extended basic block. */
+  if (single_pred_p (bb))
+    {
+      last_cmp = (struct comparison *) single_pred (bb)->aux;
+      if (last_cmp)
+	last_cmp_valid = last_cmp->inputs_valid;
+    }
+
+  for (insn = BB_HEAD (bb); insn; insn = next)
+    {
+      rtx src;
+
+      next = (insn == BB_END (bb) ? NULL_RTX : NEXT_INSN (insn));
+      if (!NONDEBUG_INSN_P (insn))
+	continue;
+
+      /* Compute the set of registers modified by this instruction.  */
+      bitmap_clear (killed);
+      df_simulate_find_defs (insn, killed);
+
+      src = conforming_compare (insn);
+      if (src)
+	{
+	  /* Eliminate a compare that's redundant with the previous.  */
+	  if (last_cmp_valid
+	      && rtx_equal_p (last_cmp->in_a, XEXP (src, 0))
+	      && rtx_equal_p (last_cmp->in_b, XEXP (src, 1)))
+	    {
+	      delete_insn (insn);
+	      continue;
+	    }
+
+          last_cmp = XCNEW (struct comparison);
+	  last_cmp->insn = insn;
+	  last_cmp->prev_clobber = last_clobber;
+	  last_cmp->in_a = XEXP (src, 0);
+	  last_cmp->in_b = XEXP (src, 1);
+	  last_cmp->orig_mode = GET_MODE (SET_DEST (single_set (insn)));
+	  VEC_safe_push (comparison_struct_p, heap, all_compares, last_cmp);
+
+	  /* It's unusual, but be prepared for comparison patterns that
+	     also clobber an input, or perhaps a scratch.  */
+	  last_clobber = NULL;
+	  last_cmp_valid = true;
+	}
+
+      /* Notice if this instruction kills the flags register.  */
+      else if (bitmap_bit_p (killed, targetm.flags_regnum))
+	{
+	  /* See if this insn could be the "clobber" that eliminates
+	     a future comparison.   */
+	  last_clobber = (arithmetic_flags_clobber_p (insn) ? insn : NULL);
+
+	  /* In either case, the previous compare is no longer valid.  */
+	  last_cmp = NULL;
+	  last_cmp_valid = false;
+	  continue;
+	}
+
+      /* Notice if this instruction uses the flags register.  */
+      else if (last_cmp)
+	find_flags_uses_in_insn (last_cmp, insn);
+
+      /* Notice if any of the inputs to the comparison have changed.  */
+      if (last_cmp_valid
+	  && (bitmap_bit_p (killed, REGNO (last_cmp->in_a))
+	      || (REG_P (last_cmp->in_b)
+		  && bitmap_bit_p (killed, REGNO (last_cmp->in_b)))))
+	last_cmp_valid = false;
+    }
+
+  BITMAP_FREE (killed);
+
+  /* Remember the live comparison for subsequent members of
+     the extended basic block.  */
+  if (last_cmp)
+    {
+      bb->aux = last_cmp;
+      last_cmp->inputs_valid = last_cmp_valid;
+
+      /* Look to see if the flags register is live outgoing here, and
+	 incoming to any successor not part of the extended basic block.  */
+      if (bitmap_bit_p (&DF_LIVE_BB_INFO (bb)->out, targetm.flags_regnum))
+	{
+	  edge e;
+	  edge_iterator ei;
+
+	  FOR_EACH_EDGE (e, ei, bb->succs)
+	    {
+	      basic_block dest = e->dest;
+	      if (bitmap_bit_p (&DF_LIVE_BB_INFO (dest)->in,
+				targetm.flags_regnum)
+		  && !single_pred_p (dest))
+		{
+		  last_cmp->missing_uses = true;
+		  break;
+		}
+	    }
+	}
+    }
+}
+
+/* Find all comparisons in the function.  */
+
+static void
+find_comparisons (void)
+{
+  struct dom_walk_data data;
+
+  memset (&data, 0, sizeof(data));
+  data.dom_direction = CDI_DOMINATORS;
+  data.before_dom_children = find_comparisons_in_bb;
+
+  calculate_dominance_info (CDI_DOMINATORS);
+
+  init_walk_dominator_tree (&data);
+  walk_dominator_tree (&data, ENTRY_BLOCK_PTR);
+  fini_walk_dominator_tree (&data);
+
+  clear_aux_for_blocks ();
+  free_dominance_info (CDI_DOMINATORS);
+}
+
+/* Select an alternate CC_MODE for a comparison insn comparing A and B.
+   Note that inputs are almost certainly different than the IN_A and IN_B
+   stored in CMP -- we're called while attempting to eliminate the compare
+   after all.  Return the new FLAGS rtx if successful, else return NULL.
+   Note that this function may start a change group.  */
+
+static rtx
+maybe_select_cc_mode (struct comparison *cmp, rtx a, rtx b)
+{
+  enum machine_mode sel_mode;
+  const int n = cmp->n_uses;
+  rtx flags = NULL;
+
+#ifndef SELECT_CC_MODE
+  /* Minimize code differences when this target macro is undefined.  */
+  return NULL;
+#define SELECT_CC_MODE(A,B,C) (gcc_unreachable (), VOIDmode)
+#endif
+
+  /* If we don't have access to all of the uses, we can't validate.  */
+  if (cmp->missing_uses || n == 0)
+    return NULL;
+
+  /* Find a new mode that works for all of the uses.  Special case the
+     common case of exactly one use.  */
+  if (n == 1)
+    {
+      sel_mode = SELECT_CC_MODE (cmp->uses[0].code, a, b);
+      if (sel_mode != cmp->orig_mode)
+	{
+	  flags = gen_rtx_REG (sel_mode, targetm.flags_regnum);
+	  validate_change (cmp->uses[0].insn, cmp->uses[0].loc, flags, true);
+	}
+    }
+  else
+    {
+      int i;
+
+      sel_mode = SELECT_CC_MODE (cmp->uses[0].code, a, b);
+      for (i = 1; i < n; ++i)
+	{
+	  enum machine_mode new_mode;
+	  new_mode = SELECT_CC_MODE (cmp->uses[i].code, a, b);
+	  if (new_mode != sel_mode)
+	    {
+	      sel_mode = targetm.cc_modes_compatible (sel_mode, new_mode);
+	      if (sel_mode == VOIDmode)
+		return NULL;
+	    }
+	}
+      
+      if (sel_mode != cmp->orig_mode)
+	{
+	  flags = gen_rtx_REG (sel_mode, targetm.flags_regnum);
+	  for (i = 0; i < n; ++i)
+	    validate_change (cmp->uses[i].insn, cmp->uses[i].loc, flags, true);
+	}
+    }
+
+  return flags;
+}
+
+/* Attempt to replace a comparison with a prior arithmetic insn that can
+   compute the same flags value as the comparison itself.  Return true if
+   successful, having made all rtl modifications necessary.  */
+
+static bool
+try_eliminate_compare (struct comparison *cmp)
+{
+  rtx x, insn, bb_head, flags, in_a, cmp_src;
+
+  /* We must have found an interesting "clobber" preceeding the compare.  */
+  if (cmp->prev_clobber == NULL)
+    return false;
+
+  /* ??? For the moment we don't handle comparisons for which IN_B
+     is a register.  We accepted these during initial comparison 
+     recognition in order to eliminate duplicate compares.
+     An improvement here would be to handle x = a - b; if (a cmp b).  */
+  if (!CONSTANT_P (cmp->in_b))
+    return false;
+
+  /* Verify that IN_A is not clobbered in between CMP and PREV_CLOBBER.
+     Given that this target requires this pass, we can assume that most
+     insns do clobber the flags, and so the distance between the compare
+     and the clobber is likely to be small.  */
+  /* ??? This is one point at which one could argue that DF_REF_CHAIN would
+     be useful, but it is thought to be too heavy-weight a solution here.  */
+
+  in_a = cmp->in_a;
+  insn = cmp->insn;
+  bb_head = BB_HEAD (BLOCK_FOR_INSN (insn));
+  for (insn = PREV_INSN (insn);
+       insn != cmp->prev_clobber;
+       insn = PREV_INSN (insn))
+    {
+      const int abnormal_flags
+	= (DF_REF_CONDITIONAL | DF_REF_PARTIAL | DF_REF_MAY_CLOBBER
+	   | DF_REF_MUST_CLOBBER | DF_REF_SIGN_EXTRACT
+	   | DF_REF_ZERO_EXTRACT | DF_REF_STRICT_LOW_PART
+	   | DF_REF_PRE_POST_MODIFY);
+      df_ref *def_rec, def;
+
+      /* Note that the BB_HEAD is always either a note or a label, but in
+	 any case it means that IN_A is defined outside the block.  */
+      if (insn == bb_head)
+	return false;
+      if (NOTE_P (insn) || DEBUG_INSN_P (insn))
+	continue;
+
+      /* Find a possible def of IN_A in INSN.  */
+      for (def_rec = DF_INSN_DEFS (insn); (def = *def_rec) != NULL; def_rec++)
+	if (DF_REF_REGNO (def) == REGNO (in_a))
+	  break;
+
+      /* No definitions of IN_A; continue searching.  */
+      if (def == NULL)
+	continue;
+
+      /* Bail if this is not a totally normal set of IN_A.  */
+      if (DF_REF_IS_ARTIFICIAL (def))
+	return false;
+      if (DF_REF_FLAGS (def) & abnormal_flags)
+	return false;
+
+      /* We've found an insn between the compare and the clobber that sets
+	 IN_A.  Given that pass_cprop_hardreg has not yet run, we still find
+	 situations in which we can usefully look through a copy insn.  */
+      x = single_set (insn);
+      if (x == NULL)
+	return false;
+      in_a = SET_SRC (x);
+      if (!REG_P (in_a))
+	return false;
+    }
+
+  /* We've reached PREV_CLOBBER without finding a modification of IN_A.
+     Validate that PREV_CLOBBER itself does in fact refer to IN_A.  Do
+     recall that we've already validated the shape of PREV_CLOBBER.  */
+  x = XVECEXP (PATTERN (insn), 0, 0);
+  if (!rtx_equal_p (SET_DEST (x), in_a))
+    return false;
+  cmp_src = SET_SRC (x);
+  
+  /* Determine if we ought to use a different CC_MODE here.  */
+  flags = maybe_select_cc_mode (cmp, cmp_src, cmp->in_b);
+  if (flags == NULL)
+    flags = gen_rtx_REG (cmp->orig_mode, targetm.flags_regnum);
+
+  /* Generate a new comparison for installation in the setter.  */
+  x = copy_rtx (cmp_src);
+  x = gen_rtx_COMPARE (GET_MODE (flags), x, cmp->in_b);
+  x = gen_rtx_SET (VOIDmode, flags, x);
+
+  /* Succeed if the new instruction is valid.  Note that we may have started
+     a change group within maybe_select_cc_mode, therefore we must continue. */
+  validate_change (insn, &XVECEXP (PATTERN (insn), 0, 1), x, true);
+  if (!apply_change_group ())
+    return false;
+ 
+  /* Success.  Delete the compare insn...  */
+  delete_insn (cmp->insn);
+
+  /* ... and any notes that are now invalid due to multiple sets.  */
+  x = find_regno_note (insn, REG_UNUSED, targetm.flags_regnum);
+  if (x)
+    remove_note (insn, x);
+  x = find_reg_note (insn, REG_EQUAL, NULL);
+  if (x)
+    remove_note (insn, x);
+  x = find_reg_note (insn, REG_EQUIV, NULL);
+  if (x)
+    remove_note (insn, x);
+
+  return true;
+}
+
+/* Main entry point to the pass.  */
+
+static unsigned int
+execute_compare_elim_after_reload (void)
+{
+  df_set_flags (DF_DEFER_INSN_RESCAN);
+  df_live_add_problem ();
+  df_analyze ();
+
+  gcc_checking_assert (all_compares == NULL);
+
+  /* Locate all comparisons and their uses, and eliminate duplicates.  */
+  find_comparisons ();
+  if (all_compares)
+    {
+      struct comparison *cmp;
+      size_t i;
+
+      /* Eliminate comparisons that are redundant with flags computation.  */
+      FOR_EACH_VEC_ELT (comparison_struct_p, all_compares, i, cmp)
+	{
+	  try_eliminate_compare (cmp);
+	  XDELETE (cmp);
+	}
+
+      VEC_free (comparison_struct_p, heap, all_compares);
+      all_compares = NULL;
+
+      df_analyze ();
+    }
+
+  return 0;
+}
+
+static bool
+gate_compare_elim_after_reload (void)
+{
+  /* Setting this target hook value is how a backend indicates the need.  */
+  if (targetm.flags_regnum == INVALID_REGNUM)
+    return false;
+  return flag_compare_elim_after_reload;
+}
+
+struct rtl_opt_pass pass_compare_elim_after_reload =
+{
+ {
+  RTL_PASS,
+  "cmpelim",				/* name */
+  gate_compare_elim_after_reload,	/* gate */
+  execute_compare_elim_after_reload,	/* execute */
+  NULL,					/* sub */
+  NULL,					/* next */
+  0,					/* static_pass_number */
+  TV_NONE,				/* tv_id */
+  0,					/* properties_required */
+  0,					/* properties_provided */
+  0,					/* properties_destroyed */
+  0,					/* todo_flags_start */
+  TODO_df_finish
+  | TODO_df_verify
+  | TODO_verify_rtl_sharing
+  | TODO_dump_func
+  | TODO_ggc_collect			/* todo_flags_finish */
+ }
+};
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index c7187f2..3d64438 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -337,7 +337,7 @@ Objective-C and Objective-C++ Dialects}.
 -fauto-inc-dec -fbranch-probabilities -fbranch-target-load-optimize @gol
 -fbranch-target-load-optimize2 -fbtr-bb-exclusive -fcaller-saves @gol
 -fcheck-data-deps -fcombine-stack-adjustments -fconserve-stack @gol
--fcprop-registers -fcrossjumping @gol
+-fcompare-elim -fcprop-registers -fcrossjumping @gol
 -fcse-follow-jumps -fcse-skip-blocks -fcx-fortran-rules @gol
 -fcx-limited-range @gol
 -fdata-sections -fdce -fdce -fdelayed-branch @gol
@@ -5870,6 +5870,7 @@ compilation time.
 @option{-O} turns on the following optimization flags:
 @gccoptlist{
 -fauto-inc-dec @gol
+-fcompare-elim @gol
 -fcprop-registers @gol
 -fdce @gol
 -fdefer-pop @gol
@@ -7689,6 +7690,18 @@ use hidden visibility) is similar to @code{-fwhole-program}.  See
 Enabled by default when LTO support in GCC is enabled and GCC was compiled
 with linker supporting plugins (GNU ld or @code{gold}).
 
+@item -fcompare-elim
+@opindex fcompare-elim
+After register allocation and post-register allocation instruction splitting,
+identify arithmetic instructions that compute processor flags similar to a
+comparison operation based on that arithmetic.  If possible, eliminate the
+explicit comparison operation.
+
+This pass only applies to certain targets that cannot explicitly represent
+the comparison operation before register allocation is complete.
+
+Enabled at levels @option{-O}, @option{-O2}, @option{-O3}, @option{-Os}.
+
 @item -fcprop-registers
 @opindex fcprop-registers
 After register allocation and post-register allocation instruction splitting,
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 3c9e659..85e1d88 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -4351,6 +4351,10 @@ to return a nonzero value when it is required, the compiler will run out
 of spill registers and print a fatal error message.
 @end deftypefn
 
+@deftypevr {Target Hook} {unsigned int} TARGET_FLAGS_REGNUM
+If the target has a dedicated flags register, and it needs to use the post-reload comparison elimination pass, then this value should be set appropriately.
+@end deftypevr
+
 @node Scalar Return
 @subsection How Scalar Function Values Are Returned
 @cindex return values in registers
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 71d7b46..a799bc4 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -4337,6 +4337,8 @@ to return a nonzero value when it is required, the compiler will run out
 of spill registers and print a fatal error message.
 @end deftypefn
 
+@hook TARGET_FLAGS_REGNUM
+
 @node Scalar Return
 @subsection How Scalar Function Values Are Returned
 @cindex return values in registers
diff --git a/gcc/opts.c b/gcc/opts.c
index 67fb6da..b958a09 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -456,6 +456,7 @@ static const struct default_options default_options_table[] =
     { OPT_LEVELS_1_PLUS, OPT_ftree_sink, NULL, 1 },
     { OPT_LEVELS_1_PLUS, OPT_ftree_ch, NULL, 1 },
     { OPT_LEVELS_1_PLUS, OPT_fcombine_stack_adjustments, NULL, 1 },
+    { OPT_LEVELS_1_PLUS, OPT_fcompare_elim, NULL, 1 },
 
     /* -O2 optimizations.  */
     { OPT_LEVELS_2_PLUS, OPT_finline_small_functions, NULL, 1 },
diff --git a/gcc/passes.c b/gcc/passes.c
index 090110e..d32bccf 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -1022,6 +1022,7 @@ init_optimization_passes (void)
 	  NEXT_PASS (pass_gcse2);
 	  NEXT_PASS (pass_split_after_reload);
 	  NEXT_PASS (pass_implicit_zee);
+	  NEXT_PASS (pass_compare_elim_after_reload);
 	  NEXT_PASS (pass_branch_target_load_optimize1);
 	  NEXT_PASS (pass_thread_prologue_and_epilogue);
 	  NEXT_PASS (pass_rtl_dse2);
diff --git a/gcc/recog.h b/gcc/recog.h
index 217c6e5..534d2c9 100644
--- a/gcc/recog.h
+++ b/gcc/recog.h
@@ -18,6 +18,9 @@ You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
+#ifndef GCC_RECOG_H
+#define GCC_RECOG_H
+
 /* Random number that should be large enough for all purposes.  */
 #define MAX_RECOG_ALTERNATIVES 30
 
@@ -305,3 +308,5 @@ struct insn_data_d
 
 extern const struct insn_data_d insn_data[];
 extern int peep2_current_count;
+
+#endif /* GCC_RECOG_H */
diff --git a/gcc/target.def b/gcc/target.def
index bdd7662..57134cb 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -1638,6 +1638,15 @@ DEFHOOK
  bool, (enum machine_mode mode),
  hook_bool_mode_false)
 
+/* Register number for a flags register.  Only needs to be defined if the
+   target is constrainted to use post-reload comparison elimination.  */
+DEFHOOKPOD
+(flags_regnum,
+ "If the target has a dedicated flags register, and it needs to use the\
+ post-reload comparison elimination pass, then this value should be set\
+ appropriately.",
+ unsigned int, INVALID_REGNUM)
+
 /* Compute a (partial) cost for rtx X.  Return true if the complete
    cost has been computed, and false if subexpressions should be
    scanned.  In either case, *TOTAL contains the cost result.  */
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 32d8f40..dd82288 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -551,6 +551,7 @@ extern struct rtl_opt_pass pass_reorder_blocks;
 extern struct rtl_opt_pass pass_branch_target_load_optimize2;
 extern struct rtl_opt_pass pass_leaf_regs;
 extern struct rtl_opt_pass pass_split_before_sched2;
+extern struct rtl_opt_pass pass_compare_elim_after_reload;
 extern struct rtl_opt_pass pass_sched2;
 extern struct rtl_opt_pass pass_stack_regs;
 extern struct rtl_opt_pass pass_stack_regs_run;

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [RFC, v3] New -fcompare-elim pass
  2011-01-21 17:54             ` [RFC, v3] " Richard Henderson
@ 2011-01-21 18:07               ` Richard Guenther
  2011-01-21 19:28               ` Jakub Jelinek
  2011-01-23 14:13               ` Andreas Schwab
  2 siblings, 0 replies; 90+ messages in thread
From: Richard Guenther @ 2011-01-21 18:07 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Paolo Bonzini, gcc-patches, nickc, law

On Fri, 21 Jan 2011, Richard Henderson wrote:

> On 01/18/2011 12:45 AM, Paolo Bonzini wrote:
> > Besides this, "seems to be perfect".
> 
> Heh.  Anyway, here's v3, with comments from v2 addressed.
> 
> I realize that neither mn10300 nor rx are even secondary targets.
> However, this patch avoids a regression for these targets, and 
> Nick did post a patch trying to address this (which I rejected)
> at least as early as October.
> 
> Therefore I'm requesting that the Release Manager consider allowing
> this pass at this late stage.

If it doesn't affect primary or secondary targets then it's ok.
Be prepared to address eventual build problems that pop up though.

Thanks,
Richard.

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [RFC, v3] New -fcompare-elim pass
  2011-01-21 17:54             ` [RFC, v3] " Richard Henderson
  2011-01-21 18:07               ` Richard Guenther
@ 2011-01-21 19:28               ` Jakub Jelinek
  2011-01-23 14:13               ` Andreas Schwab
  2 siblings, 0 replies; 90+ messages in thread
From: Jakub Jelinek @ 2011-01-21 19:28 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Paolo Bonzini, gcc-patches, nickc, law, rguenther

On Fri, Jan 21, 2011 at 09:38:03AM -0800, Richard Henderson wrote:
> On 01/18/2011 12:45 AM, Paolo Bonzini wrote:
> > Besides this, "seems to be perfect".
> 
> Heh.  Anyway, here's v3, with comments from v2 addressed.
> 
> I realize that neither mn10300 nor rx are even secondary targets.
> However, this patch avoids a regression for these targets, and 
> Nick did post a patch trying to address this (which I rejected)
> at least as early as October.
> 
> Therefore I'm requesting that the Release Manager consider allowing
> this pass at this late stage.

This is OK from RM perspective.

	Jakub

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [RFC, v3] New -fcompare-elim pass
  2011-01-21 17:54             ` [RFC, v3] " Richard Henderson
  2011-01-21 18:07               ` Richard Guenther
  2011-01-21 19:28               ` Jakub Jelinek
@ 2011-01-23 14:13               ` Andreas Schwab
  2011-01-23 17:12                 ` Andreas Schwab
  2 siblings, 1 reply; 90+ messages in thread
From: Andreas Schwab @ 2011-01-23 14:13 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Paolo Bonzini, gcc-patches, nickc, law, rguenther

../../gcc/compare-elim.c: In function 'maybe_select_cc_mode':
../../gcc/compare-elim.c:407:51: error: unused parameter 'a' [-Werror=unused-parameter]
../../gcc/compare-elim.c:407:58: error: unused parameter 'b' [-Werror=unused-parameter]

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."

^ permalink raw reply	[flat|nested] 90+ messages in thread

* Re: [RFC, v3] New -fcompare-elim pass
  2011-01-23 14:13               ` Andreas Schwab
@ 2011-01-23 17:12                 ` Andreas Schwab
  0 siblings, 0 replies; 90+ messages in thread
From: Andreas Schwab @ 2011-01-23 17:12 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Paolo Bonzini, gcc-patches, nickc, law, rguenther

Committed.

Andreas.

2011-01-23  Andreas Schwab  <schwab@linux-m68k.org>

	* compare-elim.c (maybe_select_cc_mode): Add ATTRIBUTE_UNUSED
	markers.

Index: compare-elim.c
===================================================================
--- compare-elim.c	(revision 169142)
+++ compare-elim.c	(working copy)
@@ -404,7 +404,8 @@ find_comparisons (void)
    Note that this function may start a change group.  */
 
 static rtx
-maybe_select_cc_mode (struct comparison *cmp, rtx a, rtx b)
+maybe_select_cc_mode (struct comparison *cmp, rtx a ATTRIBUTE_UNUSED,
+		      rtx b ATTRIBUTE_UNUSED)
 {
   enum machine_mode sel_mode;
   const int n = cmp->n_uses;

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."

^ permalink raw reply	[flat|nested] 90+ messages in thread

end of thread, other threads:[~2011-01-23 14:28 UTC | newest]

Thread overview: 90+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-01-10 20:33 [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Richard Henderson
2011-01-10 20:32 ` [PATCH 01/28] mn10300: Better definition of INCOMING_RETURN_ADDR_RTX Richard Henderson
2011-01-11 14:45   ` Jeff Law
2011-01-10 20:32 ` [PATCH 04/28] mn10300: Emit the movm stores in the correct order Richard Henderson
2011-01-11 14:53   ` Jeff Law
2011-01-11 17:10     ` Richard Henderson
2011-01-10 20:32 ` [PATCH 13/28] mn10300: cleanup secondary reloads Richard Henderson
2011-01-18 17:14   ` Jeff Law
2011-01-18 18:35     ` Richard Henderson
2011-01-18 18:49       ` Jeff Law
2011-01-18 19:12         ` Richard Henderson
2011-01-19 15:41           ` Jeff Law
2011-01-19 16:55             ` Richard Henderson
2011-01-10 20:33 ` [PATCH 20/28] mn10300: Emit clr Richard Henderson
2011-01-12 14:05   ` Jeff Law
2011-01-10 20:33 ` [PATCH 02/28] mn10300: disable test tree-ssa/vrp47.c Richard Henderson
2011-01-11 14:46   ` Jeff Law
2011-01-10 20:33 ` [PATCH 27/28] mn10300: Add support in longlong.h Richard Henderson
2011-01-12 14:31   ` Jeff Law
2011-01-12 18:10     ` Richard Henderson
2011-01-10 20:33 ` [PATCH 12/28] mn10300: Re-write move patterns Richard Henderson
2011-01-18 17:12   ` Jeff Law
2011-01-18 18:30     ` Richard Henderson
2011-01-19 16:12       ` Jeff Law
2011-01-19 19:21         ` Hans-Peter Nilsson
2011-01-18 19:18     ` Richard Henderson
2011-01-19 15:48       ` Jeff Law
2011-01-10 20:33 ` [PATCH 15/28] mn10300: Force lower-subreg pass to run Richard Henderson
2011-01-12 14:04   ` Jeff Law
2011-01-10 20:33 ` [PATCH 21/28] mn10300: Add clzsi2 Richard Henderson
2011-01-12 14:05   ` Jeff Law
2011-01-10 20:33 ` [PATCH 10/28] mn10300: Clean up trampoline handling Richard Henderson
2011-01-12 14:04   ` Jeff Law
2011-01-10 20:33 ` [PATCH 06/28] mn10300: fp insn cleanup Richard Henderson
2011-01-11 14:46   ` Jeff Law
2011-01-10 20:33 ` [PATCH 25/28] mn10300: Use reg_or_am33_const_operand in mulsi3 Richard Henderson
2011-01-12 14:06   ` Jeff Law
2011-01-12 18:07     ` Richard Henderson
2011-01-12 18:11       ` Jeff Law
2011-01-10 20:33 ` [PATCH 23/28] mn10300: Add delegitimize_address hook Richard Henderson
2011-01-12 14:06   ` Jeff Law
2011-01-10 20:34 ` [PATCH 05/28] mn10300: Fix debug offsets into the stack frame Richard Henderson
2011-01-11 14:50   ` Jeff Law
2011-01-10 20:34 ` [PATCH 11/28] mn10300: Clean up costing Richard Henderson
2011-01-11 15:02   ` Jeff Law
2011-01-10 20:34 ` [PATCH 09/28] mn10300: Remove bset/bclr patterns Richard Henderson
2011-01-11 14:57   ` Jeff Law
2011-01-10 20:34 ` [PATCH 28/28] New -fcompare-elim pass Richard Henderson
2011-01-11 19:00   ` Nathan Froyd
2011-01-11 19:24     ` Richard Henderson
2011-01-12  9:07   ` Paolo Bonzini
2011-01-12 20:34     ` Richard Henderson
2011-01-13  9:04       ` Paolo Bonzini
2011-01-17 22:42         ` [RFC, v2] " Richard Henderson
2011-01-18 10:06           ` Paolo Bonzini
2011-01-21 17:54             ` [RFC, v3] " Richard Henderson
2011-01-21 18:07               ` Richard Guenther
2011-01-21 19:28               ` Jakub Jelinek
2011-01-23 14:13               ` Andreas Schwab
2011-01-23 17:12                 ` Andreas Schwab
2011-01-10 20:34 ` [PATCH 07/28] mn10300: Add attribute enabled Richard Henderson
2011-01-11 14:47   ` Jeff Law
2011-01-10 20:34 ` [PATCH 24/28] mn10300: Implement adddi3, subdi3 Richard Henderson
2011-01-19 18:45   ` Jeff Law
2011-01-10 20:34 ` [PATCH 17/28] mn10300: Explicitly represent MDR in multiply and divide Richard Henderson
2011-01-18 18:13   ` Jeff Law
2011-01-10 20:34 ` [PATCH 03/28] mn10300: delete ASM_PN_FORMAT Richard Henderson
2011-01-11 14:46   ` Jeff Law
2011-01-10 20:34 ` [PATCH 08/28] mn10300: Define the A and D constraints Richard Henderson
2011-01-11 14:56   ` Jeff Law
2011-01-11 16:44     ` Richard Henderson
2011-01-11 18:53       ` Jeff Law
2011-01-11 19:31         ` Richard Henderson
2011-01-11 20:59           ` Gerald Pfeifer
2011-01-12  0:30           ` Jeff Law
2011-01-10 20:34 ` [PATCH 26/28] mn10300: Auto-clobber the flags in asms Richard Henderson
2011-01-12 14:22   ` Jeff Law
2011-01-10 20:34 ` [PATCH 18/28] mn10300: Cleanup all arithmetic Richard Henderson
2011-01-19 16:58   ` Jeff Law
2011-01-10 20:34 ` [PATCH 22/28] mn10300: Emit retf instruction Richard Henderson
2011-01-18 18:18   ` Jeff Law
2011-01-10 20:34 ` [PATCH 14/28] mn10300: Cleanup legitimate addresses Richard Henderson
2011-01-18 17:14   ` Jeff Law
2011-01-10 20:39 ` [PATCH 16/28] mn10300: Expose the MDR register to register allocation Richard Henderson
2011-01-18 17:56   ` Jeff Law
2011-01-10 20:44 ` [PATCH 19/28] mn10300: tidy pic address loading Richard Henderson
2011-01-19 16:44   ` Jeff Law
2011-01-11 14:20 ` [PATCH 00/28] mn10300 cleanup + compare-elim, v2 Nick Clifton
2011-01-11 16:45   ` Richard Henderson
2011-01-11 18:31 ` Richard Henderson

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).