OSDN Git Service

* alias.c (record_set): Use hard_regno_nregs.
[pf3gnuchains/gcc-fork.git] / gcc / postreload.c
index 78153b6..e0f72d9 100644 (file)
@@ -1,6 +1,6 @@
 /* Perform simple optimizations to clean up the result of reload.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -45,24 +45,23 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "except.h"
 #include "tree.h"
 
-static int reload_cse_noop_set_p       PARAMS ((rtx));
-static void reload_cse_simplify                PARAMS ((rtx, rtx));
-static void reload_cse_regs_1          PARAMS ((rtx));
-static int reload_cse_simplify_set     PARAMS ((rtx, rtx));
-static int reload_cse_simplify_operands        PARAMS ((rtx, rtx));
+static int reload_cse_noop_set_p (rtx);
+static void reload_cse_simplify (rtx, rtx);
+static void reload_cse_regs_1 (rtx);
+static int reload_cse_simplify_set (rtx, rtx);
+static int reload_cse_simplify_operands (rtx, rtx);
 
-static void reload_combine             PARAMS ((void));
-static void reload_combine_note_use    PARAMS ((rtx *, rtx));
-static void reload_combine_note_store  PARAMS ((rtx, rtx, void *));
+static void reload_combine (void);
+static void reload_combine_note_use (rtx *, rtx);
+static void reload_combine_note_store (rtx, rtx, void *);
 
-static void reload_cse_move2add                PARAMS ((rtx));
-static void move2add_note_store                PARAMS ((rtx, rtx, void *));
+static void reload_cse_move2add (rtx);
+static void move2add_note_store (rtx, rtx, void *);
 
 /* Call cse / combine like post-reload optimization phases.
    FIRST is the first instruction.  */
 void
