OSDN Git Service

2010-12-06 Jerry DeLisle <jvdelisle@gcc.gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / lower-subreg.c
index c61a8b7..3563cee 100644 (file)
@@ -1,5 +1,5 @@
 /* Decompose multiword subregs.
-   Copyright (C) 2007 Free Software Foundation, Inc.
+   Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>
                  Ian Lance Taylor <iant@google.com>
 
@@ -33,6 +33,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "basic-block.h"
 #include "recog.h"
 #include "bitmap.h"
+#include "dce.h"
 #include "expr.h"
 #include "except.h"
 #include "regs.h"
@@ -63,6 +64,12 @@ static bitmap decomposable_context;
    which it can not be decomposed.  */
 static bitmap non_decomposable_context;
 
+/* Bit N in this bitmap is set if regno N is used in a subreg
+   which changes the mode but not the size.  This typically happens
+   when the register accessed as a floating-point value; we want to
+   avoid generating accesses to its subwords in integer modes.  */
+static bitmap subreg_context;
+
 /* Bit N in the bitmap in element M of this array is set if there is a
    copy from reg M to reg N.  */
 static VEC(bitmap,heap) *reg_copy_graph;
@@ -225,11 +232,9 @@ enum classify_move_insn
 {
   /* Not a simple move from one location to another.  */
   NOT_SIMPLE_MOVE,
-  /* A simple move from one pseudo-register to another with no
-     REG_RETVAL note.  */
+  /* A simple move from one pseudo-register to another.  */
   SIMPLE_PSEUDO_REG_MOVE,
-  /* A simple move involving a non-pseudo-register, or from one
-     pseudo-register to another with a REG_RETVAL note.  */
+  /* A simple move involving a non-pseudo-register.  */
   SIMPLE_MOVE
 };
 
@@ -291,6 +296,7 @@ find_decomposable_subregs (rtx *px, void *data)
          && !MODES_TIEABLE_P (GET_MODE (x), GET_MODE (inner)))
        {
          bitmap_set_bit (non_decomposable_context, regno);
+         bitmap_set_bit (subreg_context, regno);
          return -1;
        }
     }
@@ -304,10 +310,10 @@ find_decomposable_subregs (rtx *px, void *data)
 
         If this is not a simple copy from one location to another,
         then we can not decompose this register.  If this is a simple
-        copy from one pseudo-register to another, with no REG_RETVAL
-        note, and the mode is right, then we mark the register as
-        decomposable.  Otherwise we don't say anything about this
-        register--it could be decomposed, but whether that would be
+        copy from one pseudo-register to another, and the mode is right
+        then we mark the register as decomposable.
+        Otherwise we don't say anything about this register --
+        it could be decomposed, but whether that would be
         profitable depends upon how it is used elsewhere.
 
         We only set bits in the bitmap for multi-word
@@ -390,7 +396,7 @@ simplify_subreg_concatn (enum machine_mode outermode, rtx op,
                         unsigned int byte)
 {
   unsigned int inner_size;
-  enum machine_mode innermode;
+  enum machine_mode innermode, partmode;
   rtx part;
   unsigned int final_offset;
 
@@ -403,11 +409,24 @@ simplify_subreg_concatn (enum machine_mode outermode, rtx op,
 
   inner_size = GET_MODE_SIZE (innermode) / XVECLEN (op, 0);
   part = XVECEXP (op, 0, byte / inner_size);
+  partmode = GET_MODE (part);
+
+  /* VECTOR_CSTs in debug expressions are expanded into CONCATN instead of
+     regular CONST_VECTORs.  They have vector or integer modes, depending
+     on the capabilities of the target.  Cope with them.  */
+  if (partmode == VOIDmode && VECTOR_MODE_P (innermode))
+    partmode = GET_MODE_INNER (innermode);
+  else if (partmode == VOIDmode)
+    {
+      enum mode_class mclass = GET_MODE_CLASS (innermode);
+      partmode = mode_for_size (inner_size * BITS_PER_UNIT, mclass, 0);
+    }
+
   final_offset = byte % inner_size;
   if (final_offset + GET_MODE_SIZE (outermode) > inner_size)
     return NULL_RTX;
 
-  return simplify_gen_subreg (outermode, part, GET_MODE (part), final_offset);
+  return simplify_gen_subreg (outermode, part, partmode, final_offset);
 }
 
 /* Wrapper around simplify_gen_subreg which handles CONCATN.  */
@@ -533,83 +552,32 @@ resolve_subreg_use (rtx *px, void *data)
   return 0;
 }
 
