OSDN Git Service

2000-07-21 Alexandre Petit-Bianco <apbianco@cygnus.com>
[pf3gnuchains/gcc-fork.git] / gcc / function.c
index 0f6785b..fc8be4c 100644 (file)
@@ -204,7 +204,7 @@ struct temp_slot
      imposed on the memory.  For example, if the stack slot is the
      call frame for an inline functioned, we have no idea what alias
      sets will be assigned to various pieces of the call frame.  */
-  int alias_set;
+  HOST_WIDE_INT alias_set;
   /* The value of `sequence_rtl_expr' when this temporary is allocated.  */
   tree rtl_expr;
   /* Non-zero if this temporary is currently in use.  */
@@ -276,9 +276,6 @@ static void pad_to_arg_alignment PARAMS ((struct args_size *, int,
 static void pad_below          PARAMS ((struct args_size *, enum machine_mode,
                                         tree));
 #endif
-#ifdef ARGS_GROW_DOWNWARD
-static tree round_down         PARAMS ((tree, int));
-#endif
 static rtx round_trampoline_addr PARAMS ((rtx));
 static tree *identify_blocks_1 PARAMS ((rtx, tree *, tree *, tree *));
 static void reorder_blocks_1   PARAMS ((rtx, tree, varray_type *));
@@ -290,7 +287,7 @@ static tree *get_block_vector   PARAMS ((tree, int *));
 static void record_insns       PARAMS ((rtx, varray_type *)) ATTRIBUTE_UNUSED;
 static int contains            PARAMS ((rtx, varray_type));
 #ifdef HAVE_return
-static void emit_return_into_block PARAMS ((basic_block));
+static void emit_return_into_block PARAMS ((basic_block, rtx));
 #endif
 static void put_addressof_into_stack PARAMS ((rtx, struct hash_table *));
 static boolean purge_addressof_1 PARAMS ((rtx *, rtx, int, int, 
@@ -628,6 +625,7 @@ assign_stack_local_1 (mode, size, align, function)
 
 /* Wrapper around assign_stack_local_1;  assign a local stack slot for the
    current function.  */
+
 rtx
 assign_stack_local (mode, size, align)
      enum machine_mode mode;
@@ -662,7 +660,7 @@ assign_stack_temp_for_type (mode, size, keep, type)
      tree type;
 {
   int align;
-  int alias_set;
+  HOST_WIDE_INT alias_set;
   struct temp_slot *p, *best_p = 0;
 
   /* If SIZE is -1 it means that somebody tried to allocate a temporary
@@ -684,6 +682,7 @@ assign_stack_temp_for_type (mode, size, keep, type)
 
   if (! type)
     type = type_for_mode (mode, 0);
+
   if (type)
     align = LOCAL_ALIGNMENT (type, align);
 
@@ -693,7 +692,7 @@ assign_stack_temp_for_type (mode, size, keep, type)
   for (p = temp_slots; p; p = p->next)
     if (p->align >= align && p->size >= size && GET_MODE (p->slot) == mode
        && ! p->in_use
-       && (!flag_strict_aliasing
+       && (! flag_strict_aliasing
            || (alias_set && p->alias_set == alias_set))
        && (best_p == 0 || best_p->size > p->size
            || (best_p->size == p->size && best_p->align > p->align)))
@@ -712,11 +711,7 @@ assign_stack_temp_for_type (mode, size, keep, type)
       /* If there are enough aligned bytes left over, make them into a new
         temp_slot so that the extra bytes don't get wasted.  Do this only
         for BLKmode slots, so that we can be sure of the alignment.  */
-      if (GET_MODE (best_p->slot) == BLKmode
-         /* We can't split slots if -fstrict-aliasing because the
-            information about the alias set for the new slot will be
-            lost.  */
-         && !flag_strict_aliasing)
+      if (GET_MODE (best_p->slot) == BLKmode)
        {
          int alignment = best_p->align / BITS_PER_UNIT;
          HOST_WIDE_INT rounded_size = CEIL_ROUND (size, alignment);
@@ -734,6 +729,7 @@ assign_stack_temp_for_type (mode, size, keep, type)
              p->align = best_p->align;
              p->address = 0;
              p->rtl_expr = 0;
+             p->alias_set = best_p->alias_set;
              p->next = temp_slots;
              temp_slots = p;
 
@@ -824,7 +820,11 @@ assign_stack_temp_for_type (mode, size, keep, type)
   RTX_UNCHANGING_P (p->slot) = 0;
   MEM_IN_STRUCT_P (p->slot) = 0;
   MEM_SCALAR_P (p->slot) = 0;
-  MEM_ALIAS_SET (p->slot) = 0;
+  MEM_ALIAS_SET (p->slot) = alias_set;
+
+  if (type != 0)
+    MEM_SET_IN_STRUCT_P (p->slot, AGGREGATE_TYPE_P (type));
+
   return p->slot;
 }
 
@@ -875,11 +875,10 @@ assign_temp (type, keep, memory_required, dont_promote)
         instead.  This is the case for Chill variable-sized strings.  */
       if (size == -1 && TREE_CODE (type) == ARRAY_TYPE
          && TYPE_ARRAY_MAX_SIZE (type) != NULL_TREE
-         && TREE_CODE (TYPE_ARRAY_MAX_SIZE (type)) == INTEGER_CST)
-       size = TREE_INT_CST_LOW (TYPE_ARRAY_MAX_SIZE (type));
+         && host_integerp (TYPE_ARRAY_MAX_SIZE (type), 1))
+       size = tree_low_cst (TYPE_ARRAY_MAX_SIZE (type), 1);
 
       tmp = assign_stack_temp_for_type (mode, size, keep, type);
-      MEM_SET_IN_STRUCT_P (tmp, AGGREGATE_TYPE_P (type));
       return tmp;
     }
 
@@ -1333,6 +1332,9 @@ put_var_into_stack (decl)
   struct function *function = 0;
   tree context;
   int can_use_addressof;
+  int volatilep = TREE_CODE (decl) != SAVE_EXPR && TREE_THIS_VOLATILE (decl);
+  int usedp = (TREE_USED (decl)
+              || (TREE_CODE (decl) != SAVE_EXPR && DECL_INITIAL (decl) != 0));
 
   context = decl_function_context (decl);
 
@@ -1360,7 +1362,7 @@ put_var_into_stack (decl)
 
   /* If this is a variable-size object with a pseudo to address it,
      put that pseudo into the stack, if the var is nonlocal.  */
-  if (DECL_NONLOCAL (decl)
+  if (TREE_CODE (decl) != SAVE_EXPR && DECL_NONLOCAL (decl)
       && GET_CODE (reg) == MEM
       && GET_CODE (XEXP (reg, 0)) == REG
       && REGNO (XEXP (reg, 0)) > LAST_VIRTUAL_REGISTER)
@@ -1395,11 +1397,8 @@ put_var_into_stack (decl)
       if (can_use_addressof)
        gen_mem_addressof (reg, decl);
       else
-       put_reg_into_stack (function, reg, TREE_TYPE (decl),
-                           promoted_mode, decl_mode,
-                           TREE_SIDE_EFFECTS (decl), 0,
-                           TREE_USED (decl) || DECL_INITIAL (decl) != 0,
-                           0);
+       put_reg_into_stack (function, reg, TREE_TYPE (decl), promoted_mode,
+                           decl_mode, volatilep, 0, usedp, 0);
     }
   else if (GET_CODE (reg) == CONCAT)
     {
@@ -1410,29 +1409,19 @@ put_var_into_stack (decl)
 #ifdef FRAME_GROWS_DOWNWARD
       /* Since part 0 should have a lower address, do it second.  */
       put_reg_into_stack (function, XEXP (reg, 1), part_type, part_mode,
-                         part_mode, TREE_SIDE_EFFECTS (decl), 0,
-                         TREE_USED (decl) || DECL_INITIAL (decl) != 0,
-                         0);
+                         part_mode, volatilep, 0, usedp, 0);
       put_reg_into_stack (function, XEXP (reg, 0), part_type, part_mode,
-                         part_mode, TREE_SIDE_EFFECTS (decl), 0,
-                         TREE_USED (decl) || DECL_INITIAL (decl) != 0,
-                         0);
+                         part_mode, volatilep, 0, usedp, 0);
 #else
       put_reg_into_stack (function, XEXP (reg, 0), part_type, part_mode,
-                         part_mode, TREE_SIDE_EFFECTS (decl), 0,
-                         TREE_USED (decl) || DECL_INITIAL (decl) != 0,
-                         0);
+                         part_mode, volatilep, 0, usedp, 0);
       put_reg_into_stack (function, XEXP (reg, 1), part_type, part_mode,
-                         part_mode, TREE_SIDE_EFFECTS (decl), 0,
-                         TREE_USED (decl) || DECL_INITIAL (decl) != 0,
-                         0);
+                         part_mode, volatilep, 0, usedp, 0);
 #endif
 
       /* 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);
-      MEM_SET_IN_STRUCT_P (reg, AGGREGATE_TYPE_P (TREE_TYPE (decl)));
+      set_mem_attributes (reg, decl, 1);
 
       /* The two parts are in memory order already.
         Use the lower parts address as ours.  */
