OSDN Git Service

[pf3gnuchains/gcc-fork.git] / gcc / function.c
index 44cee08..d2eab67 100644 (file)
@@ -55,6 +55,7 @@ Boston, MA 02111-1307, USA.  */
 #include "output.h"
 #include "basic-block.h"
 #include "obstack.h"
+#include "toplev.h"
 
 #ifndef TRAMPOLINE_ALIGNMENT
 #define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY
@@ -137,6 +138,12 @@ int current_function_has_computed_jump;
 
 int current_function_contains_functions;
 
+/* Nonzero if function being compiled doesn't modify the stack pointer
+   (ignoring the prologue and epilogue).  This is only valid after
+   life_analysis has run. */
+
+int current_function_sp_is_unchanging;
+
 /* 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.  */
@@ -213,6 +220,16 @@ int current_function_uses_pic_offset_table;
 /* The arg pointer hard register, or the pseudo into which it was copied.  */
 rtx current_function_internal_arg_pointer;
 
+/* Language-specific reason why the current function cannot be made inline.  */
+char *current_function_cannot_inline;
+
+/* Nonzero if instrumentation calls for function entry and exit should be
+   generated.  */
+int current_function_instrument_entry_exit;
+
+/* Nonzero if memory access checking be enabled in the current function.  */
+int current_function_check_memory_usage;
+
 /* The FUNCTION_DECL for an inline function currently being expanded.  */
 tree inline_function_decl;
 
@@ -438,16 +455,18 @@ static void pad_to_arg_alignment PROTO((struct args_size *, int));
 static void pad_below          PROTO((struct args_size *, enum  machine_mode,
                                       tree));
 #endif
+#ifdef ARGS_GROW_DOWNWARD
 static tree round_down         PROTO((tree, int));
+#endif
 static rtx round_trampoline_addr PROTO((rtx));
 static tree blocks_nreverse    PROTO((tree));
 static int all_blocks          PROTO((tree, tree *));
-static int *record_insns       PROTO((rtx));
 #if defined (HAVE_prologue) || defined (HAVE_epilogue)
+static int *record_insns       PROTO((rtx));
 static int contains            PROTO((rtx, int *));
 #endif /* HAVE_prologue || HAVE_epilogue */
 static void put_addressof_into_stack PROTO((rtx));
-static void purge_addressof_1  PROTO((rtx *, rtx, int));
+static void purge_addressof_1  PROTO((rtx *, rtx, int, int));
 \f
 /* Pointer to chain of `struct function' for containing functions.  */
 struct function *outer_function_chain;
@@ -504,6 +523,7 @@ push_function_context_to (context)
   p->uses_const_pool = current_function_uses_const_pool;
   p->uses_pic_offset_table = current_function_uses_pic_offset_table;
   p->internal_arg_pointer = current_function_internal_arg_pointer;
+  p->cannot_inline = current_function_cannot_inline;
   p->max_parm_reg = max_parm_reg;
   p->parm_reg_stack_loc = parm_reg_stack_loc;
   p->outgoing_args_size = current_function_outgoing_args_size;
@@ -532,6 +552,8 @@ push_function_context_to (context)
   p->fixup_var_refs_queue = 0;
   p->epilogue_delay_list = current_function_epilogue_delay_list;
   p->args_info = current_function_args_info;
+  p->check_memory_usage = current_function_check_memory_usage;
+  p->instrument_entry_exit = current_function_instrument_entry_exit;
 
   save_tree_status (p, context);
   save_storage_status (p);
@@ -585,6 +607,7 @@ pop_function_context_from (context)
   current_function_uses_const_pool = p->uses_const_pool;
   current_function_uses_pic_offset_table = p->uses_pic_offset_table;
   current_function_internal_arg_pointer = p->internal_arg_pointer;
+  current_function_cannot_inline = p->cannot_inline;
   max_parm_reg = p->max_parm_reg;
   parm_reg_stack_loc = p->parm_reg_stack_loc;
   current_function_outgoing_args_size = p->outgoing_args_size;