-reload_cse_regs (first)
-     rtx first ATTRIBUTE_UNUSED;
+reload_cse_regs (rtx first ATTRIBUTE_UNUSED)
 {
   reload_cse_regs_1 (first);
   reload_combine ();
@@ -73,8 +72,7 @@ reload_cse_regs (first)
 
 /* See whether a single set SET is a noop.  */
 static int
-reload_cse_noop_set_p (set)
-     rtx set;
+reload_cse_noop_set_p (rtx set)
 {
   if (cselib_reg_set_mode (SET_DEST (set)) != GET_MODE (SET_DEST (set)))
     return 0;
@@ -84,9 +82,7 @@ reload_cse_noop_set_p (set)
 
 /* Try to simplify INSN.  */
 static void
-reload_cse_simplify (insn, testreg)
-     rtx insn;
-     rtx testreg;
+reload_cse_simplify (rtx insn, rtx testreg)
 {
   rtx body = PATTERN (insn);
 
@@ -180,8 +176,7 @@ reload_cse_simplify (insn, testreg)
    if possible, much like an optional reload would.  */
 
 static void
-reload_cse_regs_1 (first)
-     rtx first;
+reload_cse_regs_1 (rtx first)
 {
   rtx insn;
   rtx testreg = gen_rtx_REG (VOIDmode, -1);
@@ -209,9 +204,7 @@ reload_cse_regs_1 (first)
    and change the set into a register copy.  */
 
 static int
-reload_cse_simplify_set (set, insn)
-     rtx set;
-     rtx insn;
+reload_cse_simplify_set (rtx set, rtx insn)
 {
   int did_change = 0;
   int dreg;
@@ -246,21 +239,19 @@ reload_cse_simplify_set (set, insn)
     return 0;
 #endif
 
+  val = cselib_lookup (src, GET_MODE (SET_DEST (set)), 0);
+  if (! val)
+    return 0;
+
   /* If memory loads are cheaper than register copies, don't change them.  */
   if (GET_CODE (src) == MEM)
     old_cost = MEMORY_MOVE_COST (GET_MODE (src), dclass, 1);
-  else if (CONSTANT_P (src))
-    old_cost = rtx_cost (src, SET);
   else if (GET_CODE (src) == REG)
     old_cost = REGISTER_MOVE_COST (GET_MODE (src),
                                   REGNO_REG_CLASS (REGNO (src)), dclass);
   else
-    /* ???   */
     old_cost = rtx_cost (src, SET);
 
-  val = cselib_lookup (src, GET_MODE (SET_DEST (set)), 0);
-  if (! val)
-    return 0;
   for (l = val->locs; l; l = l->next)
     {
       rtx this_rtx = l->loc;
@@ -356,9 +347,7 @@ reload_cse_simplify_set (set, insn)
    hard registers.  */
 
 static int
-reload_cse_simplify_operands (insn, testreg)
-     rtx insn;
-     rtx testreg;
+reload_cse_simplify_operands (rtx insn, rtx testreg)
 {
   int i, j;
 
@@ -388,17 +377,19 @@ reload_cse_simplify_operands (insn, testreg)
   if (! constrain_operands (1))
     fatal_insn_not_found (insn);
 
-  alternative_reject = (int *) alloca (recog_data.n_alternatives * sizeof (int));
-  alternative_nregs = (int *) alloca (recog_data.n_alternatives * sizeof (int));
-  alternative_order = (int *) alloca (recog_data.n_alternatives * sizeof (int));
-  memset ((char *) alternative_reject, 0, recog_data.n_alternatives * sizeof (int));
-  memset ((char *) alternative_nregs, 0, recog_data.n_alternatives * sizeof (int));
+  alternative_reject = alloca (recog_data.n_alternatives * sizeof (int));
+  alternative_nregs = alloca (recog_data.n_alternatives * sizeof (int));
+  alternative_order = alloca (recog_data.n_alternatives * sizeof (int));
+  memset (alternative_reject, 0, recog_data.n_alternatives * sizeof (int));
+  memset (alternative_nregs, 0, recog_data.n_alternatives * sizeof (int));
 
   /* For each operand, find out which regs are equivalent.  */
   for (i = 0; i < recog_data.n_operands; i++)
     {
       cselib_val *v;
       struct elt_loc_list *l;
+      rtx op;
+      enum machine_mode mode;
 
       CLEAR_HARD_REG_SET (equiv_regs[i]);
 
@@ -410,7 +401,61 @@ reload_cse_simplify_operands (insn, testreg)
              && recog_data.operand_mode[i] == VOIDmode))
        continue;
 
-      v = cselib_lookup (recog_data.operand[i], recog_data.operand_mode[i], 0);
+      op = recog_data.operand[i];
+      mode = GET_MODE (op);
+#ifdef LOAD_EXTEND_OP
+      if (GET_CODE (op) == MEM
+         && GET_MODE_BITSIZE (mode) < BITS_PER_WORD
+         && LOAD_EXTEND_OP (mode) != NIL)
+       {
+         rtx set = single_set (insn);
+
+         /* We might have multiple sets, some of which do implicit
+            extension.  Punt on this for now.  */
+         if (! set)
+           continue;
+         /* If the destination is a also MEM or a STRICT_LOW_PART, no
+            extension applies.
+            Also, if there is an explicit extension, we don't have to
+            worry about an implicit one.  */
+         else if (GET_CODE (SET_DEST (set)) == MEM
+                  || GET_CODE (SET_DEST (set)) == STRICT_LOW_PART
+                  || GET_CODE (SET_SRC (set)) == ZERO_EXTEND
+                  || GET_CODE (SET_SRC (set)) == SIGN_EXTEND)
+           ; /* Continue ordinary processing.  */
+#ifdef CANNOT_CHANGE_MODE_CLASS
+         /* If the register cannot change mode to word_mode, it follows that
+            it cannot have been used in word_mode.  */
+         else if (GET_CODE (SET_DEST (set)) == REG
+                  && CANNOT_CHANGE_MODE_CLASS (GET_MODE (SET_DEST (set)),
+                                               word_mode,
+                                               REGNO_REG_CLASS (REGNO (SET_DEST (set)))))
+           ; /* Continue ordinary processing.  */
+#endif
+         /* If this is a straight load, make the extension explicit.  */
+         else if (GET_CODE (SET_DEST (set)) == REG
+                  && recog_data.n_operands == 2
+                  && SET_SRC (set) == op
+                  && SET_DEST (set) == recog_data.operand[1-i])
+           {
+             validate_change (insn, recog_data.operand_loc[i],
+                              gen_rtx_fmt_e (LOAD_EXTEND_OP (mode),
+                                             word_mode, op),
+                              1);
+             validate_change (insn, recog_data.operand_loc[1-i],
+                              gen_rtx_REG (word_mode, REGNO (SET_DEST (set))),
+                              1);
+             if (! apply_change_group ())
+               return 0;
+             return reload_cse_simplify_operands (insn, testreg);
+           }
+         else
+           /* ??? There might be arithmetic operations with memory that are
+              safe to optimize, but is it worth the trouble?  */
+           continue;
+       }
+#endif /* LOAD_EXTEND_OP */
+      v = cselib_lookup (op, recog_data.operand_mode[i], 0);
       if (! v)
        continue;
 
@@ -425,7 +470,7 @@ reload_cse_simplify_operands (insn, testreg)
       int regno;
       const char *p;
 
-      op_alt_regno[i] = (int *) alloca (recog_data.n_alternatives * sizeof (int));
+      op_alt_regno[i] = alloca (recog_data.n_alternatives * sizeof (int));
       for (j = 0; j < recog_data.n_alternatives; j++)
        op_alt_regno[i][j] = -1;
 
@@ -631,7 +676,7 @@ static int reload_combine_ruid;
   (label_live[CODE_LABEL_NUMBER (LABEL) - min_labelno])
 
 static void
-reload_combine ()
+reload_combine (void)
 {
   rtx insn, set;
   int first_index_reg = -1;
@@ -670,12 +715,12 @@ reload_combine ()
      destination.  */
   min_labelno = get_first_label_num ();
   n_labels = max_label_num () - min_labelno;
-  label_live = (HARD_REG_SET *) xmalloc (n_labels * sizeof (HARD_REG_SET));
+  label_live = xmalloc (n_labels * sizeof (HARD_REG_SET));
   CLEAR_HARD_REG_SET (ever_live_at_start);
 
   FOR_EACH_BB_REVERSE (bb)
     {
-      insn = bb->head;
+      insn = BB_HEAD (bb);
       if (GET_CODE (insn) == CODE_LABEL)
        {
          HARD_REG_SET live;
@@ -729,16 +774,19 @@ reload_combine ()
         ... (MEM (PLUS (REGZ) (REGY)))... .
 
         First, check that we have (set (REGX) (PLUS (REGX) (REGY)))
-        and that we know all uses of REGX before it dies.  */
+        and that we know all uses of REGX before it dies.  
+        Also, explicitly check that REGX != REGY; our life information
+        does not yet show whether REGY changes in this insn.  */
       set = single_set (insn);
       if (set != NULL_RTX
          && GET_CODE (SET_DEST (set)) == REG
-         && (HARD_REGNO_NREGS (REGNO (SET_DEST (set)),
-                               GET_MODE (SET_DEST (set)))
+         && (hard_regno_nregs[REGNO (SET_DEST (set))]
+                             [GET_MODE (SET_DEST (set))]
              == 1)
          && GET_CODE (SET_SRC (set)) == PLUS
          && GET_CODE (XEXP (SET_SRC (set), 1)) == REG
          && rtx_equal_p (XEXP (SET_SRC (set), 0), SET_DEST (set))
+         && !rtx_equal_p (XEXP (SET_SRC (set), 1), SET_DEST (set))
          && last_label_ruid < reg_state[REGNO (SET_DEST (set))].use_ruid)
        {
          rtx reg = SET_DEST (set);
@@ -768,7 +816,7 @@ reload_combine ()
          else
            {
              /* Otherwise, look for a free index register.  Since we have
-                checked above that neiter REG nor BASE are index registers,
+                checked above that neither REG nor BASE are index registers,
                 if we find anything at all, it will be different from these
                 two registers.  */
              for (i = first_index_reg; i <= last_index_reg; i++)
@@ -777,7 +825,7 @@ reload_combine ()
                                         i)
                      && reg_state[i].use_index == RELOAD_COMBINE_MAX_USES
                      && reg_state[i].store_ruid <= reg_state[regno].use_ruid
-                     && HARD_REGNO_NREGS (i, GET_MODE (reg)) == 1)
+                     && hard_regno_nregs[i][GET_MODE (reg)] == 1)
                    {
                      rtx index_reg = gen_rtx_REG (GET_MODE (reg), i);
 
@@ -870,7 +918,7 @@ reload_combine ()
                  unsigned int i;
                  unsigned int start_reg = REGNO (usage_rtx);
                  unsigned int num_regs =
-                       HARD_REGNO_NREGS (start_reg, GET_MODE (usage_rtx));
+                       hard_regno_nregs[start_reg][GET_MODE (usage_rtx)];
                  unsigned int end_reg  = start_reg + num_regs - 1;
                  for (i = start_reg; i <= end_reg; i++)
                    if (GET_CODE (XEXP (link, 0)) == CLOBBER)
@@ -924,9 +972,7 @@ reload_combine ()
    accordingly.  Called via note_stores from reload_combine.  */
 
 static void
-reload_combine_note_store (dst, set, data)
-     rtx dst, set;
-     void *data ATTRIBUTE_UNUSED;
+reload_combine_note_store (rtx dst, rtx set, void *data ATTRIBUTE_UNUSED)
 {
   int regno = 0;
   int i;
@@ -953,7 +999,7 @@ reload_combine_note_store (dst, set, data)
       || GET_CODE (SET_DEST (set)) == SIGN_EXTRACT
       || GET_CODE (SET_DEST (set)) == STRICT_LOW_PART)
     {
-      for (i = HARD_REGNO_NREGS (regno, mode) - 1 + regno; i >= regno; i--)
+      for (i = hard_regno_nregs[regno][mode] - 1 + regno; i >= regno; i--)
        {
          reg_state[i].use_index = -1;
          reg_state[i].store_ruid = reload_combine_ruid;
@@ -961,7 +1007,7 @@ reload_combine_note_store (dst, set, data)
     }
   else
     {
-      for (i = HARD_REGNO_NREGS (regno, mode) - 1 + regno; i >= regno; i--)
+      for (i = hard_regno_nregs[regno][mode] - 1 + regno; i >= regno; i--)
        {
          reg_state[i].store_ruid = reload_combine_ruid;
          reg_state[i].use_index = RELOAD_COMBINE_MAX_USES;
@@ -974,8 +1020,7 @@ reload_combine_note_store (dst, set, data)
    *XP is the pattern of INSN, or a part of it.
    Called from reload_combine, and recursively by itself.  */
 static void
-reload_combine_note_use (xp, insn)
-     rtx *xp, insn;
+reload_combine_note_use (rtx *xp, rtx insn)
 {
   rtx x = *xp;
   enum rtx_code code = x->code;
@@ -1000,7 +1045,7 @@ reload_combine_note_use (xp, insn)
        /* Mark the return register as used in an unknown fashion.  */
          rtx reg = XEXP (x, 0);
          int regno = REGNO (reg);
-         int nregs = HARD_REGNO_NREGS (regno, GET_MODE (reg));
+         int nregs = hard_regno_nregs[regno][GET_MODE (reg)];
 
          while (--nregs >= 0)
            reg_state[regno + nregs].use_index = -1;
@@ -1036,7 +1081,7 @@ reload_combine_note_use (xp, insn)
        if (regno >= FIRST_PSEUDO_REGISTER)
          abort ();
 
-       nregs = HARD_REGNO_NREGS (regno, GET_MODE (x));
+       nregs = hard_regno_nregs[regno][GET_MODE (x)];
 
        /* We can't substitute into multi-hard-reg uses.  */
        if (nregs > 1)
@@ -1133,8 +1178,7 @@ static int move2add_last_label_luid;
                                 GET_MODE_BITSIZE (INMODE))))
 
 static void
-reload_cse_move2add (first)
-     rtx first;
+reload_cse_move2add (rtx first)
 {
   int i;
   rtx insn;
@@ -1211,14 +1255,12 @@ reload_cse_move2add (first)
                  else if (rtx_cost (new_src, PLUS) < rtx_cost (src, SET)
                           && have_add2_insn (reg, new_src))
                    {
-                     rtx newpat = gen_add2_insn (reg, new_src);
-                     if (INSN_P (newpat) && NEXT_INSN (newpat) == NULL_RTX)
-                       newpat = PATTERN (newpat);
-                     /* If it was the first insn of a sequence or
-                        some other emitted insn, validate_change will
-                        reject it.  */
-                     validate_change (insn, &PATTERN (insn),
-                                      newpat, 0);
+                     rtx newpat = gen_rtx_SET (VOIDmode,
+                                               reg,
+                                               gen_rtx_PLUS (GET_MODE (reg),
+                                                             reg,
+                                                             new_src));
+                     validate_change (insn, &PATTERN (insn), newpat, 0);
                    }
                  else
                    {
@@ -1300,10 +1342,11 @@ reload_cse_move2add (first)
                                < COSTS_N_INSNS (1) + rtx_cost (src3, SET))
                               && have_add2_insn (reg, new_src))
                        {
-                         rtx newpat = gen_add2_insn (reg, new_src);
-                         if (INSN_P (newpat)
-                             && NEXT_INSN (newpat) == NULL_RTX)
-                           newpat = PATTERN (newpat);
+                         rtx newpat = gen_rtx_SET (VOIDmode,
+                                                   reg,
+                                                   gen_rtx_PLUS (GET_MODE (reg),
+                                                                 reg,
+                                                                 new_src));
                          success
                            = validate_change (next, &PATTERN (next),
                                               newpat, 0);
@@ -1348,7 +1391,7 @@ reload_cse_move2add (first)
                 number of calls to gen_rtx_SET to avoid memory
                 allocation if possible.  */
              && SCALAR_INT_MODE_P (GET_MODE (XEXP (cnd, 0)))
-             && HARD_REGNO_NREGS (REGNO (XEXP (cnd, 0)), GET_MODE (XEXP (cnd, 0))) == 1
+             && hard_regno_nregs[REGNO (XEXP (cnd, 0))][GET_MODE (XEXP (cnd, 0))] == 1
              && GET_CODE (XEXP (cnd, 1)) == CONST_INT)
            {
              rtx implicit_set =
@@ -1376,9 +1419,7 @@ reload_cse_move2add (first)
    Called from reload_cse_move2add via note_stores.  */
 
 static void
-move2add_note_store (dst, set, data)
-     rtx dst, set;
-     void *data ATTRIBUTE_UNUSED;
+move2add_note_store (rtx dst, rtx set, void *data ATTRIBUTE_UNUSED)
 {
   unsigned int regno = 0;
   unsigned int i;
@@ -1409,7 +1450,7 @@ move2add_note_store (dst, set, data)
   regno += REGNO (dst);
 
   if (SCALAR_INT_MODE_P (mode)
-      && HARD_REGNO_NREGS (regno, mode) == 1 && GET_CODE (set) == SET
+      && hard_regno_nregs[regno][mode] == 1 && GET_CODE (set) == SET
       && GET_CODE (SET_DEST (set)) != ZERO_EXTRACT
       && GET_CODE (SET_DEST (set)) != SIGN_EXTRACT
       && GET_CODE (SET_DEST (set)) != STRICT_LOW_PART)
@@ -1510,7 +1551,7 @@ move2add_note_store (dst, set, data)
     }
   else
     {
-      unsigned int endregno = regno + HARD_REGNO_NREGS (regno, mode);
+      unsigned int endregno = regno + hard_regno_nregs[regno][mode];
 
       for (i = regno; i < endregno; i++)
        /* Reset the information about this register.  */