OSDN Git Service

* Make-lang.in (stmp-f2c.h): Don't configure the runtime
[pf3gnuchains/gcc-fork.git] / gcc / function.c
index 827f14b..644cc72 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.  */
 
@@ -182,10 +191,10 @@ CUMULATIVE_ARGS current_function_args_info;
 
 char *current_function_name;
 
-/* If non-zero, an RTL expression for that location at which the current
-   function returns its result.  Always equal to
-   DECL_RTL (DECL_RESULT (current_function_decl)), but provided
-   independently of the tree structures.  */
+/* If non-zero, an RTL expression for the location at which the current 
+   function returns its result.  If the current function returns its
+   result in a register, current_function_return_rtx will always be
+   the hard register containing the result.  */
 
 rtx current_function_return_rtx;
 
@@ -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);
     }
 }
@@ -1312,7 +1330,7 @@ put_var_into_stack (decl)
 
   /* If this variable comes from an outer function,
      find that function's saved context.  */
-  if (context != current_function_decl)
+  if (context != current_function_decl && context != inline_function_decl)
     for (function = outer_function_chain; function; function = function->next)
       if (function->decl == context)
        break;
@@ -1363,6 +1381,15 @@ put_var_into_stack (decl)
       if (GET_CODE (XEXP (reg, 0)) == PLUS)
        XEXP (reg, 0) = copy_rtx (XEXP (reg, 0));
     }
+  else
+    return;
+  
+  if (flag_check_memory_usage)
+    emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
+                      XEXP (reg, 0), ptr_mode,
+                      GEN_INT (GET_MODE_SIZE (GET_MODE (reg))),
+                      TYPE_MODE (sizetype),
+                      GEN_INT (MEMORY_USE_RW), QImode);
 }
 
 /* Subroutine of put_var_into_stack.  This puts a single pseudo reg REG
@@ -1578,27 +1605,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 +1808,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 +2638,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 +2971,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 +3029,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 +3044,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 +3060,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.  */
@@ -3644,6 +3695,18 @@ assign_parms (fndecl, second_time)
          else
            stack_parm = gen_rtx (MEM, nominal_mode,
                                  gen_rtx (PLUS, Pmode,
+             if (flag_check_memory_usage)
+               {
+                 push_to_sequence (conversion_insns);
+                 emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
+                                    XEXP (stack_parm, 0), ptr_mode,
+                                    GEN_INT (int_size_in_bytes 
+                                             (TREE_TYPE (parm))),
+                                    TYPE_MODE (sizetype),
+                                    GEN_INT (MEMORY_USE_RW), QImode);
+                 conversion_insns = get_insns ();
+                 end_sequence ();
+               }
                                           internal_arg_pointer, offset_rtx));
 
          /* If this is a memory ref that contains aggregate components,
@@ -3864,6 +3927,12 @@ assign_parms (fndecl, second_time)
 
              store_expr (parm, copy, 0);
              emit_move_insn (parmreg, XEXP (copy, 0));
+             if (flag_check_memory_usage)
+               emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
+                                  XEXP (copy, 0), ptr_mode,
+                                  GEN_INT (int_size_in_bytes (type)),
+                                  TYPE_MODE (sizetype),
+                                  GEN_INT (MEMORY_USE_RW), QImode);
              conversion_insns = get_insns ();
              did_conversion = 1;
              end_sequence ();
@@ -3926,11 +3995,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 +4029,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.  */
@@ -4013,7 +4082,19 @@ assign_parms (fndecl, second_time)
                emit_move_insn (validize_mem (stack_parm),
                                validize_mem (entry_parm));
            }
+         if (flag_check_memory_usage)
+           {
+             push_to_sequence (conversion_insns);
+             emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
+                                XEXP (stack_parm, 0), ptr_mode,
+                                GEN_INT (GET_MODE_SIZE (GET_MODE 
+                                                        (entry_parm))),
+                                TYPE_MODE (sizetype),
+                                GEN_INT (MEMORY_USE_RW), QImode);
 
+             conversion_insns = get_insns ();
+             end_sequence ();
+           }
          DECL_RTL (parm) = stack_parm;
        }
       
