OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / function.c
index 506ec03..96879c8 100644 (file)
@@ -1,7 +1,7 @@
 /* Expands front end tree to back end RTL for GCC.
    Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
    1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
-   2010, 2011  Free Software Foundation, Inc.
+   2010, 2011, 2012  Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -939,14 +939,7 @@ assign_stack_temp_for_type (enum machine_mode mode, HOST_WIDE_INT size,
 
   /* If a type is specified, set the relevant flags.  */
   if (type != 0)
-    {
-      MEM_VOLATILE_P (slot) = TYPE_VOLATILE (type);
-      gcc_checking_assert (!MEM_SCALAR_P (slot) && !MEM_IN_STRUCT_P (slot));
-      if (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == COMPLEX_TYPE)
-       MEM_IN_STRUCT_P (slot) = 1;
-      else
-       MEM_SCALAR_P (slot) = 1;
-    }
+    MEM_VOLATILE_P (slot) = TYPE_VOLATILE (type);
   MEM_NOTRAP_P (slot) = 1;
 
   return slot;
@@ -1737,7 +1730,7 @@ instantiate_virtual_regs_in_insn (rtx insn)
       if (!check_asm_operands (PATTERN (insn)))
        {
          error_for_asm (insn, "impossible constraint in %<asm%>");
-         delete_insn (insn);
+         delete_insn_and_edges (insn);
        }
     }
   else
