OSDN Git Service

CLIX patch from Thomas Dickey via urs@akk.uni-karlsruhe.de (Urs Janssen).
[pf3gnuchains/gcc-fork.git] / gcc / function.c
index b34f48d..750f333 100644 (file)
@@ -1,5 +1,5 @@
 /* Expands front end tree to back end RTL for GNU C-Compiler
-   Copyright (C) 1987, 88, 89, 91-95, 1996 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 89, 91-96, 1997 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -58,6 +58,10 @@ Boston, MA 02111-1307, USA.  */
 #include "bytecode.h"
 #include "bc-emit.h"
 
+#ifndef TRAMPOLINE_ALIGNMENT
+#define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY
+#endif
+
 /* Some systems use __main in a way incompatible with its use in gcc, in these
    cases use the macros NAME__MAIN to give a quoted symbol and SYMBOL__MAIN to
    give the same symbol without quotes for an alternative entry point.  You
@@ -128,6 +132,11 @@ int current_function_has_nonlocal_goto;
 
 int current_function_contains_functions;
 
+/* Nonzero if the current function is a thunk (a lightweight function that
+   just adjusts one of its arguments and forwards to another function), so
+   we should try to cut corners where we can.  */
+int current_function_is_thunk;
+
 /* Nonzero if function being compiled can call alloca,
    either as a subroutine or builtin.  */
 
@@ -263,7 +272,7 @@ rtx arg_pointer_save_area;
 /* Offset to end of allocated area of stack frame.
    If stack grows down, this is the address of the last stack slot allocated.
    If stack grows up, this is the address for the next slot.  */
-int frame_offset;
+HOST_WIDE_INT frame_offset;
 
 /* List (chain of TREE_LISTs) of static chains for containing functions.
    Each link has a FUNCTION_DECL in the TREE_PURPOSE and a reg rtx
@@ -485,6 +494,7 @@ push_function_context_to (context)
   p->has_nonlocal_label = current_function_has_nonlocal_label;
   p->has_nonlocal_goto = current_function_has_nonlocal_goto;
   p->contains_functions = current_function_contains_functions;
+  p->is_thunk = current_function_is_thunk;
   p->args_size = current_function_args_size;
   p->pretend_args_size = current_function_pretend_args_size;
   p->arg_offset_rtx = current_function_arg_offset_rtx;
@@ -518,6 +528,7 @@ push_function_context_to (context)
   p->temp_slot_level = temp_slot_level;
   p->fixup_var_refs_queue = 0;
   p->epilogue_delay_list = current_function_epilogue_delay_list;
+  p->args_info = current_function_args_info;
 
   save_tree_status (p, context);
   save_storage_status (p);
@@ -563,6 +574,7 @@ pop_function_context_from (context)
   current_function_calls_alloca = p->calls_alloca;
   current_function_has_nonlocal_label = p->has_nonlocal_label;
   current_function_has_nonlocal_goto = p->has_nonlocal_goto;
+  current_function_is_thunk = p->is_thunk;
   current_function_args_size = p->args_size;
   current_function_pretend_args_size = p->pretend_args_size;
   current_function_arg_offset_rtx = p->arg_offset_rtx;
@@ -596,6 +608,7 @@ pop_function_context_from (context)
   temp_slot_level = p->temp_slot_level;
   current_function_epilogue_delay_list = p->epilogue_delay_list;
   reg_renumber = 0;
+  current_function_args_info = p->args_info;
 
   restore_tree_status (p);
   restore_storage_status (p);
@@ -633,7 +646,7 @@ void pop_function_context ()
    This size counts from zero.  It is not rounded to STACK_BOUNDARY;
    the caller may have to do that.  */
 
-int
+HOST_WIDE_INT
 get_frame_size ()
 {
 #ifdef FRAME_GROWS_DOWNWARD
@@ -907,6 +920,11 @@ assign_stack_temp (mode, size, keep)
       p->level = temp_slot_level;
       p->keep = keep;
     }
+
+  /* We may be reusing an old slot, so clear any MEM flags that may have been
+     set from before.  */
+  RTX_UNCHANGING_P (p->slot) = 0;
+  MEM_IN_STRUCT_P (p->slot) = 0;
   return p->slot;
 }
 \f
