OSDN Git Service

(LINK_COST_ZERO, LINK_COST_FREE): New macros.
[pf3gnuchains/gcc-fork.git] / gcc / function.c
index 02ce0f9..753931d 100644 (file)
@@ -1,5 +1,5 @@
 /* Expands front end tree to back end RTL for GNU C-Compiler
-   Copyright (C) 1987, 1988, 1989, 1991 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1989, 1991, 1992 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -307,6 +307,7 @@ static void fixup_var_refs_1 ();
 static void optimize_bit_field ();
 static void instantiate_decls ();
 static void instantiate_decls_1 ();
+static void instantiate_decl ();
 static int instantiate_virtual_regs_1 ();
 static rtx fixup_memory_subreg ();
 static rtx walk_fixup_memory_subreg ();
@@ -1902,16 +1903,10 @@ instantiate_decls (fndecl, valid_only)
   /* Process all parameters of the function.  */
   for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl))
     {
-      if (DECL_RTL (decl) && GET_CODE (DECL_RTL (decl)) == MEM)
-       instantiate_virtual_regs_1 (&XEXP (DECL_RTL (decl), 0),
-                                   (valid_only ? DECL_RTL (decl) : NULL_RTX),
-                                   0);
-      if (DECL_INCOMING_RTL (decl)
-         && GET_CODE (DECL_INCOMING_RTL (decl)) == MEM)
-       instantiate_virtual_regs_1 (&XEXP (DECL_INCOMING_RTL (decl), 0),
-                                   (valid_only ? DECL_INCOMING_RTL (decl)
-                                    : NULL_RTX),
-                                   0);
+      instantiate_decl (DECL_RTL (decl), int_size_in_bytes (TREE_TYPE (decl)),
+                       valid_only);    
+      instantiate_decl (DECL_INCOMING_RTL (decl),
+                       int_size_in_bytes (TREE_TYPE (decl)), valid_only);
     }
 
   /* Now process all variables defined in the function or its subblocks. */
@@ -1938,14 +1933,77 @@ instantiate_decls_1 (let, valid_only)
   tree t;
 
   for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t))
-    if (DECL_RTL (t) && GET_CODE (DECL_RTL (t)) == MEM)
-      instantiate_virtual_regs_1 (& XEXP (DECL_RTL (t), 0),
-                                 valid_only ? DECL_RTL (t) : NULL_RTX, 0);
+    instantiate_decl (DECL_RTL (t), int_size_in_bytes (TREE_TYPE (t)),
+                     valid_only);
 
   /* Process all subblocks.  */
   for (t = BLOCK_SUBBLOCKS (let); t; t = TREE_CHAIN (t))
     instantiate_decls_1 (t, valid_only);
 }
+
+/* Subroutine of the preceeding procedures: Given RTL representing a
+   decl and the size of the object, do any instantiation required.
+
+   If VALID_ONLY is non-zero, it means that the RTL should only be
+   changed if the new address is valid.  */
+
+static void
+instantiate_decl (x, size, valid_only)
+     rtx x;
+     int size;
+     int valid_only;
+{
+  enum machine_mode mode;
+  rtx addr;
+
+  /* If this is not a MEM, no need to do anything.  Similarly if the
+     address is a constant or a register that is not a virtual register.  */
+
+  if (x == 0 || GET_CODE (x) != MEM)
+    return;
+
+  addr = XEXP (x, 0);
+  if (CONSTANT_P (addr)
+      || (GET_CODE (addr) == REG
+         && (REGNO (addr) < FIRST_VIRTUAL_REGISTER
+             || REGNO (addr) > LAST_VIRTUAL_REGISTER)))
+    return;
+
+  /* If we should only do this if the address is valid, copy the address.
+     We need to do this so we can undo any changes that might make the
+     address invalid.  This copy is unfortunate, but probably can't be
+     avoided.  */
+
+  if (valid_only)
+    addr = copy_rtx (addr);
+
+  instantiate_virtual_regs_1 (&addr, NULL_RTX, 0);
+
+  if (! valid_only)
+    return;
+
+  /* Now verify that the resulting address is valid for every integer or
+     floating-point mode up to and including SIZE bytes long.  We do this
+     since the object might be accessed in any mode and frame addresses
+     are shared.  */
+
+  for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
+       mode != VOIDmode && GET_MODE_SIZE (mode) <= size;
+       mode = GET_MODE_WIDER_MODE (mode))
+    if (! memory_address_p (mode, addr))
+      return;
+
+  for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
+       mode != VOIDmode && GET_MODE_SIZE (mode) <= size;
+       mode = GET_MODE_WIDER_MODE (mode))
+    if (! memory_address_p (mode, addr))
+      return;
+
+  /* Otherwise, put back the address, now that we have updated it and we
+     know it is valid.  */
+
+  XEXP (x, 0) = addr;
+}
 \f
 /* Given a pointer to a piece of rtx and an optional pointer to the
    containing object, instantiate any virtual registers present in it.
@@ -2550,6 +2608,14 @@ assign_parms (fndecl, second_time)
       passed_mode = TYPE_MODE (passed_type);
       nominal_mode = TYPE_MODE (TREE_TYPE (parm));
 
+      /* If the parm's mode is VOID, its value doesn't matter,
+        and avoid the usual things like emit_move_insn that could crash.  */
+      if (nominal_mode == VOIDmode)
+       {
+         DECL_INCOMING_RTL (parm) = DECL_RTL (parm) = const0_rtx;
+         continue;
+       }
+
 #ifdef FUNCTION_ARG_PASS_BY_REFERENCE
       /* See if this arg was passed by invisible reference.  */
       if (FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far, passed_mode,
@@ -2804,14 +2870,8 @@ assign_parms (fndecl, second_time)
            }
          DECL_RTL (parm) = stack_parm;
        }