@@ -613,6 +636,8 @@ pop_function_context_from (context)
   current_function_epilogue_delay_list = p->epilogue_delay_list;
   reg_renumber = 0;
   current_function_args_info = p->args_info;
+  current_function_check_memory_usage = p->check_memory_usage;
+  current_function_instrument_entry_exit = p->instrument_entry_exit;
 
   restore_tree_status (p, context);
   restore_storage_status (p);
@@ -1367,7 +1392,7 @@ put_var_into_stack (decl)
 
   context = decl_function_context (decl);
 
-  /* Get the current rtl used for this object and it's original mode.  */
+  /* Get the current rtl used for this object and its original mode.  */
   reg = TREE_CODE (decl) == SAVE_EXPR ? SAVE_EXPR_RTL (decl) : DECL_RTL (decl);
 
   /* No need to do anything if decl has no rtx yet
@@ -1458,6 +1483,7 @@ put_var_into_stack (decl)
       /* Change the CONCAT into a combined MEM for both parts.  */
       PUT_CODE (reg, MEM);
       MEM_VOLATILE_P (reg) = MEM_VOLATILE_P (XEXP (reg, 0));
+      MEM_ALIAS_SET (reg) = get_alias_set (decl);
 
       /* The two parts are in memory order already.
         Use the lower parts address as ours.  */
@@ -1469,7 +1495,7 @@ put_var_into_stack (decl)
   else
     return;
   