-/* We are deleting INSN.  Move any EH_REGION notes to INSNS.  */
+/* This is called via for_each_rtx.  Look for SUBREGs which can be
+   decomposed and decomposed REGs that need copying.  */
 
-static void
-move_eh_region_note (rtx insn, rtx insns)
+static int
+adjust_decomposed_uses (rtx *px, void *data ATTRIBUTE_UNUSED)
 {
-  rtx note, p;
-
-  note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
-  if (note == NULL_RTX)
-    return;
+  rtx x = *px;
 
-  gcc_assert (CALL_P (insn)
-             || (flag_non_call_exceptions && may_trap_p (PATTERN (insn))));
+  if (x == NULL_RTX)
+    return 0;
 
-  for (p = insns; p != NULL_RTX; p = NEXT_INSN (p))
+  if (resolve_subreg_p (x))
     {
-      if (CALL_P (p)
-         || (flag_non_call_exceptions
-             && INSN_P (p)
-             && may_trap_p (PATTERN (p))))
-       REG_NOTES (p) = gen_rtx_EXPR_LIST (REG_EH_REGION, XEXP (note, 0),
-                                          REG_NOTES (p));
-    }
-}
-
-/* If there is a REG_LIBCALL note on OLD_START, move it to NEW_START,
-   and link the corresponding REG_RETVAL note to NEW_START.  */
-
-static void
-move_libcall_note (rtx old_start, rtx new_start)
-{
-  rtx note0, note1, end;
-
-  note0 = find_reg_note (old_start, REG_LIBCALL, NULL);
-  if (note0 == NULL_RTX)
-    return;
-
-  remove_note (old_start, note0);
-  end = XEXP (note0, 0);
-  note1 = find_reg_note (end, REG_RETVAL, NULL);
-
-  XEXP (note0, 1) = REG_NOTES (new_start);
-  REG_NOTES (new_start) = note0;
-  XEXP (note1, 0) = new_start;
-}
-
-/* Remove any REG_RETVAL note, the corresponding REG_LIBCALL note, and
-   any markers for a no-conflict block.  We have decomposed the
-   registers so the non-conflict is now obvious.  */
-
-static void
-remove_retval_note (rtx insn1)
-{
-  rtx note0, insn0, note1, insn;
-
-  note1 = find_reg_note (insn1, REG_RETVAL, NULL);
-  if (note1 == NULL_RTX)
-    return;
-
-  insn0 = XEXP (note1, 0);
-  note0 = find_reg_note (insn0, REG_LIBCALL, NULL);
+      x = simplify_subreg_concatn (GET_MODE (x), SUBREG_REG (x),
+                                  SUBREG_BYTE (x));
 
-  remove_note (insn0, note0);
-  remove_note (insn1, note1);
+      if (x)
+       *px = x;
+      else
+       x = copy_rtx (*px);
+    }
 