@@ -4068,7 +4149,7 @@ assign_parms (fndecl, second_time)
     = (stack_args_size.var == 0 ? GEN_INT (-stack_args_size.constant)
        : expand_expr (size_binop (MINUS_EXPR, stack_args_size.var,     
                                  size_int (-stack_args_size.constant)),   
-                     NULL_RTX, VOIDmode, 0));
+                     NULL_RTX, VOIDmode, EXPAND_MEMORY_USE_BAD));
 #else
   current_function_arg_offset_rtx = ARGS_SIZE_RTX (stack_args_size);
 #endif
@@ -4237,8 +4318,8 @@ locate_and_pad_parm (passed_mode, type, in_regs, fndecl,
     }
   else
     {
-      arg_size_ptr->constant = (- initial_offset_ptr->constant -
-                               offset_ptr->constant); 
+      arg_size_ptr->constant = (- initial_offset_ptr->constant
+                               offset_ptr->constant); 
     }
 #else /* !ARGS_GROW_DOWNWARD */
   pad_to_arg_alignment (initial_offset_ptr, boundary);
@@ -4590,7 +4671,8 @@ trampoline_address (function)
   /* Find the `struct function' for the function containing FUNCTION.  */
   fp = 0;
   fn_context = decl_function_context (function);
-  if (fn_context != current_function_decl)
+  if (fn_context != current_function_decl
+      && fn_context != inline_function_decl)
     for (fp = outer_function_chain; fp; fp = fp->next)
       if (fp->decl == fn_context)
        break;
@@ -4871,8 +4953,6 @@ init_function_start (subr, filename, line)
      char *filename;
      int line;
 {
-  char *junk;
-
   if (output_bytecode)
     {
       this_function_decl = subr;
@@ -4920,7 +5000,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 +5018,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;
@@ -5093,8 +5174,8 @@ bc_expand_function_start (subr, parms_have_cleanups)
   ++nlab;
   name = (char *) obstack_copy0 (&permanent_obstack, label, strlen (label));
   this_function_callinfo = bc_gen_rtx (name, 0, (struct bc_label *) 0);
-  this_function_bytecode =
-    bc_emit_trampoline (BYTECODE_LABEL (this_function_callinfo));
+  this_function_bytecode
+    bc_emit_trampoline (BYTECODE_LABEL (this_function_callinfo));
 }
 
 
@@ -5163,7 +5244,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 +5359,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 +5401,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 +5441,13 @@ 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,
+                  EXPAND_MEMORY_USE_BAD);
+      /* 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 +5525,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 ();
@@ -5446,6 +5535,26 @@ expand_function_end (filename, line, end_bindings)
       emit_insns_before (seq, tail_recursion_reentry);
     }
 
+  /* If we are doing stack checking and this function makes calls,
+     do a stack probe at the start of the function to ensure we have enough
+     space for another stack frame.  */
+  if (flag_stack_check && ! STACK_CHECK_BUILTIN)
+    {
+      rtx insn, seq;
+
+      for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+       if (GET_CODE (insn) == CALL_INSN)
+         {
+           start_sequence ();
+           probe_stack_range (STACK_CHECK_PROTECT,
+                              GEN_INT (STACK_CHECK_MAX_FRAME_SIZE));
+           seq = get_insns ();
+           end_sequence ();
+           emit_insns_before (seq, tail_recursion_reentry);
+           break;
+         }
+    }
+
   /* Warn about unused parms if extra warnings were specified.  */
   if (warn_unused && extra_warnings)
     {
@@ -5499,6 +5608,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);
@@ -5516,6 +5633,24 @@ expand_function_end (filename, line, end_bindings)
   if (end_bindings)
     expand_end_bindings (0, 0, 0);
 
+  /* Now handle any leftover exception regions that may have been
+     created for the parameters.  */
+  {
+    rtx last = get_last_insn ();
+    rtx label;
+
+    expand_leftover_cleanups ();
+
+    /* If the above emitted any code, may sure we jump around it.  */
+    if (last != get_last_insn ())
+      {
+       label = gen_label_rtx ();
+       last = emit_jump_insn_after (gen_jump (label), last);
+       last = emit_barrier_after (last);
+       emit_label (label);
+      }
+  }
+
   /* If we had calls to alloca, and this machine needs
      an accurate stack pointer to exit the function,
      insert some code to save and restore the stack pointer.  */
@@ -5549,9 +5684,19 @@ 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));
+
+      /* The delay slot scheduler assumes that current_function_return_rtx
+        holds the hard register containing the return value, not a temporary
+        pseudo.  */
+      current_function_return_rtx = real_decl_result;
     }
 
   /* If returning a structure, arrange to return the address of the value