-  if (flag_check_memory_usage)
+  if (current_function_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))),
@@ -1530,6 +1556,7 @@ put_reg_into_stack (function, reg, type, promoted_mode, decl_mode, volatile_p,
      case it was set for other reasons.  For instance, it is set for
      __builtin_va_alist.  */
   MEM_IN_STRUCT_P (reg) = AGGREGATE_TYPE_P (type) | MEM_IN_STRUCT_P (new);
+  MEM_ALIAS_SET (reg) = get_alias_set (type);
 
   /* Now make sure that all refs to the variable, previously made
      when it was a register, are fixed up to be valid again.  */
@@ -1651,7 +1678,10 @@ fixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel)
             If it has a REG_LIBCALL note, delete the REG_LIBCALL
             and REG_RETVAL notes too.  */
          if (GET_CODE (PATTERN (insn)) == CLOBBER
-             && XEXP (PATTERN (insn), 0) == var)
+             && (XEXP (PATTERN (insn), 0) == var
+                 || (GET_CODE (XEXP (PATTERN (insn), 0)) == CONCAT
+                     && (XEXP (XEXP (PATTERN (insn), 0), 0) == var
+                         || XEXP (XEXP (PATTERN (insn), 0), 1) == var))))
            {
              if ((note = find_reg_note (insn, REG_LIBCALL, NULL_RTX)) != 0)
                /* The REG_LIBCALL note will go away since we are going to
@@ -1956,11 +1986,19 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
 
 #ifdef HAVE_extzv
              if (GET_CODE (x) == ZERO_EXTRACT)
-               wanted_mode = insn_operand_mode[(int) CODE_FOR_extzv][1];
+               {
+                 wanted_mode = insn_operand_mode[(int) CODE_FOR_extzv][1];
+                 if (wanted_mode == VOIDmode)
+                   wanted_mode = word_mode;
+               }
 #endif
 #ifdef HAVE_extv
              if (GET_CODE (x) == SIGN_EXTRACT)
-               wanted_mode = insn_operand_mode[(int) CODE_FOR_extv][1];
+               {
+                 wanted_mode = insn_operand_mode[(int) CODE_FOR_extv][1];
+                 if (wanted_mode == VOIDmode)
+                   wanted_mode = word_mode;
+               }
 #endif
              /* If we have a narrower mode, we can do something.  */
              if (wanted_mode != VOIDmode
@@ -2149,11 +2187,14 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
                && ! mode_dependent_address_p (XEXP (tem, 0))
                && ! MEM_VOLATILE_P (tem))
              {
-               enum machine_mode wanted_mode
-                 = insn_operand_mode[(int) CODE_FOR_insv][0];
+               enum machine_mode wanted_mode;
                enum machine_mode is_mode = GET_MODE (tem);
                HOST_WIDE_INT pos = INTVAL (XEXP (outerdest, 2));
 
+               wanted_mode = insn_operand_mode[(int) CODE_FOR_insv][0];
+               if (wanted_mode == VOIDmode)
+                 wanted_mode = word_mode;
+
                /* If we have a narrower mode, we can do something.  */
                if (GET_MODE_SIZE (wanted_mode) < GET_MODE_SIZE (is_mode))
                  {
@@ -2669,6 +2710,7 @@ static int in_arg_offset;
 static int var_offset;
 static int dynamic_offset;
 static int out_arg_offset;
+static int cfa_offset;
 
 /* In most machines, the stack pointer register is equivalent to the bottom
    of the stack.  */
@@ -2707,6 +2749,13 @@ static int out_arg_offset;
 #endif
 #endif
 
+/* On a few machines, the CFA coincides with the arg pointer.  */
+
+#ifndef ARG_POINTER_CFA_OFFSET
+#define ARG_POINTER_CFA_OFFSET 0
+#endif
+
+
 /* Build up a (MEM (ADDRESSOF (REG))) rtx for a register REG that just had
    its address taken.  DECL is the decl for the object stored in the
    register, for later use if we do need to force REG into the stack.
@@ -2718,15 +2767,18 @@ gen_mem_addressof (reg, decl)
      tree decl;
 {
   tree type = TREE_TYPE (decl);
-
   rtx r = gen_rtx_ADDRESSOF (Pmode, gen_reg_rtx (GET_MODE (reg)), REGNO (reg));
   SET_ADDRESSOF_DECL (r, decl);
+  /* If the original REG was a user-variable, then so is the REG whose
+     address is being taken.  */
+  REG_USERVAR_P (XEXP (r, 0)) = REG_USERVAR_P (reg);
 
   XEXP (reg, 0) = r;
   PUT_CODE (reg, MEM);
   PUT_MODE (reg, DECL_MODE (decl));
   MEM_VOLATILE_P (reg) = TREE_SIDE_EFFECTS (decl);
   MEM_IN_STRUCT_P (reg) = AGGREGATE_TYPE_P (type);
+  MEM_ALIAS_SET (reg) = get_alias_set (decl);
 
   if (TREE_USED (decl) || DECL_INITIAL (decl) != 0)
     fixup_var_refs (reg, GET_MODE (reg), TREE_UNSIGNED (type));
@@ -2766,15 +2818,19 @@ put_addressof_into_stack (r)
                      TREE_USED (decl) || DECL_INITIAL (decl) != 0);
 }
 
+/* List of replacements made below in purge_addressof_1 when creating
+   bitfield insertions.  */
+static rtx purge_addressof_replacements;
+
 /* Helper function for purge_addressof.  See if the rtx expression at *LOC
    in INSN needs to be changed.  If FORCE, always put any ADDRESSOFs into
    the stack.  */
 
 static void
-purge_addressof_1 (loc, insn, force)
+purge_addressof_1 (loc, insn, force, store)
      rtx *loc;
      rtx insn;
-     int force;
+     int force, store;
 {
   rtx x;
   RTX_CODE code;
@@ -2806,9 +2862,9 @@ purge_addressof_1 (loc, insn, force)
                             0))
        abort ();
 
-      insns = get_insns ();
+      insns = gen_sequence ();
       end_sequence ();
-      emit_insns_before (insns, insn);
+      emit_insn_before (insns, insn);
       return;
     }
   else if (code == MEM && GET_CODE (XEXP (x, 0)) == ADDRESSOF && ! force)