-      else if (! (
-#if 0 /* This change was turned off because it makes compilation bigger.  */
-                 !optimize
-#else /* It's not clear why the following was replaced.  */
-                 /* Obsoleted by preceding line. */
-                 (obey_regdecls && ! DECL_REGISTER (parm)
+      else if (! ((obey_regdecls && ! DECL_REGISTER (parm)
                   && ! DECL_INLINE (fndecl))
-#endif
                  /* layout_decl may set this.  */
                  || TREE_ADDRESSABLE (parm)
                  || TREE_SIDE_EFFECTS (parm)
@@ -2858,6 +2918,26 @@ assign_parms (fndecl, second_time)
          else
            emit_move_insn (parmreg, validize_mem (entry_parm));
 
+         /* If we were passed a pointer but the actual value
+            can safely live in a register, put it in one.  */
+         if (passed_pointer && TYPE_MODE (TREE_TYPE (parm)) != BLKmode
+             && ! ((obey_regdecls && ! DECL_REGISTER (parm)
+                    && ! DECL_INLINE (fndecl))
+                   /* layout_decl may set this.  */
+                   || TREE_ADDRESSABLE (parm)
+                   || TREE_SIDE_EFFECTS (parm)
+                   /* If -ffloat-store specified, don't put explicit
+                      float variables into registers.  */
+                   || (flag_float_store
+                       && TREE_CODE (TREE_TYPE (parm)) == REAL_TYPE)))
+           {
+             /* We can't use nominal_mode, because it will have been set to
+                Pmode above.  We must use the actual mode of the parm.  */
+             parmreg = gen_reg_rtx (TYPE_MODE (TREE_TYPE (parm)));
+             emit_move_insn (parmreg, DECL_RTL (parm));
+             DECL_RTL (parm) = parmreg;
+           }
+
          /* In any case, record the parm's desired stack location
             in case we later discover it must live in the stack.  */
          if (REGNO (parmreg) >= nparmregs)
@@ -3526,14 +3606,21 @@ identify_blocks (top_block, insns)
      tree top_block;
      rtx insns;
 {
-  int n_blocks = all_blocks (top_block, 0);
-  tree *block_vector = (tree *) alloca (n_blocks * sizeof (tree));
-  int *block_stack = (int *) alloca (n_blocks * sizeof (int));
+  int n_blocks;
+  tree *block_vector;
+  int *block_stack;
   int depth = 0;
   int next_block_number = 0;
   int current_block_number = 0;
   rtx insn;
 
+  if (top_block == 0)
+    return 0;
+
+  n_blocks = all_blocks (top_block, 0);
+  block_vector = (tree *) xmalloc (n_blocks * sizeof (tree));
+  block_stack = (int *) alloca (n_blocks * sizeof (int));
+
   all_blocks (top_block, block_vector);
 
   for (insn = insns; insn; insn = NEXT_INSN (insn))
@@ -3543,12 +3630,12 @@ identify_blocks (top_block, insns)
          {
            block_stack[depth++] = current_block_number;
            current_block_number = next_block_number;
-           SET_NOTE_BLOCK_NUMBER (insn, next_block_number++);
+           NOTE_BLOCK_NUMBER (insn) =  next_block_number++;
          }
        if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END)
          {
            current_block_number = block_stack[--depth];
-           SET_NOTE_BLOCK_NUMBER (insn, current_block_number);
+           NOTE_BLOCK_NUMBER (insn) = current_block_number;
          }
       }
 
@@ -3558,16 +3645,24 @@ identify_blocks (top_block, insns)
 /* Given BLOCK_VECTOR which was returned by identify_blocks,
    and a revised instruction chain, rebuild the tree structure
    of BLOCK nodes to correspond to the new order of RTL.
+   The new block tree is inserted below TOP_BLOCK.
    Returns the current top-level block.  */
 
 tree
-reorder_blocks (block_vector, insns)
+reorder_blocks (block_vector, top_block, insns)
      tree *block_vector;
+     tree top_block;
      rtx insns;
 {
-  tree current_block = block_vector[0];
+  tree current_block = top_block;
   rtx insn;
 
+  if (block_vector == 0)
+    return top_block;
+
+  /* Prune the old tree away, so that it doesn't get in the way.  */
+  BLOCK_SUBBLOCKS (current_block) = 0;
+
   for (insn = insns; insn; insn = NEXT_INSN (insn))
     if (GET_CODE (insn) == NOTE)
       {
@@ -3577,21 +3672,20 @@ reorder_blocks (block_vector, insns)
            /* If we have seen this block before, copy it.  */
            if (TREE_ASM_WRITTEN (block))
              block = copy_node (block);
-           else
-             BLOCK_SUBBLOCKS (block) = 0;
+           BLOCK_SUBBLOCKS (block) = 0;
            TREE_ASM_WRITTEN (block) = 1;
            BLOCK_SUPERCONTEXT (block) = current_block; 
            BLOCK_CHAIN (block) = BLOCK_SUBBLOCKS (current_block);
            BLOCK_SUBBLOCKS (current_block) = block;
            current_block = block;
-           SET_NOTE_BLOCK_NUMBER (insn, 0);
+           NOTE_SOURCE_FILE (insn) = 0;
          }
        if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END)
          {
            BLOCK_SUBBLOCKS (current_block)
              = blocks_nreverse (BLOCK_SUBBLOCKS (current_block));
            current_block = BLOCK_SUPERCONTEXT (current_block);
-           SET_NOTE_BLOCK_NUMBER (insn, 0);
+           NOTE_SOURCE_FILE (insn) = 0;
          }
       }
 
@@ -3628,12 +3722,13 @@ all_blocks (block, vector)
 
   TREE_ASM_WRITTEN (block) = 0;
   /* Record this block.  */
-  vector[n_blocks++] = block;
+  if (vector)
+    vector[0] = block;
 
   /* Record the subblocks, and their subblocks.  */
   for (subblocks = BLOCK_SUBBLOCKS (block);
        subblocks; subblocks = BLOCK_CHAIN (subblocks))
-    n_blocks += all_blocks (subblocks, vector + n_blocks);
+    n_blocks += all_blocks (subblocks, vector ? vector + n_blocks : 0);
 
   return n_blocks;
 }
@@ -4237,9 +4332,9 @@ record_insns (insns)
   return vec;
 }
 
-/* Determine whether INSN is in the array of INSN_UIDs VEC.  */
+/* Determine how many INSN_UIDs in VEC are part of INSN.  */
 
-static rtx
+static int
 contains (insn, vec)
      rtx insn;
      int *vec;
@@ -4249,16 +4344,18 @@ contains (insn, vec)
   if (GET_CODE (insn) == INSN
       && GET_CODE (PATTERN (insn)) == SEQUENCE)
     {
+      int count = 0;
       for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
        for (j = 0; vec[j]; j++)
          if (INSN_UID (XVECEXP (PATTERN (insn), 0, i)) == vec[j])
-           return XVECEXP (PATTERN (insn), 0, i);
+           count++;
+      return count;
     }
   else
     {
       for (j = 0; vec[j]; j++)
        if (INSN_UID (insn) == vec[j])
-         return insn;
+         return 1;
     }
   return 0;
 }