-  for (insn = insn0; insn != insn1; insn = NEXT_INSN (insn))
-    {
-      while (1)
-       {
-         rtx note;
+  if (resolve_reg_p (x))
+    *px = copy_rtx (x);
 
-         note = find_reg_note (insn, REG_NO_CONFLICT, NULL);
-         if (note == NULL_RTX)
-           break;
-         remove_note (insn, note);
-       }
-    }
+  return 0;
 }
 
 /* Resolve any decomposed registers which appear in register notes on
@@ -625,10 +593,7 @@ resolve_reg_notes (rtx insn)
     {
       int old_count = num_validated_changes ();
       if (for_each_rtx (&XEXP (note, 0), resolve_subreg_use, NULL))
-       {
-         remove_note (insn, note);
-         remove_retval_note (insn);
-       }
+       remove_note (insn, note);
       else
        if (old_count != num_validated_changes ())
          df_notes_rescan (insn);
@@ -637,23 +602,22 @@ resolve_reg_notes (rtx insn)
   pnote = &REG_NOTES (insn);
   while (*pnote != NULL_RTX)
     {
-      bool delete = false;
+      bool del = false;
 
       note = *pnote;
       switch (REG_NOTE_KIND (note))
        {
-       case REG_NO_CONFLICT:
        case REG_DEAD:
        case REG_UNUSED:
          if (resolve_reg_p (XEXP (note, 0)))
-           delete = true;
+           del = true;
          break;
 
        default:
          break;
        }
 
-      if (delete)
+      if (del)
        *pnote = XEXP (note, 1);
       else
        pnote = &XEXP (note, 1);
@@ -673,7 +637,7 @@ can_decompose_p (rtx x)
        return (validate_subreg (word_mode, GET_MODE (x), x, UNITS_PER_WORD)
                && HARD_REGNO_MODE_OK (regno, word_mode));
       else
-       return !bitmap_bit_p (non_decomposable_context, regno);
+       return !bitmap_bit_p (subreg_context, regno);
     }
 
   return true;
@@ -850,7 +814,7 @@ resolve_simple_move (rtx set, rtx insn)
       unsigned int i;
 
       if (REG_P (dest) && !HARD_REGISTER_NUM_P (REGNO (dest)))
-       emit_insn (gen_rtx_CLOBBER (VOIDmode, dest));
+       emit_clobber (dest);
 
       for (i = 0; i < words; ++i)
        emit_move_insn (simplify_gen_subreg_concatn (word_mode, dest,
@@ -880,12 +844,10 @@ resolve_simple_move (rtx set, rtx insn)
   insns = get_insns ();
   end_sequence ();
 
-  move_eh_region_note (insn, insns);
+  copy_reg_eh_region_note_forward (insn, insns, NULL_RTX);
 
   emit_insn_before (insns, insn);
 
-  move_libcall_note (insn, insns);
-  remove_retval_note (insn);
   delete_insn (insn);
 
   return insns;
@@ -906,15 +868,6 @@ resolve_clobber (rtx pat, rtx insn)
   if (!resolve_reg_p (reg) && !resolve_subreg_p (reg))
     return false;
 
-  /* If this clobber has a REG_LIBCALL note, then it is the initial
-     clobber added by emit_no_conflict_block.  We were able to
-     decompose the register, so we no longer need the clobber.  */
-  if (find_reg_note (insn, REG_LIBCALL, NULL_RTX) != NULL_RTX)
-    {
-      delete_insn (insn);
-      return true;
-    }
-
   orig_mode = GET_MODE (reg);
   words = GET_MODE_SIZE (orig_mode);
   words = (words + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
@@ -958,6 +911,18 @@ resolve_use (rtx pat, rtx insn)
   return false;
 }
 
+/* A VAR_LOCATION can be simplified.  */
+
+static void
+resolve_debug (rtx insn)
+{
+  for_each_rtx (&PATTERN (insn), adjust_decomposed_uses, NULL_RTX);
+
+  df_insn_rescan (insn);
+
+  resolve_reg_notes (insn);
+}
+
 /* Checks if INSN is a decomposable multiword-shift or zero-extend and
    sets the decomposable_context bitmap accordingly.  A non-zero value
    is returned if a decomposable insn has been found.  */