@@ -2826,15 +2882,99 @@ purge_addressof_1 (loc, insn, force)
        }
       else if (GET_CODE (sub) == REG && GET_MODE (x) != GET_MODE (sub))
        {
-         if (! BYTES_BIG_ENDIAN && ! WORDS_BIG_ENDIAN)
+         int size_x, size_sub;
+
+         if (!insn)
            {
-             rtx sub2 = gen_rtx_SUBREG (GET_MODE (x), sub, 0);
-             if (validate_change (insn, loc, sub2, 0))
-               goto restart;
+             /* When processing REG_NOTES look at the list of
+                replacements done on the insn to find the register that X
+                was replaced by.  */
+             rtx tem;
+
+             for (tem = purge_addressof_replacements; tem != NULL_RTX;
+                  tem = XEXP (XEXP (tem, 1), 1))
+               if (rtx_equal_p (x, XEXP (tem, 0)))
+                 {
+                   *loc = XEXP (XEXP (tem, 1), 0);
+                   return;
+                 }
+
+             /* There should always be such a replacement.  */
+             abort ();
+           }
+
+         size_x = GET_MODE_BITSIZE (GET_MODE (x));
+         size_sub = GET_MODE_BITSIZE (GET_MODE (sub));
+
+         /* Don't even consider working with paradoxical subregs,
+            or the moral equivalent seen here.  */
+         if (size_x <= size_sub
+             && int_mode_for_mode (GET_MODE (sub)) != BLKmode)
+           {
+             /* Do a bitfield insertion to mirror what would happen
+                in memory.  */
+
+             rtx val, seq;
+
+             if (store)
+               {
+                 start_sequence ();
+                 val = gen_reg_rtx (GET_MODE (x));
+                 if (! validate_change (insn, loc, val, 0))
+                   {
+                     /* Discard the current sequence and put the
+                        ADDRESSOF on stack.  */
+                     end_sequence ();
+                     goto give_up;
+                   }
+                 seq = gen_sequence ();
+                 end_sequence ();
+                 emit_insn_before (seq, insn);
+             
+                 start_sequence ();
+                 store_bit_field (sub, size_x, 0, GET_MODE (x),
+                                  val, GET_MODE_SIZE (GET_MODE (sub)),
+                                  GET_MODE_SIZE (GET_MODE (sub)));
+
+                 seq = gen_sequence ();
+                 end_sequence ();
+                 emit_insn_after (seq, insn);
+               }
+             else
+               {
+                 start_sequence ();
+                 val = extract_bit_field (sub, size_x, 0, 1, NULL_RTX,
+                                          GET_MODE (x), GET_MODE (x),
+                                          GET_MODE_SIZE (GET_MODE (sub)),
+                                          GET_MODE_SIZE (GET_MODE (sub)));
+
+                 if (! validate_change (insn, loc, val, 0))
+                   {
+                     /* Discard the current sequence and put the
+                        ADDRESSOF on stack.  */
+                     end_sequence ();
+                     goto give_up;
+                   }
+
+                 seq = gen_sequence ();
+                 end_sequence ();
+                 emit_insn_before (seq, insn);
+               }
+
+             /* Remember the replacement so that the same one can be done
+                on the REG_NOTES.  */
+             purge_addressof_replacements
+               = gen_rtx_EXPR_LIST (VOIDmode, x,
+                                    gen_rtx_EXPR_LIST (VOIDmode, val,
+                                                       purge_addressof_replacements));
+
+             /* We replaced with a reg -- all done.  */
+             return;
            }
        }
       else if (validate_change (insn, loc, sub, 0))
        goto restart;
+    give_up:;
       /* else give up and put it into the stack */
     }
   else if (code == ADDRESSOF)
@@ -2842,16 +2982,22 @@ purge_addressof_1 (loc, insn, force)
       put_addressof_into_stack (x);
       return;
     }