@@ -1237,7 +1255,7 @@ mark_all_temps_used ()
 
   for (p = temp_slots; p; p = p->next)
     {
-      p->in_use = 1;
+      p->in_use = p->keep = 1;
       p->level = MIN (p->level, temp_slot_level);
     }
 }
@@ -1578,27 +1596,30 @@ fixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel)
                 of the CALL_INSN and see if the next insn uses both that
                 and VAR.  */
 
-             if (call_dest != 0 && GET_CODE (insn) == INSN
-                 && reg_mentioned_p (var, PATTERN (insn))
-                 && reg_mentioned_p (call_dest, PATTERN (insn)))
+             if (SMALL_REGISTER_CLASSES)
                {
-                 rtx temp = gen_reg_rtx (GET_MODE (call_dest));
+                 if (call_dest != 0 && GET_CODE (insn) == INSN
+                     && reg_mentioned_p (var, PATTERN (insn))
+                     && reg_mentioned_p (call_dest, PATTERN (insn)))
+                   {
+                     rtx temp = gen_reg_rtx (GET_MODE (call_dest));
 
-                 emit_insn_before (gen_move_insn (temp, call_dest), insn);
+                     emit_insn_before (gen_move_insn (temp, call_dest), insn);
 
-                 PATTERN (insn) = replace_rtx (PATTERN (insn),
-                                               call_dest, temp);
-               }
+                     PATTERN (insn) = replace_rtx (PATTERN (insn),
+                                                   call_dest, temp);
+                   }
              
-             if (GET_CODE (insn) == CALL_INSN
-                 && GET_CODE (PATTERN (insn)) == SET)
-               call_dest = SET_DEST (PATTERN (insn));
-             else if (GET_CODE (insn) == CALL_INSN
-                      && GET_CODE (PATTERN (insn)) == PARALLEL
-                      && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET)
-               call_dest = SET_DEST (XVECEXP (PATTERN (insn), 0, 0));
-             else
-               call_dest = 0;
+                 if (GET_CODE (insn) == CALL_INSN
+                     && GET_CODE (PATTERN (insn)) == SET)
+                   call_dest = SET_DEST (PATTERN (insn));
+                 else if (GET_CODE (insn) == CALL_INSN
+                          && GET_CODE (PATTERN (insn)) == PARALLEL
+                          && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET)
+                   call_dest = SET_DEST (XVECEXP (PATTERN (insn), 0, 0));
+                 else
+                   call_dest = 0;
+               }
 #endif
 
              /* See if we have to do anything to INSN now that VAR is in
@@ -1778,8 +1799,8 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
                    replacement->new = gen_reg_rtx (GET_MODE (var));
                  SUBREG_REG (tem) = replacement->new;
                }
-
-             tem = fixup_memory_subreg (tem, insn, 0);
+             else
+               tem = fixup_memory_subreg (tem, insn, 0);
            }
          else
            tem = fixup_stack_1 (tem, insn);
@@ -2608,10 +2629,14 @@ instantiate_decls (fndecl, valid_only)
   /* Process all parameters of the function.  */
   for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl))
     {
-      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);
+      int size = int_size_in_bytes (TREE_TYPE (decl));
+      instantiate_decl (DECL_RTL (decl), size, valid_only);    
+
+      /* If the parameter was promoted, then the incoming RTL mode may be
+        larger than the declared type size.  We must use the larger of
+        the two sizes.  */
+      size = MAX (GET_MODE_SIZE (GET_MODE (DECL_INCOMING_RTL (decl))), size);
+      instantiate_decl (DECL_INCOMING_RTL (decl), size, valid_only);
     }
 
   /* Now process all variables defined in the function or its subblocks.  */
@@ -2937,7 +2962,7 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
 
     case MEM:
       /* Most cases of MEM that convert to valid addresses have already been
-        handled by our scan of regno_reg_rtx.  The only special handling we
+        handled by our scan of decls.  The only special handling we
         need here is to make a copy of the rtx to ensure it isn't being
         shared if we have to change it to a pseudo. 
 
@@ -2995,7 +3020,9 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
             ??? Also note that this can still lose if OBJECT is an insn that
             has less restrictions on an address that some other insn.
             In that case, we will modify the shared address.  This case
-            doesn't seem very likely, though.  */
+            doesn't seem very likely, though.  One case where this could
+            happen is in the case of a USE or CLOBBER reference, but we
+            take care of that below.  */
 
          if (instantiate_virtual_regs_1 (&XEXP (x, 0),
                                          object ? object : x, 0))