@@ -2840,9 +2829,14 @@ put_addressof_into_stack (r, ht)
     abort ();
 
   put_reg_into_stack (0, reg, TREE_TYPE (decl), GET_MODE (reg),
-                     DECL_MODE (decl), TREE_SIDE_EFFECTS (decl),
+                     GET_MODE (reg),
+                     (TREE_CODE (decl) != SAVE_EXPR
+                      && TREE_THIS_VOLATILE (decl)),
                      ADDRESSOF_REGNO (r),
-                     TREE_USED (decl) || DECL_INITIAL (decl) != 0, ht);
+                     (TREE_USED (decl)
+                      || (TREE_CODE (decl) != SAVE_EXPR
+                          && DECL_INITIAL (decl) != 0)),
+                     ht);
 }
 
 /* List of replacements made below in purge_addressof_1 when creating
@@ -4168,7 +4162,6 @@ assign_parms (fndecl)
 
   for (parm = fnargs; parm; parm = TREE_CHAIN (parm))
     {
-      int aggregate = AGGREGATE_TYPE_P (TREE_TYPE (parm));
       struct args_size stack_offset;
       struct args_size arg_size;
       int passed_pointer = 0;
@@ -4221,7 +4214,8 @@ assign_parms (fndecl)
         type of the first field for the tests below.  We have already
         verified that the modes are the same.  */
       if (DECL_TRANSPARENT_UNION (parm)
-         || TYPE_TRANSPARENT_UNION (passed_type))
+         || (TREE_CODE (passed_type) == UNION_TYPE
+             && TYPE_TRANSPARENT_UNION (passed_type)))
        passed_type = TREE_TYPE (TYPE_FIELDS (passed_type));
 
       /* See if this arg was passed by invisible reference.  It is if
@@ -4325,12 +4319,7 @@ assign_parms (fndecl)
                                                  internal_arg_pointer,
                                                  offset_rtx));
 
-       /* If this is a memory ref that contains aggregate components,
-          mark it as such for cse and loop optimize.  Likewise if it
-          is readonly.  */
-       MEM_SET_IN_STRUCT_P (stack_parm, aggregate);
-       RTX_UNCHANGING_P (stack_parm) = TREE_READONLY (parm);
-       MEM_ALIAS_SET (stack_parm) = get_alias_set (parm);
+       set_mem_attributes (stack_parm, parm, 1);
       }
 
       /* If this parameter was passed both in registers and in the stack,
@@ -4435,38 +4424,6 @@ assign_parms (fndecl)
          && nominal_mode != BLKmode && nominal_mode != passed_mode)
        stack_parm = 0;
 
-#if 0
-      /* Now adjust STACK_PARM to the mode and precise location
-        where this parameter should live during execution,
-        if we discover that it must live in the stack during execution.
-        To make debuggers happier on big-endian machines, we store
-        the value in the last bytes of the space available.  */
-
-      if (nominal_mode != BLKmode && nominal_mode != passed_mode
-         && stack_parm != 0)
-       {
-         rtx offset_rtx;
-
-         if (BYTES_BIG_ENDIAN
-             && GET_MODE_SIZE (nominal_mode) < UNITS_PER_WORD)
-           stack_offset.constant += (GET_MODE_SIZE (passed_mode)
-                                     - GET_MODE_SIZE (nominal_mode));
-
-         offset_rtx = ARGS_SIZE_RTX (stack_offset);
-         if (offset_rtx == const0_rtx)
-           stack_parm = gen_rtx_MEM (nominal_mode, internal_arg_pointer);
-         else
-           stack_parm = gen_rtx_MEM (nominal_mode,
-                                     gen_rtx_PLUS (Pmode,
-                                                   internal_arg_pointer,
-                                                   offset_rtx));
-
-         /* If this is a memory ref that contains aggregate components,
-            mark it as such for cse and loop optimize.  */
-         MEM_SET_IN_STRUCT_P (stack_parm, aggregate);
-       }
-#endif /* 0 */
-
       /* ENTRY_PARM is an RTX for the parameter as it arrives,
         in the mode in which it arrives.
         STACK_PARM is an RTX for a stack slot where the parameter can live
@@ -4506,18 +4463,12 @@ assign_parms (fndecl)
                  stack_parm
                    = assign_stack_local (GET_MODE (entry_parm),
                                          size_stored, 0);
-
-                 /* If this is a memory ref that contains aggregate
-                    components, mark it as such for cse and loop optimize.  */
-                 MEM_SET_IN_STRUCT_P (stack_parm, aggregate);
+                 set_mem_attributes (stack_parm, parm, 1);
                }
 
              else if (PARM_BOUNDARY % BITS_PER_WORD != 0)
                abort ();
 