+  else if (code == SET)
+    {
+      purge_addressof_1 (&SET_DEST (x), insn, force, 1);
+      purge_addressof_1 (&SET_SRC (x), insn, force, 0);
+      return;
+    }
 
   /* Scan all subexpressions. */
   fmt = GET_RTX_FORMAT (code);
   for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
     {
       if (*fmt == 'e')
-       purge_addressof_1 (&XEXP (x, i), insn, force);
+       purge_addressof_1 (&XEXP (x, i), insn, force, 0);
       else if (*fmt == 'E')
        for (j = 0; j < XVECLEN (x, i); j++)
-         purge_addressof_1 (&XVECEXP (x, i, j), insn, force);
+         purge_addressof_1 (&XVECEXP (x, i, j), insn, force, 0);
     }
 }
 
@@ -2869,8 +3015,9 @@ purge_addressof (insns)
        || GET_CODE (insn) == CALL_INSN)
       {
        purge_addressof_1 (&PATTERN (insn), insn,
-                          asm_noperands (PATTERN (insn)) > 0);
-       purge_addressof_1 (&REG_NOTES (insn), NULL_RTX, 0);
+                          asm_noperands (PATTERN (insn)) > 0, 0);
+       purge_addressof_1 (&REG_NOTES (insn), NULL_RTX, 0, 0);
+       purge_addressof_replacements = 0;
       }
 }
 \f
@@ -2890,6 +3037,7 @@ instantiate_virtual_regs (fndecl, insns)
   var_offset = STARTING_FRAME_OFFSET;
   dynamic_offset = STACK_DYNAMIC_OFFSET (fndecl);
   out_arg_offset = STACK_POINTER_OFFSET;
+  cfa_offset = ARG_POINTER_CFA_OFFSET;
 
   /* Scan all variables and parameters of this function.  For each that is
      in memory, instantiate all virtual registers if the result is a valid
@@ -3112,7 +3260,7 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
 
     case SET:
       /* We are allowed to set the virtual registers.  This means that
-        that the actual register should receive the source minus the
+        the actual register should receive the source minus the
         appropriate offset.  This is used, for example, in the handling
         of non-local gotos.  */
       if (SET_DEST (x) == virtual_incoming_args_rtx)
@@ -3123,6 +3271,8 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
        new = stack_pointer_rtx, offset = - dynamic_offset;
       else if (SET_DEST (x) == virtual_outgoing_args_rtx)
        new = stack_pointer_rtx, offset = - out_arg_offset;