@@ -994,7 +959,7 @@ find_decomposable_shift_zext (rtx insn)
     }
   else /* left or right shift */
     {
-      if (GET_CODE (XEXP (op, 1)) != CONST_INT
+      if (!CONST_INT_P (XEXP (op, 1))
          || INTVAL (XEXP (op, 1)) < BITS_PER_WORD
          || GET_MODE_BITSIZE (GET_MODE (op_operand)) != 2 * BITS_PER_WORD)
        return 0;
@@ -1043,11 +1008,12 @@ resolve_shift_zext (rtx insn)
      endian machines this is register 0.  */
   src_reg_num = GET_CODE (op) == LSHIFTRT ? 1 : 0;
 
-  if (WORDS_BIG_ENDIAN)
+  if (WORDS_BIG_ENDIAN
+      && GET_MODE_SIZE (GET_MODE (op_operand)) > UNITS_PER_WORD)
     src_reg_num = 1 - src_reg_num;
 
   if (GET_CODE (op) == ZERO_EXTEND)
-    dest_reg_num = src_reg_num;
+    dest_reg_num = WORDS_BIG_ENDIAN ? 1 : 0;
   else
     dest_reg_num = 1 - src_reg_num;
 
@@ -1055,13 +1021,6 @@ resolve_shift_zext (rtx insn)
   offset2 = UNITS_PER_WORD * (1 - dest_reg_num);
   src_offset = UNITS_PER_WORD * src_reg_num;
 
-  if (WORDS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
-    {
-      offset1 += UNITS_PER_WORD - 1;
-      offset2 += UNITS_PER_WORD - 1;
-      src_offset += UNITS_PER_WORD - 1;
-    }
-
   start_sequence ();
 
   dest_reg = simplify_gen_subreg_concatn (word_mode, SET_DEST (set),
@@ -1139,6 +1098,9 @@ decompose_multiword_subregs (void)
       return;
   }
 
+  if (df)
+    run_word_dce ();
+
   /* FIXME: When the dataflow branch is merged, we can change this
      code to look for each multi-word pseudo-register and to find each
      insn which sets or uses that register.  That should be faster
@@ -1146,6 +1108,7 @@ decompose_multiword_subregs (void)
 
   decomposable_context = BITMAP_ALLOC (NULL);
   non_decomposable_context = BITMAP_ALLOC (NULL);
+  subreg_context = BITMAP_ALLOC (NULL);
 
   reg_copy_graph = VEC_alloc (bitmap, heap, max);
   VEC_safe_grow (bitmap, heap, reg_copy_graph, max);
@@ -1178,34 +1141,8 @@ decompose_multiword_subregs (void)
            cmi = NOT_SIMPLE_MOVE;
          else
            {
-             bool retval;
-
-             retval = find_reg_note (insn, REG_RETVAL, NULL_RTX) != NULL_RTX;
-
-             if (find_pseudo_copy (set) && !retval)
+             if (find_pseudo_copy (set))
                cmi = SIMPLE_PSEUDO_REG_MOVE;
-             else if (retval
-                      && REG_P (SET_SRC (set))
-                      && HARD_REGISTER_P (SET_SRC (set)))
-               {
-                 rtx note;
-
-                 /* We don't want to decompose an assignment which
-                    copies the value returned by a libcall to a
-                    pseudo-register.  Doing that will lose the RETVAL
-                    note with no real gain.  */
-                 cmi = NOT_SIMPLE_MOVE;
-
-                 /* If we have a RETVAL note, there should be an
-                    EQUAL note.  We don't want to decompose any
-                    registers which that EQUAL note refers to
-                    directly.  If we do, we will no longer know the
-                    value of the libcall.  */
-                 note = find_reg_equal_equiv_note (insn);
-                 if (note != NULL_RTX)
-                   for_each_rtx (&XEXP (note, 0), find_decomposable_subregs,
-                                 &cmi);
-               }
              else
                cmi = SIMPLE_MOVE;
            }
@@ -1255,18 +1192,18 @@ decompose_multiword_subregs (void)
 
          FOR_BB_INSNS (bb, insn)
            {
-             rtx next, pat;
+             rtx pat;
 
              if (!INSN_P (insn))
                continue;
 
-             next = NEXT_INSN (insn);
-
              pat = PATTERN (insn);
              if (GET_CODE (pat) == CLOBBER)
                resolve_clobber (pat, insn);
              else if (GET_CODE (pat) == USE)
                resolve_use (pat, insn);
+             else if (DEBUG_INSN_P (insn))
+               resolve_debug (insn);
              else
                {
                  rtx set;
@@ -1293,14 +1230,12 @@ decompose_multiword_subregs (void)
                         basic block and still produce the correct control
                         flow graph for it.  */
                      gcc_assert (!cfi
-                                 || (flag_non_call_exceptions
+                                 || (cfun->can_throw_non_call_exceptions
                                      && can_throw_internal (insn)));
 
                      insn = resolve_simple_move (set, insn);
                      if (insn != orig_insn)
                        {
-                         remove_retval_note (insn);
-
                          recog_memoized (insn);
                          extract_insn (insn);
 
@@ -1336,13 +1271,11 @@ decompose_multiword_subregs (void)
                          int dup_num = recog_data.dup_num[i];
                          rtx *px = recog_data.operand_loc[dup_num];
 
-                         validate_change (insn, pl, *px, 1);
+                         validate_unshare_change (insn, pl, *px, 1);
                        }
 
                      i = apply_change_group ();
                      gcc_assert (i);
-
-                     remove_retval_note (insn);
                    }
                }
            }
@@ -1385,15 +1318,16 @@ decompose_multiword_subregs (void)
     unsigned int i;
     bitmap b;
 
-    for (i = 0; VEC_iterate (bitmap, reg_copy_graph, i, b); ++i)
+    FOR_EACH_VEC_ELT (bitmap, reg_copy_graph, i, b)
       if (b)
        BITMAP_FREE (b);
   }
 