-             if (TREE_READONLY (parm))
-               RTX_UNCHANGING_P (stack_parm) = 1;
-
              /* Handle calls that pass values in multiple non-contiguous
                 locations.  The Irix 6 ABI has examples of this.  */
              if (GET_CODE (entry_parm) == PARALLEL)
@@ -4566,7 +4517,7 @@ assign_parms (fndecl)
            {
              DECL_RTL (parm)
                = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (passed_type)), parmreg);
-             MEM_SET_IN_STRUCT_P (DECL_RTL (parm), aggregate);
+             set_mem_attributes (DECL_RTL (parm), parm, 1);
            }
          else
            DECL_RTL (parm) = parmreg;
@@ -4672,8 +4623,7 @@ assign_parms (fndecl)
              else
                copy = assign_stack_temp (TYPE_MODE (type),
                                          int_size_in_bytes (type), 1);
-             MEM_SET_IN_STRUCT_P (copy, AGGREGATE_TYPE_P (type));
-             RTX_UNCHANGING_P (copy) = TREE_READONLY (parm);
+             set_mem_attributes (copy, parm, 1);
 
              store_expr (parm, copy, 0);
              emit_move_insn (parmreg, XEXP (copy, 0));
@@ -4824,9 +4774,7 @@ assign_parms (fndecl)
                  stack_parm
                    = assign_stack_local (GET_MODE (entry_parm),
                                          GET_MODE_SIZE (GET_MODE (entry_parm)), 0);