+      else if (SET_DEST (x) == virtual_cfa_rtx)
+       new = arg_pointer_rtx, offset = - cfa_offset;
 
       if (new)
        {
@@ -3174,6 +3324,8 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
                new = stack_pointer_rtx, offset = dynamic_offset;
              else if (inner == virtual_outgoing_args_rtx)
                new = stack_pointer_rtx, offset = out_arg_offset;
+             else if (inner == virtual_cfa_rtx)
+               new = arg_pointer_rtx, offset = cfa_offset;
              else
                {
                  loc = &XEXP (x, 0);
@@ -3193,6 +3345,8 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
            new = stack_pointer_rtx, offset = dynamic_offset;
          else if (XEXP (x, 0) == virtual_outgoing_args_rtx)
            new = stack_pointer_rtx, offset = out_arg_offset;
+          else if (XEXP (x, 0) == virtual_cfa_rtx)
+            new = arg_pointer_rtx, offset = cfa_offset;
          else
            {
              /* We know the second operand is a constant.  Unless the
@@ -3400,6 +3554,8 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
        new = stack_pointer_rtx, offset = dynamic_offset;
       else if (x == virtual_outgoing_args_rtx)
        new = stack_pointer_rtx, offset = out_arg_offset;
+      else if (x == virtual_cfa_rtx)
+        new = arg_pointer_rtx, offset = cfa_offset;
 
       if (new)
        {
@@ -3900,6 +4056,7 @@ assign_parms (fndecl, second_time)
             is readonly.  */
          MEM_IN_STRUCT_P (stack_parm) = aggregate;
          RTX_UNCHANGING_P (stack_parm) = TREE_READONLY (parm);
+         MEM_ALIAS_SET (stack_parm) = get_alias_set (parm);
        }
 
       /* If this parameter was passed both in registers and in the stack,
@@ -3933,8 +4090,10 @@ assign_parms (fndecl, second_time)
                  /* Handle calls that pass values in multiple non-contiguous
                     locations.  The Irix 6 ABI has examples of this.  */
                  if (GET_CODE (entry_parm) == PARALLEL)
-                   emit_group_store (validize_mem (stack_parm),
-                                        entry_parm);
+                   emit_group_store (validize_mem (stack_parm), entry_parm,
+                                     int_size_in_bytes (TREE_TYPE (parm)),
+                                     (TYPE_ALIGN (TREE_TYPE (parm))
+                                      / BITS_PER_UNIT));
                  else
                    move_block_from_reg (REGNO (entry_parm),
                                         validize_mem (stack_parm), nregs,
@@ -4104,7 +4263,10 @@ assign_parms (fndecl, second_time)
              /* Handle calls that pass values in multiple non-contiguous
                 locations.  The Irix 6 ABI has examples of this.  */
              if (GET_CODE (entry_parm) == PARALLEL)
-               emit_group_store (validize_mem (stack_parm), entry_parm);
+               emit_group_store (validize_mem (stack_parm), entry_parm,
+                                 int_size_in_bytes (TREE_TYPE (parm)),
+                                 (TYPE_ALIGN (TREE_TYPE (parm))
+                                  / BITS_PER_UNIT));
              else
                move_block_from_reg (REGNO (entry_parm),
                                     validize_mem (stack_parm),
@@ -4252,7 +4414,7 @@ assign_parms (fndecl, second_time)
 
              store_expr (parm, copy, 0);
              emit_move_insn (parmreg, XEXP (copy, 0));
-             if (flag_check_memory_usage)
+             if (current_function_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)),
@@ -4417,7 +4579,7 @@ assign_parms (fndecl, second_time)
                emit_move_insn (validize_mem (stack_parm),
                                validize_mem (entry_parm));
            }
-         if (flag_check_memory_usage)
+         if (current_function_check_memory_usage)
            {
              push_to_sequence (conversion_insns);
              emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
@@ -4746,6 +4908,7 @@ pad_below (offset_ptr, passed_mode, sizetree)
 }
 #endif
 
+#ifdef ARGS_GROW_DOWNWARD
 static tree
 round_down (value, divisor)
      tree value;
@@ -4755,6 +4918,7 @@ round_down (value, divisor)
                     size_binop (FLOOR_DIV_EXPR, value, size_int (divisor)),
                     size_int (divisor));
 }
+#endif
 \f
 /* Walk the tree of blocks describing the binding levels within a function
    and warn about uninitialized variables.
@@ -4776,6 +4940,14 @@ uninitialized_vars_warning (block)
          && ! AGGREGATE_TYPE_P (TREE_TYPE (decl))
          && DECL_RTL (decl) != 0
          && GET_CODE (DECL_RTL (decl)) == REG
+         /* Global optimizations can make it difficult to determine if a
+            particular variable has been initialized.  However, a VAR_DECL
+            with a nonzero DECL_INITIAL had an initializer, so do not
+            claim it is potentially uninitialized.
+
+            We do not care about the actual value in DECL_INITIAL, so we do
+            not worry that it may be a dangling pointer.  */
+         && DECL_INITIAL (decl) == NULL_TREE
          && regno_uninitialized (REGNO (DECL_RTL (decl))))
        warning_with_decl (decl,
                           "`%s' might be used uninitialized in this function");