@@ -3008,8 +3035,6 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
        }
 
       /* Fall through to generic unary operation case.  */
-    case USE:
-    case CLOBBER:
     case SUBREG:
     case STRICT_LOW_PART:
     case NEG:          case NOT:
@@ -3026,6 +3051,23 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
       loc = &XEXP (x, 0);
       goto restart;
 
+    case USE:
+    case CLOBBER:
+      /* If the operand is a MEM, see if the change is a valid MEM.  If not,
+        go ahead and make the invalid one, but do it to a copy.  For a REG,
+        just make the recursive call, since there's no chance of a problem. */
+
+      if ((GET_CODE (XEXP (x, 0)) == MEM
+          && instantiate_virtual_regs_1 (&XEXP (XEXP (x, 0), 0), XEXP (x, 0),
+                                         0))
+         || (GET_CODE (XEXP (x, 0)) == REG
+             && instantiate_virtual_regs_1 (&XEXP (x, 0), object, 0)))
+       return 1;
+
+      XEXP (x, 0) = copy_rtx (XEXP (x, 0));
+      loc = &XEXP (x, 0);
+      goto restart;
+
     case REG:
       /* Try to replace with a PLUS.  If that doesn't work, compute the sum
         in front of this insn and substitute the temporary.  */
@@ -3751,7 +3793,7 @@ assign_parms (fndecl, second_time)
            = promote_mode (TREE_TYPE (parm), nominal_mode, &unsignedp, 0);
 
          parmreg = gen_reg_rtx (promoted_nominal_mode);
-         REG_USERVAR_P (parmreg) = 1;
+         mark_user_reg (parmreg);
 
          /* If this was an item that we received a pointer to, set DECL_RTL
             appropriately.  */
@@ -3819,7 +3861,7 @@ assign_parms (fndecl, second_time)
              /* 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)));
-             REG_USERVAR_P (parmreg) = 1;
+             mark_user_reg (parmreg);
              emit_move_insn (parmreg, DECL_RTL (parm));
              DECL_RTL (parm) = parmreg;
              /* STACK_PARM is the pointer, not the parm, and PARMREG is
@@ -3926,11 +3968,11 @@ assign_parms (fndecl, second_time)
             as we make here would screw up life analysis for it.  */
          if (nominal_mode == passed_mode
              && ! did_conversion
-             && GET_CODE (entry_parm) == MEM
-             && entry_parm == stack_parm
+             && stack_parm != 0
+             && GET_CODE (stack_parm) == MEM
              && stack_offset.var == 0
              && reg_mentioned_p (virtual_incoming_args_rtx,
-                                 XEXP (entry_parm, 0)))
+                                 XEXP (stack_parm, 0)))
            {
              rtx linsn = get_last_insn ();
              rtx sinsn, set;
@@ -3960,7 +4002,7 @@ assign_parms (fndecl, second_time)
                       && SET_DEST (set) == parmreg)
                REG_NOTES (linsn)
                  = gen_rtx (EXPR_LIST, REG_EQUIV,
-                            entry_parm, REG_NOTES (linsn));
+                            stack_parm, REG_NOTES (linsn));
            }
 
          /* For pointer data type, suggest pointer register.  */