-                 /* If this is a memory ref that contains aggregate components,
-                    mark it as such for cse and loop optimize.  */
-                 MEM_SET_IN_STRUCT_P (stack_parm, aggregate);
+                 set_mem_attributes (stack_parm, parm, 1);
                }
 
              if (promoted_mode != nominal_mode)
@@ -4863,19 +4811,12 @@ assign_parms (fndecl)
       if (parm == function_result_decl)
        {
          tree result = DECL_RESULT (fndecl);
-         tree restype = TREE_TYPE (result);
 
          DECL_RTL (result)
            = gen_rtx_MEM (DECL_MODE (result), DECL_RTL (parm));
 
-         MEM_SET_IN_STRUCT_P (DECL_RTL (result), 
-                              AGGREGATE_TYPE_P (restype));
+         set_mem_attributes (DECL_RTL (result), result, 1);
        }
-
-      if (TREE_THIS_VOLATILE (parm))
-       MEM_VOLATILE_P (DECL_RTL (parm)) = 1;
-      if (TREE_READONLY (parm))
-       RTX_UNCHANGING_P (DECL_RTL (parm)) = 1;
     }
 
   /* Output all parameter conversion instructions (possibly including calls)
@@ -5398,7 +5339,9 @@ fix_lexical_addr (addr, var)
       addr = fix_lexical_addr (XEXP (fp->x_arg_pointer_save_area, 0), var);
       addr = memory_address (Pmode, addr);
 
-      base = copy_to_reg (gen_rtx_MEM (Pmode, addr));
+      base = gen_rtx_MEM (Pmode, addr);
+      MEM_ALIAS_SET (base) = get_frame_alias_set ();
+      base = copy_to_reg (base);
 #else
       displacement += (FIRST_PARM_OFFSET (context) - STARTING_FRAME_OFFSET);
       base = lookup_static_chain (var);
@@ -6149,10 +6092,8 @@ expand_function_start (subr, parms_have_cleanups)
        {
          DECL_RTL (DECL_RESULT (subr))
            = gen_rtx_MEM (DECL_MODE (DECL_RESULT (subr)), value_address);
-         MEM_SET_IN_STRUCT_P (DECL_RTL (DECL_RESULT (subr)),
-                              AGGREGATE_TYPE_P (TREE_TYPE
-                                                (DECL_RESULT
-                                                 (subr))));
+         set_mem_attributes (DECL_RTL (DECL_RESULT (subr)),
+                             DECL_RESULT (subr), 1);
        }
     }
   else if (DECL_MODE (DECL_RESULT (subr)) == VOIDmode)
@@ -6247,9 +6188,9 @@ expand_function_start (subr, parms_have_cleanups)
 #ifdef FRAME_GROWS_DOWNWARD
          last_ptr = plus_constant (last_ptr, - GET_MODE_SIZE (Pmode));
 #endif
-         last_ptr = copy_to_reg (gen_rtx_MEM (Pmode,
-                                              memory_address (Pmode,
-                                                              last_ptr)));
+         last_ptr = gen_rtx_MEM (Pmode, memory_address (Pmode, last_ptr));
+         MEM_ALIAS_SET (last_ptr) = get_frame_alias_set ();
+         last_ptr = copy_to_reg (last_ptr);
 
          /* If we are not optimizing, ensure that we know that this
             piece of context is live over the entire function.  */