@@ -4821,7 +4993,7 @@ setjmp_protect (block)
            || (GET_CODE (DECL_RTL (decl)) == MEM
                && GET_CODE (XEXP (DECL_RTL (decl), 0)) == ADDRESSOF))
        /* If this variable came from an inline function, it must be
-          that it's life doesn't overlap the setjmp.  If there was a
+          that its life doesn't overlap the setjmp.  If there was a
           setjmp in the function, it would already be in memory.  We
           must exclude such variable because their DECL_RTL might be
           set to strange things such as virtual_stack_vars_rtx.  */
@@ -5132,8 +5304,8 @@ identify_blocks (block, insns)
          }
        if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END)
          {
-           current_block_number = block_stack[--depth];
            NOTE_BLOCK_NUMBER (insn) = current_block_number;
+           current_block_number = block_stack[--depth];
          }
       }
 
@@ -5307,6 +5479,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_sp_is_unchanging = 0;
   current_function_is_thunk = 0;
 
   current_function_returns_pcc_struct = 0;
@@ -5314,6 +5487,7 @@ init_function_start (subr, filename, line)
   current_function_epilogue_delay_list = 0;
   current_function_uses_const_pool = 0;
   current_function_uses_pic_offset_table = 0;
+  current_function_cannot_inline = 0;
 
   /* We have not yet needed to make a label to jump to for tail-recursion.  */
   tail_recursion_label = 0;
@@ -5346,8 +5520,10 @@ init_function_start (subr, filename, line)
   current_function_outgoing_args_size = 0;
 
   /* Prevent ever trying to delete the first instruction of a function.
-     Also tell final how to output a linenum before the function prologue.  */
-  emit_line_note (filename, line);
+     Also tell final how to output a linenum before the function prologue.
+     Note linenums could be missing, e.g. when compiling a Java .class file. */
+  if (line > 0)
+    emit_line_note (filename, line);
 
   /* Make sure first insn is a note even if we don't want linenums.
      This makes sure the first insn will never be deleted.
@@ -5433,6 +5609,15 @@ expand_function_start (subr, parms_have_cleanups)
      valid operands of arithmetic insns.  */
   init_recog_no_volatile ();
 
+  /* Set this before generating any memory accesses.  */
+  current_function_check_memory_usage
+    = (flag_check_memory_usage
+       && ! DECL_NO_CHECK_MEMORY_USAGE (current_function_decl));
+
+  current_function_instrument_entry_exit
+    = (flag_instrument_function_entry_exit
+       && ! DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (subr));
+
   /* If function gets a static chain arg, store it in the stack frame.
      Do this first, so it gets the first stack slot offset.  */
   if (current_function_needs_context)
@@ -5459,6 +5644,7 @@ expand_function_start (subr, parms_have_cleanups)
      or if it returns a structure, or if it has parm cleanups.  */
 #ifdef HAVE_return
   if (cleanup_label == 0 && HAVE_return
+      && ! current_function_instrument_entry_exit
       && ! current_function_returns_pcc_struct
       && ! (current_function_returns_struct && ! optimize))
     return_label = 0;
@@ -5507,7 +5693,7 @@ expand_function_start (subr, parms_have_cleanups)
   else if (DECL_MODE (DECL_RESULT (subr)) == VOIDmode)
     /* If return mode is void, this decl rtl should not be used.  */
     DECL_RTL (DECL_RESULT (subr)) = 0;
-  else if (parms_have_cleanups)
+  else if (parms_have_cleanups || current_function_instrument_entry_exit)
     {
       /* If function will end with cleanup code for parms,
         compute the return values into a pseudo reg,
@@ -5625,6 +5811,21 @@ expand_function_start (subr, parms_have_cleanups)
        }
     }
 
+  if (current_function_instrument_entry_exit)
+    {
+      rtx fun = DECL_RTL (current_function_decl);
+      if (GET_CODE (fun) == MEM)
+       fun = XEXP (fun, 0);
+      else
+       abort ();
+      emit_library_call (profile_function_entry_libfunc, 0, VOIDmode, 2,
+                        fun, Pmode,
+                        expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
+                                                    0,
+                                                    hard_frame_pointer_rtx),
+                        Pmode);
+    }
+
   /* After the display initializations is where the tail-recursion label
      should go, if we end up needing one.   Ensure we have a NOTE here
      since some things (like trampolines) get placed before this.  */
@@ -5688,7 +5889,9 @@ expand_function_end (filename, line, end_bindings)
       tree function = TREE_PURPOSE (link);
       rtx context = lookup_static_chain (function);
       rtx tramp = RTL_EXPR_RTL (TREE_VALUE (link));
+#ifdef TRAMPOLINE_TEMPLATE
       rtx blktramp;
+#endif
       rtx seq;
 
 #ifdef TRAMPOLINE_TEMPLATE
@@ -5836,6 +6039,21 @@ expand_function_end (filename, line, end_bindings)
       }
   }
 