@@ -4871,8 +4913,6 @@ init_function_start (subr, filename, line)
      char *filename;
      int line;
 {
-  char *junk;
-
   if (output_bytecode)
     {
       this_function_decl = subr;
@@ -4920,7 +4960,7 @@ init_function_start (subr, filename, line)
 
   init_const_rtx_hash_table ();
 
-  current_function_name = (*decl_printable_name) (subr, &junk);
+  current_function_name = (*decl_printable_name) (subr, 2);
 
   /* Nonzero if this is a nested function that uses a static chain.  */
 
@@ -4938,6 +4978,7 @@ init_function_start (subr, filename, line)
   current_function_has_nonlocal_label = 0;
   current_function_has_nonlocal_goto = 0;
   current_function_contains_functions = 0;
+  current_function_is_thunk = 0;
 
   current_function_returns_pcc_struct = 0;
   current_function_returns_struct = 0;
@@ -5163,7 +5204,8 @@ expand_function_start (subr, parms_have_cleanups)
 #ifdef SMALL_REGISTER_CLASSES
       /* Delay copying static chain if it is not a register to avoid
         conflicts with regs used for parameters.  */
-      if (GET_CODE (static_chain_incoming_rtx) == REG)
+      if (! SMALL_REGISTER_CLASSES
+         || GET_CODE (static_chain_incoming_rtx) == REG)
 #endif
         emit_move_insn (last_ptr, static_chain_incoming_rtx);
     }
@@ -5277,7 +5319,7 @@ expand_function_start (subr, parms_have_cleanups)
   /* Copy the static chain now if it wasn't a register.  The delay is to
      avoid conflicts with the parameter passing registers.  */
 
-  if (current_function_needs_context)
+  if (SMALL_REGISTER_CLASSES && current_function_needs_context)
       if (GET_CODE (static_chain_incoming_rtx) != REG)
         emit_move_insn (last_ptr, static_chain_incoming_rtx);
 #endif
@@ -5319,7 +5361,8 @@ expand_function_start (subr, parms_have_cleanups)
          /* If the static chain originally came in a register, put it back
             there, then move it out in the next insn.  The reason for
             this peculiar code is to satisfy function integration.  */
-         if (GET_CODE (static_chain_incoming_rtx) == REG)
+         if (SMALL_REGISTER_CLASSES
+             && GET_CODE (static_chain_incoming_rtx) == REG)
            emit_move_insn (static_chain_incoming_rtx, last_ptr);
 #endif
 
@@ -5358,7 +5401,12 @@ expand_function_start (subr, parms_have_cleanups)
 
   /* Evaluate now the sizes of any types declared among the arguments.  */
   for (tem = nreverse (get_pending_sizes ()); tem; tem = TREE_CHAIN (tem))
-    expand_expr (TREE_VALUE (tem), const0_rtx, VOIDmode, 0);
+    {
+      expand_expr (TREE_VALUE (tem), const0_rtx, VOIDmode, 0);
+      /* Flush the queue in case this parameter declaration has
+        side-effects.  */
+      emit_queue ();
+    }
 
   /* Make sure there is a line number after the function entry setup code.  */
   force_next_line_note ();
@@ -5436,7 +5484,7 @@ expand_function_end (filename, line, end_bindings)
       blktramp = change_address (initial_trampoline, BLKmode, tramp);
       emit_block_move (blktramp, initial_trampoline,
                       GEN_INT (TRAMPOLINE_SIZE),
-                      FUNCTION_BOUNDARY / BITS_PER_UNIT);
+                      TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT);
 #endif
       INITIALIZE_TRAMPOLINE (tramp, XEXP (DECL_RTL (function), 0), context);
       seq = get_insns ();
@@ -5499,6 +5547,14 @@ expand_function_end (filename, line, end_bindings)
      without returning a value.  */
   emit_note (NULL_PTR, NOTE_INSN_FUNCTION_END);
 
+  /* Must mark the last line number note in the function, so that the test
+     coverage code can avoid counting the last line twice.  This just tells
+     the code to ignore the immediately following line note, since there
+     already exists a copy of this note somewhere above.  This line number
+     note is still needed for debugging though, so we can't delete it.  */
+  if (flag_test_coverage)
+    emit_note (NULL_PTR, NOTE_REPEATED_LINE_NUMBER);
+
   /* Output a linenumber for the end of the function.
      SDB depends on this.  */
   emit_line_note_force (filename, line);
@@ -5549,6 +5605,11 @@ expand_function_end (filename, line, end_bindings)
                          current_function_decl);
 #endif
       REG_FUNCTION_VALUE_P (real_decl_result) = 1;
+      /* If this is a BLKmode structure being returned in registers, then use
+        the mode computed in expand_return.  */
+      if (GET_MODE (real_decl_result) == BLKmode)
+       PUT_MODE (real_decl_result,
+                 GET_MODE (DECL_RTL (DECL_RESULT (current_function_decl))));
       emit_move_insn (real_decl_result,
                      DECL_RTL (DECL_RESULT (current_function_decl)));
       emit_insn (gen_rtx (USE, VOIDmode, real_decl_result));