@@ -6319,14 +6260,25 @@ diddle_return_value (doit, arg)
      void *arg;
 {
   rtx outgoing = current_function_return_rtx;
+  int pcc;
 
   if (! outgoing)
     return;
 
-  if (GET_CODE (outgoing) == REG
-      && REGNO (outgoing) >= FIRST_PSEUDO_REGISTER)
+  pcc = (current_function_returns_struct
+         || current_function_returns_pcc_struct);
+
+  if ((GET_CODE (outgoing) == REG
+       && REGNO (outgoing) >= FIRST_PSEUDO_REGISTER)
+      || pcc)
     {
       tree type = TREE_TYPE (DECL_RESULT (current_function_decl));
+
+      /* A PCC-style return returns a pointer to the memory in which
+        the structure is stored.  */
+      if (pcc)
+       type = build_pointer_type (type);
+
 #ifdef FUNCTION_OUTGOING_VALUE
       outgoing = FUNCTION_OUTGOING_VALUE (type, current_function_decl);
 #else
@@ -6337,6 +6289,7 @@ diddle_return_value (doit, arg)
       if (GET_MODE (outgoing) == BLKmode)
        PUT_MODE (outgoing,
                  GET_MODE (DECL_RTL (DECL_RESULT (current_function_decl))));
+      REG_FUNCTION_VALUE_P (outgoing) = 1;
     }
 
   if (GET_CODE (outgoing) == REG)
@@ -6786,19 +6739,24 @@ sibcall_epilogue_contains (insn)
    block_for_insn appropriately.  */
 
 static void
-emit_return_into_block (bb)
+emit_return_into_block (bb, line_note)
      basic_block bb;
+     rtx line_note;
 {
   rtx p, end;
 
-  end = emit_jump_insn_after (gen_return (), bb->end);
   p = NEXT_INSN (bb->end); 
+  end = emit_jump_insn_after (gen_return (), bb->end);
+  if (line_note)
+    emit_line_note_after (NOTE_SOURCE_FILE (line_note),
+                         NOTE_LINE_NUMBER (line_note), bb->end);
+
   while (1)
     {
       set_block_for_insn (p, bb);
-      if (p == end)
+      if (p == bb->end)
        break;
-      p = NEXT_INSN (p);
+      p = PREV_INSN (p);
     }
   bb->end = end;
 }
@@ -6812,15 +6770,19 @@ void
 thread_prologue_and_epilogue_insns (f)
      rtx f ATTRIBUTE_UNUSED;
 {
-  int insertted = 0;
+  int inserted = 0;
   edge e;
   rtx seq;
+#ifdef HAVE_prologue
+  rtx prologue_end = NULL_RTX;
+#endif
+#if defined (HAVE_epilogue) || defined(HAVE_return)
+  rtx epilogue_end = NULL_RTX;
+#endif
 
 #ifdef HAVE_prologue
   if (HAVE_prologue)
     {
-      rtx insn;
-
       start_sequence ();
       seq = gen_prologue();
       emit_insn (seq);
@@ -6829,26 +6791,7 @@ thread_prologue_and_epilogue_insns (f)
       if (GET_CODE (seq) != SEQUENCE)
        seq = get_insns ();
       record_insns (seq, &prologue);
-      emit_note (NULL, NOTE_INSN_PROLOGUE_END);
-
-      /* GDB handles `break f' by setting a breakpoint on the first
-        line note *after* the prologue.  That means that we should
-        insert a line note here; otherwise, if the next line note
-        comes part way into the next block, GDB will skip all the way
-        to that point.  */
-      insn = next_nonnote_insn (f);
-      while (insn)
-       {
-         if (GET_CODE (insn) == NOTE 
-             && NOTE_LINE_NUMBER (insn) >= 0)
-           {
-             emit_line_note_force (NOTE_SOURCE_FILE (insn),
-                                   NOTE_LINE_NUMBER (insn));
-             break;
-           }
-
-         insn = PREV_INSN (insn);
-       }
+      prologue_end = emit_note (NULL, NOTE_INSN_PROLOGUE_END);
 
       seq = gen_sequence ();
       end_sequence ();
@@ -6862,7 +6805,7 @@ thread_prologue_and_epilogue_insns (f)
            abort ();
 
          insert_insn_on_edge (seq, ENTRY_BLOCK_PTR->succ);
-         insertted = 1;
+         inserted = 1;
        }
       else
        emit_insn_after (seq, f);
@@ -6908,6 +6851,19 @@ thread_prologue_and_epilogue_insns (f)
 
       if (last->head == label && GET_CODE (label) == CODE_LABEL)
        {
+          rtx epilogue_line_note = NULL_RTX;
+
+         /* Locate the line number associated with the closing brace,
+            if we can find one.  */
+         for (seq = get_last_insn ();
+              seq && ! active_insn_p (seq);
+              seq = PREV_INSN (seq))
+           if (GET_CODE (seq) == NOTE && NOTE_LINE_NUMBER (seq) > 0)
+             {
+               epilogue_line_note = seq;
+               break;
+             }
+
          for (e = last->pred; e ; e = e_next)
            {
              basic_block bb = e->src;
@@ -6925,7 +6881,7 @@ thread_prologue_and_epilogue_insns (f)
                 with a simple return instruction.  */
              if (simplejump_p (jump))
                {
-                 emit_return_into_block (bb);
+                 emit_return_into_block (bb, epilogue_line_note);
                  flow_delete_insn (jump);
                }
 
@@ -6957,29 +6913,17 @@ thread_prologue_and_epilogue_insns (f)
                continue;
 
              /* Fix up the CFG for the successful change we just made.  */
-             remove_edge (e);
-             make_edge (NULL, bb, EXIT_BLOCK_PTR, 0);
+             redirect_edge_succ (e, EXIT_BLOCK_PTR);
            }
 
          /* Emit a return insn for the exit fallthru block.  Whether
             this is still reachable will be determined later.  */
 
          emit_barrier_after (last->end);
-         emit_return_into_block (last);
+         emit_return_into_block (last, epilogue_line_note);
+         epilogue_end = last->end;
+          goto epilogue_done;
        }
-      else 
-       {
-         /* The exit block wasn't empty.  We have to use insert_insn_on_edge,
-            as it may be the exit block can go elsewhere as well
-            as exiting.  */
-         start_sequence ();
-         emit_jump_insn (gen_return ());
-         seq = gen_sequence ();
-         end_sequence ();
-         insert_insn_on_edge (seq, e);
-         insertted = 1;
-       }
-      goto epilogue_done;
     }
 #endif
 #ifdef HAVE_epilogue
@@ -6997,7 +6941,7 @@ thread_prologue_and_epilogue_insns (f)
        goto epilogue_done;
 
       start_sequence ();
-      emit_note (NULL, NOTE_INSN_EPILOGUE_BEG);
+      epilogue_end = emit_note (NULL, NOTE_INSN_EPILOGUE_BEG);
 
       seq = gen_epilogue ();
       emit_jump_insn (seq);
@@ -7011,12 +6955,12 @@ thread_prologue_and_epilogue_insns (f)
       end_sequence();
 
       insert_insn_on_edge (seq, e);
-      insertted = 1;
+      inserted = 1;
     }
 #endif
 epilogue_done:
 