+  if (current_function_instrument_entry_exit)
+    {
+      rtx fun = DECL_RTL (current_function_decl);
+      if (GET_CODE (fun) == MEM)
+       fun = XEXP (fun, 0);
+      else
+       abort ();
+      emit_library_call (profile_function_exit_libfunc, 0, VOIDmode, 2,
+                        fun, Pmode,
+                        expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
+                                                    0,
+                                                    hard_frame_pointer_rtx),
+                        Pmode);
+    }
+
   /* 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.  */
@@ -5913,6 +6131,10 @@ expand_function_end (filename, line, end_bindings)
       use_variable (outgoing);
     }
 
+  /* If this is an implementation of __throw, do what's necessary to 
+     communicate between __builtin_eh_return and the epilogue.  */
+  expand_eh_return ();
+
   /* Output a return insn if we are using one.
      Otherwise, let the rtl chain end here, to drop through
      into the epilogue.  */
@@ -5943,6 +6165,7 @@ static int *epilogue;
 /* Create an array that records the INSN_UIDs of INSNS (either a sequence
    or a single insn).  */
 
+#if defined (HAVE_prologue) || defined (HAVE_epilogue)
 static int *
 record_insns (insns)
      rtx insns;
@@ -5968,7 +6191,6 @@ record_insns (insns)
 
 /* Determine how many INSN_UIDs in VEC are part of INSN.  */
 
-#if defined (HAVE_prologue) || defined (HAVE_epilogue)
 static int
 contains (insn, vec)
      rtx insn;
@@ -6002,7 +6224,7 @@ contains (insn, vec)
 
 void
 thread_prologue_and_epilogue_insns (f)
-     rtx f;
+     rtx f ATTRIBUTE_UNUSED;
 {
 #ifdef HAVE_prologue
   if (HAVE_prologue)
@@ -6103,7 +6325,7 @@ thread_prologue_and_epilogue_insns (f)
 
 void
 reposition_prologue_and_epilogue_notes (f)
-     rtx f;
+     rtx f ATTRIBUTE_UNUSED;
 {
 #if defined (HAVE_prologue) || defined (HAVE_epilogue)
   /* Reposition the prologue and epilogue notes.  */
@@ -6139,12 +6361,19 @@ reposition_prologue_and_epilogue_notes (f)
                            && 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;
+
+                 /* Whether or not we can depend on basic_block_head, 
+                    attempt to keep it up-to-date.  */
+                 if (basic_block_head[0] == note)
+                   basic_block_head[0] = next;
+
                  add_insn_after (note, insn);
                }
            }
@@ -6183,7 +6412,14 @@ reposition_prologue_and_epilogue_notes (f)
                    NEXT_INSN (prev) = next;
                  if (next)
                    PREV_INSN (next) = prev;
-                 add_insn_after (note, PREV_INSN (insn));
+
+                 /* Whether or not we can depend on basic_block_head, 
+                    attempt to keep it up-to-date.  */
+                 if (n_basic_blocks
+                     && basic_block_head[n_basic_blocks-1] == insn)
+                   basic_block_head[n_basic_blocks-1] = note;
+
+                 add_insn_before (note, insn);
                }
            }
        }