@@ -2982,11 +2975,26 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
          && insn_operand_matches (icode, 1, op1))
        {
          enum rtx_code code = unsignedp ? ZERO_EXTEND : SIGN_EXTEND;
-         rtx insn, insns;
+         rtx insn, insns, t = op1;
          HARD_REG_SET hardregs;
 
          start_sequence ();
-         insn = gen_extend_insn (op0, op1, promoted_nominal_mode,
+         /* If op1 is a hard register that is likely spilled, first
+            force it into a pseudo, otherwise combiner might extend
+            its lifetime too much.  */
+         if (GET_CODE (t) == SUBREG)
+           t = SUBREG_REG (t);
+         if (REG_P (t)
+             && HARD_REGISTER_P (t)
+             && ! TEST_HARD_REG_BIT (fixed_reg_set, REGNO (t))
+             && targetm.class_likely_spilled_p (REGNO_REG_CLASS (REGNO (t))))
+           {
+             t = gen_reg_rtx (GET_MODE (op1));
+             emit_move_insn (t, op1);
+           }
+         else
+           t = op1;
+         insn = gen_extend_insn (op0, t, promoted_nominal_mode,
                                  data->passed_mode, unsignedp);
          emit_insn (insn);
          insns = get_insns ();
@@ -5294,6 +5302,10 @@ requires_stack_frame_p (rtx insn, HARD_REG_SET prologue_used,
   if (CALL_P (insn))
     return !SIBLING_CALL_P (insn);
 
+  /* We need a frame to get the unique CFA expected by the unwinder.  */
+  if (cfun->can_throw_non_call_exceptions && can_throw_internal (insn))
+    return true;
+
   CLEAR_HARD_REG_SET (hardregs);
   for (df_rec = DF_INSN_DEFS (insn); *df_rec; df_rec++)
     {
@@ -5329,126 +5341,182 @@ requires_stack_frame_p (rtx insn, HARD_REG_SET prologue_used,
   return false;
 }
 
-/* Look for sets of call-saved registers in the first block of the
-   function, and move them down into successor blocks if the register
-   is used only on one path.  This exposes more opportunities for
-   shrink-wrapping.
-   These kinds of sets often occur when incoming argument registers are
-   moved to call-saved registers because their values are live across
-   one or more calls during the function.  */
+/* See whether BB has a single successor that uses [REGNO, END_REGNO),
+   and if BB is its only predecessor.  Return that block if so,
+   otherwise return null.  */
 
-static void
-prepare_shrink_wrap (basic_block entry_block)
+static basic_block
+next_block_for_reg (basic_block bb, int regno, int end_regno)
 {
-  rtx insn, curr;
-  FOR_BB_INSNS_SAFE (entry_block, insn, curr)
+  edge e, live_edge;
+  edge_iterator ei;
+  bitmap live;
+  int i;
+
+  live_edge = NULL;
+  FOR_EACH_EDGE (e, ei, bb->succs)
     {
-      basic_block next_bb;
-      edge e, live_edge;
-      edge_iterator ei;
-      rtx set, scan;
-      unsigned destreg, srcreg;
+      live = df_get_live_in (e->dest);
+      for (i = regno; i < end_regno; i++)
+       if (REGNO_REG_SET_P (live, i))
+         {
+           if (live_edge && live_edge != e)
+             return NULL;
+           live_edge = e;
+         }
+    }
 
-      if (!NONDEBUG_INSN_P (insn))
-       continue;
-      set = single_set (insn);
-      if (!set)
-       continue;
+  /* We can sometimes encounter dead code.  Don't try to move it
+     into the exit block.  */
+  if (!live_edge || live_edge->dest == EXIT_BLOCK_PTR)
+    return NULL;
 
-      if (!REG_P (SET_SRC (set)) || !REG_P (SET_DEST (set)))
-       continue;
-      srcreg = REGNO (SET_SRC (set));
-      destreg = REGNO (SET_DEST (set));
-      if (hard_regno_nregs[srcreg][GET_MODE (SET_SRC (set))] > 1
-         || hard_regno_nregs[destreg][GET_MODE (SET_DEST (set))] > 1)
-       continue;
+  /* Reject targets of abnormal edges.  This is needed for correctness
+     on ports like Alpha and MIPS, whose pic_offset_table_rtx can die on
+     exception edges even though it is generally treated as call-saved
+     for the majority of the compilation.  Moving across abnormal edges
+     isn't going to be interesting for shrink-wrap usage anyway.  */
+  if (live_edge->flags & EDGE_ABNORMAL)
+    return NULL;
+
+  if (EDGE_COUNT (live_edge->dest->preds) > 1)
+    return NULL;
 
-      next_bb = entry_block;
-      scan = insn;
+  return live_edge->dest;
+}
+
+/* Try to move INSN from BB to a successor.  Return true on success.
+   USES and DEFS are the set of registers that are used and defined
+   after INSN in BB.  */
 
-      for (;;)
+static bool
+move_insn_for_shrink_wrap (basic_block bb, rtx insn,
+                          const HARD_REG_SET uses,
+                          const HARD_REG_SET defs)
+{
+  rtx set, src, dest;
+  bitmap live_out, live_in, bb_uses, bb_defs;
+  unsigned int i, dregno, end_dregno, sregno, end_sregno;
+  basic_block next_block;
+
+  /* Look for a simple register copy.  */
+  set = single_set (insn);
+  if (!set)
+    return false;
+  src = SET_SRC (set);
+  dest = SET_DEST (set);
+  if (!REG_P (dest) || !REG_P (src))
+    return false;
+
+  /* Make sure that the source register isn't defined later in BB.  */
+  sregno = REGNO (src);
+  end_sregno = END_REGNO (src);
+  if (overlaps_hard_reg_set_p (defs, GET_MODE (src), sregno))
+    return false;
+
+  /* Make sure that the destination register isn't referenced later in BB.  */
+  dregno = REGNO (dest);
+  end_dregno = END_REGNO (dest);
+  if (overlaps_hard_reg_set_p (uses, GET_MODE (dest), dregno)
+      || overlaps_hard_reg_set_p (defs, GET_MODE (dest), dregno))
+    return false;
+
+  /* See whether there is a successor block to which we could move INSN.  */
+  next_block = next_block_for_reg (bb, dregno, end_dregno);
+  if (!next_block)
+    return false;
+
+  /* At this point we are committed to moving INSN, but let's try to
+     move it as far as we can.  */
+  do
+    {
+      live_out = df_get_live_out (bb);
+      live_in = df_get_live_in (next_block);
+      bb = next_block;
+
+      /* Check whether BB uses DEST or clobbers DEST.  We need to add
+        INSN to BB if so.  Either way, DEST is no longer live on entry,
+        except for any part that overlaps SRC (next loop).  */
+      bb_uses = &DF_LR_BB_INFO (bb)->use;
+      bb_defs = &DF_LR_BB_INFO (bb)->def;
+      for (i = dregno; i < end_dregno; i++)
        {
-         live_edge = NULL;
-         /* Try to find a single edge across which the register is live.
-            If we find one, we'll try to move the set across this edge.  */
-         FOR_EACH_EDGE (e, ei, next_bb->succs)
-           {
-             if (REGNO_REG_SET_P (df_get_live_in (e->dest), destreg))
-               {
-                 if (live_edge)
-                   {
-                     live_edge = NULL;
-                     break;
-                   }
-                 live_edge = e;
-               }
-           }
-         if (!live_edge)
-           break;
-         /* We can sometimes encounter dead code.  Don't try to move it
-            into the exit block.  */
-         if (live_edge->dest == EXIT_BLOCK_PTR)
-           break;
-         if (EDGE_COUNT (live_edge->dest->preds) > 1)
-           break;
-         while (scan != BB_END (next_bb))
-           {
-             scan = NEXT_INSN (scan);
-             if (NONDEBUG_INSN_P (scan))
-               {
-                 rtx link;
-                 HARD_REG_SET set_regs;
-
-                 CLEAR_HARD_REG_SET (set_regs);
-                 note_stores (PATTERN (scan), record_hard_reg_sets,
-                              &set_regs);
-                 if (CALL_P (scan))
-                   IOR_HARD_REG_SET (set_regs, call_used_reg_set);
-                 for (link = REG_NOTES (scan); link; link = XEXP (link, 1))
-                   if (REG_NOTE_KIND (link) == REG_INC)
-                     record_hard_reg_sets (XEXP (link, 0), NULL, &set_regs);
-
-                 if (TEST_HARD_REG_BIT (set_regs, srcreg)
-                     || reg_referenced_p (SET_DEST (set),
-                                          PATTERN (scan)))
-                   {
-                     scan = NULL_RTX;
-                     break;
-                   }
-                 if (CALL_P (scan))
-                   {
-                     rtx link = CALL_INSN_FUNCTION_USAGE (scan);
-                     while (link)
-                       {
-                         rtx tmp = XEXP (link, 0);
-                         if (GET_CODE (tmp) == USE
-                             && reg_referenced_p (SET_DEST (set), tmp))
-                           break;
-                         link = XEXP (link, 1);
-                       }
-                     if (link)
-                       {
-                         scan = NULL_RTX;
-                         break;
-                       }
-                   }
-               }
-           }
-         if (!scan)
-           break;
-         next_bb = live_edge->dest;
+         if (REGNO_REG_SET_P (bb_uses, i) || REGNO_REG_SET_P (bb_defs, i))
+           next_block = NULL;
+         CLEAR_REGNO_REG_SET (live_out, i);
+         CLEAR_REGNO_REG_SET (live_in, i);
        }
 
-      if (next_bb != entry_block)
+      /* Check whether BB clobbers SRC.  We need to add INSN to BB if so.
+        Either way, SRC is now live on entry.  */
+      for (i = sregno; i < end_sregno; i++)
        {
-         rtx after = BB_HEAD (next_bb);
-         while (!NOTE_P (after)
-                || NOTE_KIND (after) != NOTE_INSN_BASIC_BLOCK)
-           after = NEXT_INSN (after);
-         emit_insn_after (PATTERN (insn), after);
-         delete_insn (insn);
+         if (REGNO_REG_SET_P (bb_defs, i))
+           next_block = NULL;
+         SET_REGNO_REG_SET (live_out, i);
+         SET_REGNO_REG_SET (live_in, i);
        }
+
+      /* If we don't need to add the move to BB, look for a single
+        successor block.  */
+      if (next_block)
+       next_block = next_block_for_reg (next_block, dregno, end_dregno);
     }
+  while (next_block);
+
+  /* BB now defines DEST.  It only uses the parts of DEST that overlap SRC
+     (next loop).  */
+  for (i = dregno; i < end_dregno; i++)
+    {
+      CLEAR_REGNO_REG_SET (bb_uses, i);
+      SET_REGNO_REG_SET (bb_defs, i);
+    }
+
+  /* BB now uses SRC.  */
+  for (i = sregno; i < end_sregno; i++)
+    SET_REGNO_REG_SET (bb_uses, i);
+
+  emit_insn_after (PATTERN (insn), bb_note (bb));
+  delete_insn (insn);
+  return true;
+}
+
+/* Look for register copies in the first block of the function, and move
+   them down into successor blocks if the register is used only on one
+   path.  This exposes more opportunities for shrink-wrapping.  These
+   kinds of sets often occur when incoming argument registers are moved
+   to call-saved registers because their values are live across one or
+   more calls during the function.  */
+
+static void
+prepare_shrink_wrap (basic_block entry_block)
+{
+  rtx insn, curr, x;
+  HARD_REG_SET uses, defs;
+  df_ref *ref;
+
+  CLEAR_HARD_REG_SET (uses);
+  CLEAR_HARD_REG_SET (defs);
+  FOR_BB_INSNS_REVERSE_SAFE (entry_block, insn, curr)
+    if (NONDEBUG_INSN_P (insn)
+       && !move_insn_for_shrink_wrap (entry_block, insn, uses, defs))
+      {
+       /* Add all defined registers to DEFs.  */
+       for (ref = DF_INSN_DEFS (insn); *ref; ref++)
+         {
+           x = DF_REF_REG (*ref);
+           if (REG_P (x) && HARD_REGISTER_P (x))
+             SET_HARD_REG_BIT (defs, REGNO (x));
+         }
+
+       /* Add all used registers to USESs.  */
+       for (ref = DF_INSN_USES (insn); *ref; ref++)
+         {
+           x = DF_REF_REG (*ref);
+           if (REG_P (x) && HARD_REGISTER_P (x))
+             SET_HARD_REG_BIT (uses, REGNO (x));
+         }
+      }
 }
 
 #endif
@@ -5843,7 +5911,7 @@ thread_prologue_and_epilogue_insns (void)
       && nonempty_prologue && !crtl->calls_eh_return)
     {
       HARD_REG_SET prologue_clobbered, prologue_used, live_on_edge;
-      HARD_REG_SET set_up_by_prologue;
+      struct hard_reg_set_container set_up_by_prologue;
       rtx p_insn;
       VEC(basic_block, heap) *vec;
       basic_block bb;
@@ -5883,18 +5951,22 @@ thread_prologue_and_epilogue_insns (void)
 
       vec = VEC_alloc (basic_block, heap, n_basic_blocks);
 
-      CLEAR_HARD_REG_SET (set_up_by_prologue);
-      add_to_hard_reg_set (&set_up_by_prologue, Pmode, STACK_POINTER_REGNUM);
-      add_to_hard_reg_set (&set_up_by_prologue, Pmode, ARG_POINTER_REGNUM);
+      CLEAR_HARD_REG_SET (set_up_by_prologue.set);
+      add_to_hard_reg_set (&set_up_by_prologue.set, Pmode,
+                          STACK_POINTER_REGNUM);
+      add_to_hard_reg_set (&set_up_by_prologue.set, Pmode, ARG_POINTER_REGNUM);
       if (frame_pointer_needed)
-       add_to_hard_reg_set (&set_up_by_prologue, Pmode,
+       add_to_hard_reg_set (&set_up_by_prologue.set, Pmode,
                             HARD_FRAME_POINTER_REGNUM);
       if (pic_offset_table_rtx)
-       add_to_hard_reg_set (&set_up_by_prologue, Pmode,
+       add_to_hard_reg_set (&set_up_by_prologue.set, Pmode,
                             PIC_OFFSET_TABLE_REGNUM);
-      if (stack_realign_drap && crtl->drap_reg)
-       add_to_hard_reg_set (&set_up_by_prologue, GET_MODE (crtl->drap_reg),
+      if (crtl->drap_reg)
+       add_to_hard_reg_set (&set_up_by_prologue.set,
+                            GET_MODE (crtl->drap_reg),
                             REGNO (crtl->drap_reg));
+      if (targetm.set_up_by_prologue)
+       targetm.set_up_by_prologue (&set_up_by_prologue);
 
       /* We don't use a different max size depending on
         optimize_bb_for_speed_p because increasing shrink-wrapping
@@ -5912,7 +5984,7 @@ thread_prologue_and_epilogue_insns (void)
            if (NONDEBUG_INSN_P (insn))
              {
                if (requires_stack_frame_p (insn, prologue_used,
-                                           set_up_by_prologue))
+                                           set_up_by_prologue.set))
                  {
                    if (bb == entry_edge->dest)
                      goto fail_shrinkwrap;