-  VEC_free (bitmap, heap, reg_copy_graph);  
+  VEC_free (bitmap, heap, reg_copy_graph);
 
   BITMAP_FREE (decomposable_context);
   BITMAP_FREE (non_decomposable_context);
+  BITMAP_FREE (subreg_context);
 }
 \f
 /* Gate function for lower subreg pass.  */
@@ -1422,9 +1356,11 @@ rest_of_handle_lower_subreg2 (void)
   return 0;
 }
 
-struct tree_opt_pass pass_lower_subreg =
+struct rtl_opt_pass pass_lower_subreg =
 {
-  "subreg",                            /* name */
+ {
+  RTL_PASS,
+  "subreg1",                           /* name */
   gate_handle_lower_subreg,             /* gate */
   rest_of_handle_lower_subreg,          /* execute */
   NULL,                                 /* sub */
@@ -1437,12 +1373,14 @@ struct tree_opt_pass pass_lower_subreg =
   0,                                    /* todo_flags_start */
   TODO_dump_func |
   TODO_ggc_collect |
-  TODO_verify_flow,                     /* todo_flags_finish */
-  'u'                                   /* letter */
+  TODO_verify_flow                      /* todo_flags_finish */
+ }
 };
 
-struct tree_opt_pass pass_lower_subreg2 =
+struct rtl_opt_pass pass_lower_subreg2 =
 {
+ {
+  RTL_PASS,
   "subreg2",                           /* name */
   gate_handle_lower_subreg,             /* gate */
   rest_of_handle_lower_subreg2,          /* execute */
@@ -1454,9 +1392,9 @@ struct tree_opt_pass pass_lower_subreg2 =
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
-  TODO_df_finish |
+  TODO_df_finish | TODO_verify_rtl_sharing |
   TODO_dump_func |
   TODO_ggc_collect |
-  TODO_verify_flow,                     /* todo_flags_finish */
-  'U'                                   /* letter */
+  TODO_verify_flow                      /* todo_flags_finish */
+ }
 };