@@ -4353,58 +4450,74 @@ reposition_prologue_and_epilogue_notes (f)
   if (n_basic_blocks)
     {
       rtx next, prev;
+      int len;
 
       if (prologue)
        {
-         register rtx insn, end_prologue;
-
-         /* From the end of the first basic block, search backward for a
-            prologue insn.  */
-         for (insn = NEXT_INSN (PREV_INSN (basic_block_end[0]));
-              insn; insn = prev_nonnote_insn (insn))
-           if (contains (insn, prologue))
+         register rtx insn, note = 0;
+
+         /* Scan from the beginning until we reach the last prologue insn.
+            We apparently can't depend on basic_block_{head,end} after
+            reorg has run.  */
+         for (len = 0; prologue[len]; len++)
+           ;
+         for (insn = f; insn; insn = NEXT_INSN (insn))
+           if (GET_CODE (insn) == NOTE)
+             {
+               if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_PROLOGUE_END)
+                 note = insn;
+             }
+           else if ((len -= contains (insn, prologue)) == 0)
              {
-               end_prologue = insn;
-               /* Find the prologue-end note and move it to just after the
-                  last prologue insn.  */
-               for (insn = f; insn; insn = NEXT_INSN (insn))
-                 if (GET_CODE (insn) == NOTE
-                     && NOTE_LINE_NUMBER (insn) == NOTE_INSN_PROLOGUE_END)
-                   break;
-               next = NEXT_INSN (insn);
-               prev = PREV_INSN (insn);
+               /* Find the prologue-end note if we haven't already, and
+                  move it to just after the last prologue insn.  */
+               if (note == 0)
+                 for (note = insn; note = NEXT_INSN (note);)
+                   if (GET_CODE (note) == NOTE
+                       && NOTE_LINE_NUMBER (note) == NOTE_INSN_PROLOGUE_END)
+                     break;
+               next = NEXT_INSN (note);
+               prev = PREV_INSN (note);
                if (prev)
                  NEXT_INSN (prev) = next;
                if (next)
                  PREV_INSN (next) = prev;
-               add_insn_after (insn, end_prologue);
+               add_insn_after (note, insn);
                break;
              }
        }
 
       if (epilogue)
        {
-         register rtx insn, beg_epilogue;
-
-         /* From the start of the last basic block, search forward for an
-            epilogue insn.  */
-         for (insn = PREV_INSN (NEXT_INSN (basic_block_head[n_basic_blocks - 1]));
-              insn; insn = next_nonnote_insn (insn))
-           if (beg_epilogue = contains (insn, epilogue))
+         register rtx insn, note = 0;
+
+         /* Scan from the end until we reach the first epilogue insn.
+            We apparently can't depend on basic_block_{head,end} after
+            reorg has run.  */
+         for (len = 0; epilogue[len]; len++)
+           ;
+         for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
+           if (GET_CODE (insn) == NOTE)
+             {
+               if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EPILOGUE_BEG)
+                 note = insn;
+             }
+           else if ((len -= contains (insn, epilogue)) == 0)
              {
-               /* Find the epilogue-begin note and move it to just before
-                  the first epilogue insn.  */
-               for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
-                 if (GET_CODE (insn) == NOTE
-                     && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EPILOGUE_BEG)
-                   break;
-               next = NEXT_INSN (insn);
-               prev = PREV_INSN (insn);
+               /* Find the epilogue-begin note if we haven't already, and
+                  move it to just before the first epilogue insn.  */
+               if (note == 0)
+                 for (note = insn; note = PREV_INSN (note);)
+                   if (GET_CODE (note) == NOTE
+                       && NOTE_LINE_NUMBER (note) == NOTE_INSN_EPILOGUE_BEG)
+                     break;
+               next = NEXT_INSN (note);
+               prev = PREV_INSN (note);
                if (prev)
                  NEXT_INSN (prev) = next;
                if (next)
                  PREV_INSN (next) = prev;
-               add_insn_after (insn, PREV_INSN (beg_epilogue));
+               add_insn_after (note, PREV_INSN (insn));
                break;
              }
        }