-  if (insertted)
+  if (inserted)
     commit_edge_insertions ();
 
 #ifdef HAVE_sibcall_epilogue
@@ -7049,6 +6993,73 @@ epilogue_done:
                    ? seq : newinsn, &sibcall_epilogue);
     }
 #endif
+
+#ifdef HAVE_prologue
+  if (prologue_end)
+    {
+      rtx insn, prev;
+
+      /* GDB handles `break f' by setting a breakpoint on the first
+        line note after the prologue.  Which means (1) that if
+        there are line number notes before where we inserted the
+        prologue we should move them, and (2) we should generate a
+        note before the end of the first basic block, if there isn't
+        one already there.  */
+
+      for (insn = prologue_end; insn ; insn = prev)
+       {
+         prev = PREV_INSN (insn);
+         if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
+           {
+             /* Note that we cannot reorder the first insn in the
+                chain, since rest_of_compilation relies on that
+                remaining constant.  */
+             if (prev == NULL)
+               break;
+             reorder_insns (insn, insn, prologue_end);
+           }
+       }
+
+      /* Find the last line number note in the first block.  */
+      for (insn = BASIC_BLOCK (0)->end;
+          insn != prologue_end;
+          insn = PREV_INSN (insn))
+       if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
+         break;
+
+      /* If we didn't find one, make a copy of the first line number
+        we run across.  */
+      if (! insn)
+       {
+         for (insn = next_active_insn (prologue_end);
+              insn;
+              insn = PREV_INSN (insn))
+           if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
+             {
+               emit_line_note_after (NOTE_SOURCE_FILE (insn),
+                                     NOTE_LINE_NUMBER (insn),
+                                     prologue_end);
+               break;
+             }
+       }
+    }
+#endif
+#ifdef HAVE_epilogue
+  if (epilogue_end)
+    {
+      rtx insn, next;
+
+      /* Similarly, move any line notes that appear after the epilogue.
+         There is no need, however, to be quite so anal about the existance
+        of such a note.  */
+      for (insn = epilogue_end; insn ; insn = next)
+       {
+         next = NEXT_INSN (insn);
+         if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
+           reorder_insns (insn, insn, PREV_INSN (epilogue_end));
+       }
+    }
+#endif
 }
 
 /* Reposition the prologue-end and epilogue-begin notes after instruction