OSDN Git Service

Add -mabi=n32 support.
[pf3gnuchains/gcc-fork.git] / gcc / final.c
index 460500e..47d4644 100644 (file)
@@ -1,5 +1,5 @@
 /* Convert RTL to assembler code and output it, for GNU compiler.
-   Copyright (C) 1987, 1988, 1989, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 89, 92-5, 1996 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -15,7 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 /* This is the final pass of the compiler.
@@ -43,24 +44,29 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
    directly as assembler code by the macros FUNCTION_PROLOGUE and
    FUNCTION_EPILOGUE.  Those instructions never exist as rtl.  */
 
-#include <stdio.h>
 #include "config.h"
-#include "gvarargs.h"
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include <stdio.h>
+#include <ctype.h>
+
+#include "tree.h"
 #include "rtl.h"
 #include "regs.h"
 #include "insn-config.h"
+#include "insn-flags.h"
 #include "insn-attr.h"
 #include "insn-codes.h"
 #include "recog.h"
 #include "conditions.h"
 #include "flags.h"
 #include "real.h"
-#include "output.h"
 #include "hard-reg-set.h"
-
-#ifndef ASM_STABD_OP
-#define ASM_STABD_OP ".stabd"
-#endif
+#include "defaults.h"
+#include "output.h"
 
 /* Get N_SLINE and N_SOL from stab.h if we can expect the file to exist.  */
 #if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
@@ -100,20 +106,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #define ASM_COMMENT_START ";#"
 #endif
 
-rtx peephole ();
-void output_asm_insn ();
-rtx alter_subreg ();
-static int alter_cond ();
-void output_asm_label ();
-static void output_operand ();
-void output_address ();
-void output_addr_const ();
-static void output_source_line ();
-rtx final_scan_insn ();
-void profile_function ();
-
-#ifdef HAVE_ATTR_length
-static int asm_insn_count ();
+/* Is the given character a logical line separator for the assembler?  */
+#ifndef IS_ASM_LOGICAL_LINE_SEPARATOR
+#define IS_ASM_LOGICAL_LINE_SEPARATOR(C) ((C) == ';')
 #endif
 
 /* Nonzero means this function is a leaf function, with no function calls. 
@@ -121,20 +116,21 @@ static int asm_insn_count ();
    and FUNCTION_EPILOGUE.  Always zero, unless set by some action.  */
 int leaf_function;
 
-int leaf_function_p ();
-
-#ifdef LEAF_REGISTERS
-int only_leaf_regs_used ();
-static void leaf_renumber_regs ();
-void leaf_renumber_regs_insn ();
-#endif
-
 /* Last insn processed by final_scan_insn.  */
 static rtx debug_insn = 0;
 
 /* Line number of last NOTE.  */
 static int last_linenum;
 
+/* Highest line number in current block.  */
+static int high_block_linenum;
+
+/* Likewise for function.  */
+static int high_function_linenum;
+
+/* Filename of last NOTE.  */
+static char *last_filename;
+
 /* Number of basic blocks seen so far;
    used if profile_block_flag is set.  */
 static int count_basic_blocks;
@@ -161,7 +157,7 @@ static int new_block = 1;
    and assume that they will both give the same number to each block.
    Final uses these sequence numbers to generate assembler label names
    LBBnnn and LBEnnn for the beginning and end of the symbol-block.
-   Dbxout uses the sequence nunbers to generate references to the same labels
+   Dbxout uses the sequence numbers to generate references to the same labels
    from the dbx debugging information.
 
    Sdb records this level at the beginning of each function,
@@ -234,9 +230,58 @@ static int app_on;
 
 rtx final_sequence;
 
+#ifdef ASSEMBLER_DIALECT
+
+/* Number of the assembler dialect to use, starting at 0.  */
+static int dialect_number;
+#endif
+
 /* Indexed by line number, nonzero if there is a note for that line.  */
 
 static char *line_note_exists;
+
+/* Linked list to hold line numbers for each basic block.  */
+
+struct bb_list {
+  struct bb_list *next;                /* pointer to next basic block */
+  int line_num;                        /* line number */
+  int file_label_num;          /* LPBC<n> label # for stored filename */
+  int func_label_num;          /* LPBC<n> label # for stored function name */
+};
+
+static struct bb_list *bb_head = 0;            /* Head of basic block list */
+static struct bb_list **bb_tail = &bb_head;    /* Ptr to store next bb ptr */
+static int bb_file_label_num   = -1;           /* Current label # for file */
+static int bb_func_label_num   = -1;           /* Current label # for func */
+
+/* Linked list to hold the strings for each file and function name output.  */
+
+struct bb_str {
+  struct bb_str *next;         /* pointer to next string */
+  char *string;                        /* string */
+  int label_num;               /* label number */
+  int length;                  /* string length */
+};
+
+extern rtx peephole            PROTO((rtx));
+
+static struct bb_str *sbb_head = 0;            /* Head of string list.  */
+static struct bb_str **sbb_tail        = &sbb_head;    /* Ptr to store next bb str */
+static int sbb_label_num       = 0;            /* Last label used */
+
+static int asm_insn_count      PROTO((rtx));
+static void profile_function   PROTO((FILE *));
+static void profile_after_prologue PROTO((FILE *));
+static void add_bb             PROTO((FILE *));
+static int add_bb_string       PROTO((char *, int));
+static void output_source_line PROTO((FILE *, rtx));
+static rtx walk_alter_subreg   PROTO((rtx));
+static int alter_cond          PROTO((rtx));
+static void output_asm_name    PROTO((void));
+static void output_operand     PROTO((rtx, int));
+static void leaf_renumber_regs PROTO((rtx));
+
+extern char *getpwd ();
 \f
 /* Initialize data in final at the beginning of a compilation.  */
 
@@ -249,6 +294,10 @@ init_final (filename)
   max_block_depth = 20;
   pending_blocks = (int *) xmalloc (20 * sizeof *pending_blocks);
   final_sequence = 0;
+
+#ifdef ASSEMBLER_DIALECT
+  dialect_number = ASSEMBLER_DIALECT;
+#endif
 }
 
 /* Called at end of source file,
@@ -262,64 +311,192 @@ end_final (filename)
 
   if (profile_block_flag)
     {
-      char name[12];
+      char name[20];
+      int align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
+      int size = (POINTER_SIZE / BITS_PER_UNIT) * count_basic_blocks;
+      int rounded = size;
+      struct bb_list *ptr;
+      struct bb_str *sptr;
+
+      rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;
+      rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
+                * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
 
       data_section ();
 
-      /* Output the main header, of 6 words:
-        0:  1 if this file's initialized, else 0.
-        1:  address of file name.
-        2:  address of table of counts.
-        4:  number of counts in the table.
-        5:  always 0, for compatibility with Sun.
-        6:  extra word added by GNU: address of address table
-             which contains addresses of basic blocks,
-             in parallel with the table of counts.  */
-      ASM_OUTPUT_ALIGN (asm_out_file,
-                       exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
+      /* Output the main header, of 11 words:
+        0:  1 if this file is initialized, else 0.
+        1:  address of file name (LPBX1).
+        2:  address of table of counts (LPBX2).
+        3:  number of counts in the table.
+        4:  always 0, for compatibility with Sun.
+
+         The following are GNU extensions:
+
+        5:  address of table of start addrs of basic blocks (LPBX3).
+        6:  Number of bytes in this header.
+        7:  address of table of function names (LPBX4).
+        8:  address of table of line numbers (LPBX5) or 0.
+        9:  address of table of file names (LPBX6) or 0.
+       10:  space reserved for basic block profiling. */
+
+      ASM_OUTPUT_ALIGN (asm_out_file, align);
 
       ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 0);
+      /* zero word */
       assemble_integer (const0_rtx, UNITS_PER_WORD, 1);
+
+      /* address of filename */
       ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 1);
       assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name), UNITS_PER_WORD, 1);
+
+      /* address of count table */
       ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2);
       assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name), UNITS_PER_WORD, 1);
-      assemble_integer (gen_rtx (CONST_INT, VOIDmode, count_basic_blocks),
-                       UNITS_PER_WORD, 1);
+
+      /* count of the # of basic blocks */
+      assemble_integer (GEN_INT (count_basic_blocks), UNITS_PER_WORD, 1);
+
+      /* zero word (link field) */
       assemble_integer (const0_rtx, UNITS_PER_WORD, 1);
+
+      /* address of basic block start address table */
       ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 3);
       assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name), UNITS_PER_WORD, 1);
 
-      /* Output the file name.  */
+      /* byte count for extended structure.  */
+      assemble_integer (GEN_INT (11 * UNITS_PER_WORD), UNITS_PER_WORD, 1);
+
+      /* address of function name table */
+      ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 4);
+      assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name), UNITS_PER_WORD, 1);
+
+      /* address of line number and filename tables if debugging.  */
+      if (write_symbols != NO_DEBUG)
+       {
+         ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 5);
+         assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name), UNITS_PER_WORD, 1);
+         ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 6);
+         assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name), UNITS_PER_WORD, 1);
+       }
+      else
+       {
+         assemble_integer (const0_rtx, UNITS_PER_WORD, 1);
+         assemble_integer (const0_rtx, UNITS_PER_WORD, 1);
+       }
+
+      /* space for extension ptr (link field) */
+      assemble_integer (const0_rtx, UNITS_PER_WORD, 1);
+
+      /* Output the file name changing the suffix to .d for Sun tcov
+        compatibility.  */
       ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 1);
       {
-       int len = strlen (filename);
-       char *data_file = (char *) alloca (len + 3);
-       strcpy (data_file, filename);
+       char *cwd = getpwd ();
+       int len = strlen (filename) + strlen (cwd) + 1;
+       char *data_file = (char *) alloca (len + 4);
+
+       strcpy (data_file, cwd);
+       strcat (data_file, "/");
+       strcat (data_file, filename);
        strip_off_ending (data_file, len);
        strcat (data_file, ".d");
        assemble_string (data_file, strlen (data_file) + 1);
       }
 
-      /* Realign data section.  */
-      ASM_OUTPUT_ALIGN (asm_out_file,
-                       exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
-
       /* Make space for the table of counts.  */
-      ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 2);
-      assemble_zeros (INT_TYPE_SIZE / BITS_PER_UNIT * count_basic_blocks);
+      if (size == 0)
+       {
+         /* Realign data section.  */
+         ASM_OUTPUT_ALIGN (asm_out_file, align);
+         ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 2);
+         if (size != 0)
+           assemble_zeros (size);
+       }
+      else
+       {
+         ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2);
+#ifdef ASM_OUTPUT_SHARED_LOCAL
+         if (flag_shared_data)
+           ASM_OUTPUT_SHARED_LOCAL (asm_out_file, name, size, rounded);
+         else
+#endif
+#ifdef ASM_OUTPUT_ALIGNED_LOCAL
+           ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size,
+                                     BIGGEST_ALIGNMENT);
+#else
+           ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
+#endif
+       }
 
-      /* Output the table of addresses.  */
+      /* Output any basic block strings */
       readonly_data_section ();
+      if (sbb_head)
+       {
+         ASM_OUTPUT_ALIGN (asm_out_file, align);
+         for (sptr = sbb_head; sptr != 0; sptr = sptr->next)
+           {
+             ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBC", sptr->label_num);
+             assemble_string (sptr->string, sptr->length);
+           }
+       }
+
+      /* Output the table of addresses.  */
+      /* Realign in new section */
+      ASM_OUTPUT_ALIGN (asm_out_file, align);
       ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 3);
       for (i = 0; i < count_basic_blocks; i++)
        {
-         char name[12];
          ASM_GENERATE_INTERNAL_LABEL (name, "LPB", i);
          assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name),
                            UNITS_PER_WORD, 1);
        }
 
+      /* Output the table of function names.  */
+      ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 4);
+      for ((ptr = bb_head), (i = 0); ptr != 0; (ptr = ptr->next), i++)
+       {
+         if (ptr->func_label_num >= 0)
+           {
+             ASM_GENERATE_INTERNAL_LABEL (name, "LPBC", ptr->func_label_num);
+             assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name),
+                               UNITS_PER_WORD, 1);
+           }
+         else
+           assemble_integer (const0_rtx, UNITS_PER_WORD, 1);
+       }
+
+      for ( ; i < count_basic_blocks; i++)
+       assemble_integer (const0_rtx, UNITS_PER_WORD, 1);
+
+      if (write_symbols != NO_DEBUG)
+       {
+         /* Output the table of line numbers.  */
+         ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 5);
+         for ((ptr = bb_head), (i = 0); ptr != 0; (ptr = ptr->next), i++)
+           assemble_integer (GEN_INT (ptr->line_num), UNITS_PER_WORD, 1);
+
+         for ( ; i < count_basic_blocks; i++)
+           assemble_integer (const0_rtx, UNITS_PER_WORD, 1);
+
+         /* Output the table of file names.  */
+         ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 6);
+         for ((ptr = bb_head), (i = 0); ptr != 0; (ptr = ptr->next), i++)
+           {
+             if (ptr->file_label_num >= 0)
+               {
+                 ASM_GENERATE_INTERNAL_LABEL (name, "LPBC", ptr->file_label_num);
+                 assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name),
+                                   UNITS_PER_WORD, 1);
+               }
+             else
+               assemble_integer (const0_rtx, UNITS_PER_WORD, 1);
+           }
+
+         for ( ; i < count_basic_blocks; i++)
+           assemble_integer (const0_rtx, UNITS_PER_WORD, 1);
+       }
+
       /* End with the address of the table of addresses,
         so we can find it easily, as the last word in the file's text.  */
       ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 3);
@@ -340,7 +517,7 @@ app_enable ()
     }
 }
 
-/* Enable APP processing of subsequent output.
+/* Disable APP processing of subsequent output.
    Called from varasm.c before most kinds of output.  */
 
 void
@@ -380,7 +557,7 @@ int *insn_addresses;
 /* Address of insn being processed.  Used by `insn_current_length'.  */
 int insn_current_address;
 
-/* Indicate the branch shortening hasn't yet been done.  */
+/* Indicate that branch shortening hasn't yet been done.  */
 
 void
 init_insn_lengths ()
@@ -439,7 +616,7 @@ get_attr_length (insn)
          return 0;
 
        else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0)
-         length = asm_insn_count (insn) * insn_default_length (insn);
+         length = asm_insn_count (body) * insn_default_length (insn);
        else if (GET_CODE (body) == SEQUENCE)
          for (i = 0; i < XVECLEN (body, 0); i++)
            length += get_attr_length (XVECEXP (body, 0, i));
@@ -524,13 +701,15 @@ shorten_branches (first)
       else if (GET_CODE (body) == SEQUENCE)
        {
          int i;
-
+         int const_delay_slots;
+#ifdef DELAY_SLOTS
+         const_delay_slots = const_num_delay_slots (XVECEXP (body, 0, 0));
+#else
+         const_delay_slots = 0;
+#endif
          /* Inside a delay slot sequence, we do not do any branch shortening
-            (on the only machine known to have both variable-length branches
-            and delay slots, the ROMP, branch-with-execute is the same size
-            as the maximum branch anyway).  So we only have to handle normal
-            insns (actually, reorg never puts ASM insns in a delay slot, but
-            we don't take advantage of that knowledge here).  */
+            if the shortening could change the number of delay slots
+            of the branch. */
          for (i = 0; i < XVECLEN (body, 0); i++)
            {
              rtx inner_insn = XVECEXP (body, 0, i);
@@ -544,7 +723,16 @@ shorten_branches (first)
                inner_length = insn_default_length (inner_insn);
              
              insn_lengths[inner_uid] = inner_length;
-             varying_length[inner_uid] = 0;
+             if (const_delay_slots)
+               {
+                 if ((varying_length[inner_uid]
+                      = insn_variable_length_p (inner_insn)) != 0)
+                   varying_length[uid] = 1;
+                 insn_addresses[inner_uid] = (insn_current_address +
+                                              insn_lengths[uid]);
+               }
+             else
+               varying_length[inner_uid] = 0;
              insn_lengths[uid] += inner_length;
            }
        }
@@ -569,22 +757,72 @@ shorten_branches (first)
       something_changed = 0;
       for (insn_current_address = FIRST_INSN_ADDRESS, insn = first;
           insn != 0;
-          insn_current_address += insn_lengths[uid], insn = NEXT_INSN (insn))
+          insn = NEXT_INSN (insn))
        {
          int new_length;
+         int tmp_length;
 
          uid = INSN_UID (insn);
          insn_addresses[uid] = insn_current_address;
          if (! varying_length[uid])
-           continue;
+           {
+             insn_current_address += insn_lengths[uid];
+             continue;
+           }
+         if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE)
+           {
+             int i;
+             
+             body = PATTERN (insn);
+             new_length = 0;
+             for (i = 0; i < XVECLEN (body, 0); i++)
+               {
+                 rtx inner_insn = XVECEXP (body, 0, i);
+                 int inner_uid = INSN_UID (inner_insn);
+                 int inner_length;
+
+                 insn_addresses[inner_uid] = insn_current_address;
+
+                 /* insn_current_length returns 0 for insns with a
+                    non-varying length.  */
+                 if (! varying_length[inner_uid])
+                   inner_length = insn_lengths[inner_uid];
+                 else
+                   inner_length = insn_current_length (inner_insn);
+
+                 if (inner_length != insn_lengths[inner_uid])
+                   {
+                     insn_lengths[inner_uid] = inner_length;
+                     something_changed = 1;
+                   }
+                 insn_current_address += insn_lengths[inner_uid];
+                 new_length += inner_length;
+               }
+           }
+         else
+           {
+             new_length = insn_current_length (insn);
+             insn_current_address += new_length;
+           }
+
+#ifdef SHORTEN_WITH_ADJUST_INSN_LENGTH
+#ifdef ADJUST_INSN_LENGTH
+         /* If needed, do any adjustment.  */
+         tmp_length = new_length;
+         ADJUST_INSN_LENGTH (insn, new_length);
+         insn_current_address += (new_length - tmp_length);
+#endif
+#endif
 
-         new_length = insn_current_length (insn);
          if (new_length != insn_lengths[uid])
            {
              insn_lengths[uid] = new_length;
              something_changed = 1;
            }
        }
+      /* For a non-optimizing compile, do only a single pass.  */
+      if (!optimize)
+       break;
     }
 #endif /* HAVE_ATTR_length */
 }
@@ -601,9 +839,14 @@ asm_insn_count (body)
   char *template;
   int count = 1;
 
-  for (template = decode_asm_operands (body, 0, 0, 0, 0);
-       *template; template++)
-    if (*template == ';' || *template == '\n')
+  if (GET_CODE (body) == ASM_INPUT)
+    template = XSTR (body, 0);
+  else
+    template = decode_asm_operands (body, NULL_PTR, NULL_PTR,
+                                   NULL_PTR, NULL_PTR);
+
+  for ( ; *template; template++)
+    if (IS_ASM_LOGICAL_LINE_SEPARATOR(*template) || *template == '\n')
       count++;
 
   return count;
@@ -648,24 +891,27 @@ final_start_function (first, file, optimize)
      so that the function's address will not appear to be
      in the last statement of the preceding function.  */
   if (NOTE_LINE_NUMBER (first) != NOTE_INSN_DELETED)
-    {
-      if (write_symbols == SDB_DEBUG)
-       /* For sdb, let's not, but say we did.
-          We need to set last_linenum for sdbout_function_begin,
-          but we can't have an actual line number before the .bf symbol.
-          (sdb_begin_function_line is not set,
-          and other compilers don't do it.)  */
-       last_linenum = NOTE_LINE_NUMBER (first);
+    last_linenum = high_block_linenum = high_function_linenum
+      = NOTE_LINE_NUMBER (first);
+
+  /* For SDB and XCOFF, the function beginning must be marked between
+     the function label and the prologue.  We always need this, even when
+     -g1 was used.  Defer on MIPS systems so that parameter descriptions
+     follow function entry. */
+#if defined(SDB_DEBUGGING_INFO) && !defined(MIPS_DEBUGGING_INFO)
+  if (write_symbols == SDB_DEBUG)
+    sdbout_begin_function (last_linenum);
+  else
+#endif
 #ifdef XCOFF_DEBUGGING_INFO
-      else if (write_symbols == XCOFF_DEBUG)
-       {
-         last_linenum = NOTE_LINE_NUMBER (first);
-         xcoffout_output_first_source_line (file, last_linenum);
-       }
+    if (write_symbols == XCOFF_DEBUG)
+      xcoffout_begin_function (file, last_linenum);
+    else
 #endif   
-      else
+      /* But only output line number for other debug info types if -g2
+        or better.  */
+      if (NOTE_LINE_NUMBER (first) != NOTE_INSN_DELETED)
        output_source_line (file, first);
-    }
 
 #ifdef LEAF_REG_REMAP
   if (leaf_function)
@@ -689,10 +935,33 @@ final_start_function (first, file, optimize)
     next_block_index = 1;
 #endif
 
+  /* If the machine represents the prologue as RTL, the profiling code must
+     be emitted when NOTE_INSN_PROLOGUE_END is scanned.  */
+#ifdef HAVE_prologue
+  if (! HAVE_prologue)
+#endif
+    profile_after_prologue (file);
+
+  profile_label_no++;
+
+  /* If we are doing basic block profiling, remember a printable version
+     of the function name.  */
+  if (profile_block_flag)
+    {
+      char *junk = "function";
+      bb_func_label_num =
+       add_bb_string ((*decl_printable_name) (current_function_decl, &junk), FALSE);
+    }
+}
+
+static void
+profile_after_prologue (file)
+     FILE *file;
+{
 #ifdef FUNCTION_BLOCK_PROFILER
   if (profile_block_flag)
     {
-      FUNCTION_BLOCK_PROFILER (file, profile_label_no);
+      FUNCTION_BLOCK_PROFILER (file, count_basic_blocks);
     }
 #endif /* FUNCTION_BLOCK_PROFILER */
 
@@ -700,22 +969,20 @@ final_start_function (first, file, optimize)
   if (profile_flag)
     profile_function (file);
 #endif /* not PROFILE_BEFORE_PROLOGUE */
-
-  profile_label_no++;
 }
 
-void
+static void
 profile_function (file)
      FILE *file;
 {
-  int align = MIN (BIGGEST_ALIGNMENT, INT_TYPE_SIZE);
+  int align = MIN (BIGGEST_ALIGNMENT, POINTER_SIZE);
   int sval = current_function_returns_struct;
   int cxt = current_function_needs_context;
 
   data_section ();
   ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
   ASM_OUTPUT_INTERNAL_LABEL (file, "LP", profile_label_no);
-  assemble_integer (const0_rtx, UNITS_PER_WORD, 1);
+  assemble_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
 
   text_section ();
 
@@ -784,12 +1051,17 @@ final_end_function (first, file, optimize)
 
 #ifdef SDB_DEBUGGING_INFO
   if (write_symbols == SDB_DEBUG)
-    sdbout_end_function (last_linenum);
+    sdbout_end_function (high_function_linenum);
+#endif
+
+#ifdef DWARF_DEBUGGING_INFO
+  if (write_symbols == DWARF_DEBUG)
+    dwarfout_end_function ();
 #endif
 
 #ifdef XCOFF_DEBUGGING_INFO
   if (write_symbols == XCOFF_DEBUG)
-    xcoffout_end_function (file, last_linenum);
+    xcoffout_end_function (file, high_function_linenum);
 #endif
 
 #ifdef FUNCTION_EPILOGUE
@@ -813,10 +1085,93 @@ final_end_function (first, file, optimize)
     xcoffout_end_epilogue (file);
 #endif
 
+  bb_func_label_num = -1;      /* not in function, nuke label # */
+
   /* If FUNCTION_EPILOGUE is not defined, then the function body
      itself contains return instructions wherever needed.  */
 }
 \f
+/* Add a block to the linked list that remembers the current line/file/function
+   for basic block profiling.  Emit the label in front of the basic block and
+   the instructions that increment the count field.  */
+
+static void
+add_bb (file)
+     FILE *file;
+{
+  struct bb_list *ptr = (struct bb_list *) permalloc (sizeof (struct bb_list));
+
+  /* Add basic block to linked list.  */
+  ptr->next = 0;
+  ptr->line_num = last_linenum;
+  ptr->file_label_num = bb_file_label_num;
+  ptr->func_label_num = bb_func_label_num;
+  *bb_tail = ptr;
+  bb_tail = &ptr->next;
+
+  /* Enable the table of basic-block use counts
+     to point at the code it applies to.  */
+  ASM_OUTPUT_INTERNAL_LABEL (file, "LPB", count_basic_blocks);
+
+  /* Before first insn of this basic block, increment the
+     count of times it was entered.  */
+#ifdef BLOCK_PROFILER
+  BLOCK_PROFILER (file, count_basic_blocks);
+  CC_STATUS_INIT;
+#endif
+
+  new_block = 0;
+  count_basic_blocks++;
+}
+
+/* Add a string to be used for basic block profiling.  */
+
+static int
+add_bb_string (string, perm_p)
+     char *string;
+     int perm_p;
+{
+  int len;
+  struct bb_str *ptr = 0;
+
+  if (!string)
+    {
+      string = "<unknown>";
+      perm_p = TRUE;
+    }
+
+  /* Allocate a new string if the current string isn't permanent.  If
+     the string is permanent search for the same string in other
+     allocations.  */
+
+  len = strlen (string) + 1;
+  if (!perm_p)
+    {
+      char *p = (char *) permalloc (len);
+      bcopy (string, p, len);
+      string = p;
+    }
+  else
+    for (ptr = sbb_head; ptr != (struct bb_str *)0; ptr = ptr->next)
+      if (ptr->string == string)
+       break;
+
+  /* Allocate a new string block if we need to.  */
+  if (!ptr)
+    {
+      ptr = (struct bb_str *) permalloc (sizeof (*ptr));
+      ptr->next = 0;
+      ptr->length = len;
+      ptr->label_num = sbb_label_num++;
+      ptr->string = string;
+      *sbb_tail = ptr;
+      sbb_tail = &ptr->next;
+    }
+
+  return ptr->label_num;
+}
+
+\f
 /* Output assembler code for some insns: all or part of a function.
    For description of args, see `final_start_function', above.
 
@@ -841,10 +1196,39 @@ final (first, file, optimize, prescan)
   last_ignored_compare = 0;
   new_block = 1;
 
-  /* Make a map indicating which line numbers appear in this function.  */
-  for (insn = first; insn; insn = NEXT_INSN (insn))
-    if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > max_line)
-      max_line = NOTE_LINE_NUMBER (insn);
+  /* Make a map indicating which line numbers appear in this function.
+     When producing SDB debugging info, delete troublesome line number
+     notes from inlined functions in other files as well as duplicate
+     line number notes.  */
+#ifdef SDB_DEBUGGING_INFO
+  if (write_symbols == SDB_DEBUG)
+    {
+      rtx last = 0;
+      for (insn = first; insn; insn = NEXT_INSN (insn))
+       if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
+         {
+           if ((RTX_INTEGRATED_P (insn)
+                && strcmp (NOTE_SOURCE_FILE (insn), main_input_filename) != 0)
+                || (last != 0
+                    && NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last)
+                    && NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last)))
+             {
+               NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+               NOTE_SOURCE_FILE (insn) = 0;
+               continue;
+             }
+           last = insn;
+           if (NOTE_LINE_NUMBER (insn) > max_line)
+             max_line = NOTE_LINE_NUMBER (insn);
+         }
+    }
+  else
+#endif
+    {
+      for (insn = first; insn; insn = NEXT_INSN (insn))
+       if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > max_line)
+         max_line = NOTE_LINE_NUMBER (insn);
+    }
 
   line_note_exists = (char *) oballoc (max_line + 1);
   bzero (line_note_exists, max_line + 1);
@@ -864,19 +1248,7 @@ final (first, file, optimize, prescan)
   /* Do basic-block profiling here
      if the last insn was a conditional branch.  */
   if (profile_block_flag && new_block)
-    {
-      new_block = 0;
-      /* Enable the table of basic-block use counts
-        to point at the code it applies to.  */
-      ASM_OUTPUT_INTERNAL_LABEL (file, "LPB", count_basic_blocks);
-      /* Before first insn of this basic block, increment the
-        count of times it was entered.  */
-#ifdef BLOCK_PROFILER
-      BLOCK_PROFILER (file, count_basic_blocks);
-      CC_STATUS_INIT;
-#endif
-      count_basic_blocks++;
-    }
+    add_bb (file);
 }
 \f
 /* The final scan for one insn, INSN.
@@ -926,17 +1298,39 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
       if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
        break;
 
+      if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_PROLOGUE_END)
+       {
+#ifdef FUNCTION_END_PROLOGUE
+         FUNCTION_END_PROLOGUE (file);
+#endif
+         profile_after_prologue (file);
+         break;
+       }
+
+#ifdef FUNCTION_BEGIN_EPILOGUE
+      if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EPILOGUE_BEG)
+       {
+         FUNCTION_BEGIN_EPILOGUE (file);
+         break;
+       }
+#endif
+
       if (write_symbols == NO_DEBUG)
        break;
       if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG)
        {
-#ifdef SDB_DEBUGGING_INFO
+#if defined(SDB_DEBUGGING_INFO) && defined(MIPS_DEBUGGING_INFO)
+         /* MIPS stabs require the parameter descriptions to be after the
+            function entry point rather than before. */
          if (write_symbols == SDB_DEBUG)
            sdbout_begin_function (last_linenum);
+         else
 #endif
-#ifdef XCOFF_DEBUGGING_INFO
-         if (write_symbols == XCOFF_DEBUG)
-           xcoffout_begin_function (file, last_linenum);
+#ifdef DWARF_DEBUGGING_INFO
+         /* This outputs a marker where the function body starts, so it
+            must be after the prologue.  */
+         if (write_symbols == DWARF_DEBUG)
+           dwarfout_begin_function ();
 #endif
          break;
        }
@@ -949,7 +1343,12 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
        }
       if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
          && (debug_info_level == DINFO_LEVEL_NORMAL
-             || debug_info_level == DINFO_LEVEL_VERBOSE))
+             || debug_info_level == DINFO_LEVEL_VERBOSE
+#ifdef DWARF_DEBUGGING_INFO
+             || write_symbols == DWARF_DEBUG
+#endif
+            )
+        )
        {
          /* Beginning of a symbol-block.  Assign it a sequence number
             and push the number onto the stack PENDING_BLOCKS.  */
@@ -964,6 +1363,8 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
            }
          pending_blocks[block_depth++] = next_block_index;
 
+         high_block_linenum = last_linenum;
+
          /* Output debugging info about the symbol-block beginning.  */
 
 #ifdef SDB_DEBUGGING_INFO
@@ -987,7 +1388,12 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
        }
       else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END
               && (debug_info_level == DINFO_LEVEL_NORMAL
-                  || debug_info_level == DINFO_LEVEL_VERBOSE))
+                  || debug_info_level == DINFO_LEVEL_VERBOSE
+#ifdef DWARF_DEBUGGING_INFO
+                  || write_symbols == DWARF_DEBUG
+#endif
+                 )
+             )
        {
          /* End of a symbol-block.  Pop its sequence number off
             PENDING_BLOCKS and output debugging info based on that.  */
@@ -996,7 +1402,8 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
 
 #ifdef XCOFF_DEBUGGING_INFO
          if (write_symbols == XCOFF_DEBUG && block_depth >= 0)
-           xcoffout_end_block (file, last_linenum, pending_blocks[block_depth]);
+           xcoffout_end_block (file, high_block_linenum,
+                               pending_blocks[block_depth]);
 #endif
 #ifdef DBX_DEBUGGING_INFO
          if (write_symbols == DBX_DEBUG && block_depth >= 0)
@@ -1005,13 +1412,23 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
 #endif
 #ifdef SDB_DEBUGGING_INFO
          if (write_symbols == SDB_DEBUG && block_depth >= 0)
-           sdbout_end_block (file, last_linenum);
+           sdbout_end_block (file, high_block_linenum,
+                             pending_blocks[block_depth]);
 #endif
 #ifdef DWARF_DEBUGGING_INFO
          if (write_symbols == DWARF_DEBUG && block_depth >= 1)
            dwarfout_end_block (pending_blocks[block_depth]);
 #endif
        }
+      else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL
+              && (debug_info_level == DINFO_LEVEL_NORMAL
+                  || debug_info_level == DINFO_LEVEL_VERBOSE))
+       {
+#ifdef DWARF_DEBUGGING_INFO
+          if (write_symbols == DWARF_DEBUG)
+            dwarfout_label (insn);
+#endif
+       }
       else if (NOTE_LINE_NUMBER (insn) > 0)
        /* This note is a line-number.  */
        {
@@ -1028,10 +1445,17 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
            {
              if (GET_CODE (note) != NOTE && GET_CODE (note) != CODE_LABEL)
                break;
+             /* These types of notes can be significant
+                so make sure the preceding line number stays.  */
+             else if (GET_CODE (note) == NOTE
+                      && (NOTE_LINE_NUMBER (note) == NOTE_INSN_BLOCK_BEG
+                          || NOTE_LINE_NUMBER (note) == NOTE_INSN_BLOCK_END
+                          || NOTE_LINE_NUMBER (note) == NOTE_INSN_FUNCTION_BEG))
+               break;
              else if (GET_CODE (note) == NOTE && NOTE_LINE_NUMBER (note) > 0)
                {
-                 /* Another note follows; we can delete this note provided
-                    no intervening line numbers have notes elsewhere.  */
+                 /* Another line note follows; we can delete this note
+                    if no intervening line numbers have notes elsewhere.  */
                  int num;
                  for (num = NOTE_LINE_NUMBER (insn) + 1;
                       num < NOTE_LINE_NUMBER (note);
@@ -1039,7 +1463,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
                    if (line_note_exists[num])
                      break;
 
-                 if (num == NOTE_LINE_NUMBER (note))
+                 if (num >= NOTE_LINE_NUMBER (note))
                    note_after = 1;
                  break;
                }
@@ -1054,7 +1478,11 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
 
     case BARRIER:
 #ifdef ASM_OUTPUT_ALIGN_CODE
-      ASM_OUTPUT_ALIGN_CODE (file);
+      /* Don't litter the assembler output with needless alignments.  A
+        BARRIER will be placed at the end of every function if HAVE_epilogue
+        is true.  */    
+      if (NEXT_INSN (insn))
+       ASM_OUTPUT_ALIGN_CODE (file);
 #endif
       break;
 
@@ -1063,6 +1491,11 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
       if (prescan > 0)
        break;
       new_block = 1;
+
+#ifdef FINAL_PRESCAN_LABEL
+      FINAL_PRESCAN_INSN (insn, NULL_PTR, 0);
+#endif
+
 #ifdef SDB_DEBUGGING_INFO
       if (write_symbols == SDB_DEBUG && LABEL_NAME (insn))
        sdbout_label (insn);
@@ -1090,9 +1523,14 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
            {
 #ifndef JUMP_TABLES_IN_TEXT_SECTION
              readonly_data_section ();
-#else
-             text_section ();
-#endif
+#ifdef READONLY_DATA_SECTION
+             ASM_OUTPUT_ALIGN (file,
+                               exact_log2 (BIGGEST_ALIGNMENT
+                                           / BITS_PER_UNIT));
+#endif /* READONLY_DATA_SECTION */
+#else /* JUMP_TABLES_IN_TEXT_SECTION */
+             function_section (current_function_decl);
+#endif /* JUMP_TABLES_IN_TEXT_SECTION */
 #ifdef ASM_OUTPUT_CASE_LABEL
              ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn),
                                     NEXT_INSN (insn));
@@ -1126,7 +1564,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
           of the insn that branched here.  So recover the cc status
           from the insn that set it.  */
 
-       note = find_reg_note (insn, REG_CC_SETTER, 0);
+       note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX);
        if (note)
          {
            NOTICE_UPDATE_CC (PATTERN (XEXP (note, 0)), XEXP (note, 0));
@@ -1154,13 +1592,25 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
            for (idx = 0; idx < vlen; idx++)
              {
                if (GET_CODE (body) == ADDR_VEC)
-                 ASM_OUTPUT_ADDR_VEC_ELT
-                   (file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0)));
+                 {
+#ifdef ASM_OUTPUT_ADDR_VEC_ELT
+                   ASM_OUTPUT_ADDR_VEC_ELT
+                     (file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0)));
+#else
+                   abort ();
+#endif
+                 }
                else
-                 ASM_OUTPUT_ADDR_DIFF_ELT
-                   (file,
-                    CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)),
-                    CODE_LABEL_NUMBER (XEXP (XEXP (body, 0), 0)));
+                 {
+#ifdef ASM_OUTPUT_ADDR_DIFF_ELT
+                   ASM_OUTPUT_ADDR_DIFF_ELT
+                     (file,
+                      CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)),
+                      CODE_LABEL_NUMBER (XEXP (XEXP (body, 0), 0)));
+#else
+                   abort ();
+#endif
+                 }
              }
 #ifdef ASM_OUTPUT_CASE_END
            ASM_OUTPUT_CASE_END (file,
@@ -1168,7 +1618,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
                                 insn);
 #endif
 
-           text_section ();
+           function_section (current_function_decl);
 
            break;
          }
@@ -1176,19 +1626,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
        /* Do basic-block profiling when we reach a new block.
           Done here to avoid jump tables.  */
        if (profile_block_flag && new_block)
-         {
-           new_block = 0;
-           /* Enable the table of basic-block use counts
-              to point at the code it applies to.  */
-           ASM_OUTPUT_INTERNAL_LABEL (file, "LPB", count_basic_blocks);
-           /* Before first insn of this basic block, increment the
-              count of times it was entered.  */
-#ifdef BLOCK_PROFILER
-           BLOCK_PROFILER (file, count_basic_blocks);
-           CC_STATUS_INIT;
-#endif
-           count_basic_blocks++;
-         }
+         add_bb (file);
 
        if (GET_CODE (body) == ASM_INPUT)
          {
@@ -1209,7 +1647,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
        if (asm_noperands (body) >= 0)
          {
            int noperands = asm_noperands (body);
-           rtx *ops;
+           rtx *ops = (rtx *) alloca (noperands * sizeof (rtx));
            char *string;
 
            /* There's no telling what that did to the condition codes.  */
@@ -1217,11 +1655,6 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
            if (prescan > 0)
              break;
 
-           /* alloca won't do here, since only return from `final'
-              would free it.  */
-           if (noperands > 0)
-             ops = (rtx *) xmalloc (noperands * sizeof (rtx));
-
            if (! app_on)
              {
                fprintf (file, ASM_APP_ON);
@@ -1229,15 +1662,15 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
              }
 
            /* Get out the operand values.  */
-           string = decode_asm_operands (body, ops, 0, 0, 0);
+           string = decode_asm_operands (body, ops, NULL_PTR,
+                                         NULL_PTR, NULL_PTR);
            /* Inhibit aborts on what would otherwise be compiler bugs.  */
            insn_noperands = noperands;
            this_is_asm_operands = insn;
+
            /* Output the insn using them.  */
            output_asm_insn (string, ops);
            this_is_asm_operands = 0;
-           if (noperands > 0)
-             free (ops);
            break;
          }
 
@@ -1270,7 +1703,15 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
              }
 
            for (i = 1; i < XVECLEN (body, 0); i++)
-             final_scan_insn (XVECEXP (body, 0, i), file, 0, prescan, 1);
+             {
+               rtx insn = XVECEXP (body, 0, i);
+               rtx next = NEXT_INSN (insn);
+               /* We loop in case any instruction in a delay slot gets
+                  split.  */
+               do
+                 insn = final_scan_insn (insn, file, 0, prescan, 1);
+               while (insn != next);
+             }
 #ifdef DBR_OUTPUT_SEQEND
            DBR_OUTPUT_SEQEND (file);
 #endif
@@ -1315,35 +1756,39 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
           and the next statement should reexamine the variable
           to compute the condition codes.  */
 
-       if (optimize
-           && GET_CODE (body) == SET
-           && GET_CODE (SET_DEST (body)) == CC0
-           && insn != last_ignored_compare)
+       if (optimize)
          {
-           if (GET_CODE (SET_SRC (body)) == SUBREG)
-             SET_SRC (body) = alter_subreg (SET_SRC (body));
-           else if (GET_CODE (SET_SRC (body)) == COMPARE)
-             {
-               if (GET_CODE (XEXP (SET_SRC (body), 0)) == SUBREG)
-                 XEXP (SET_SRC (body), 0)
-                   = alter_subreg (XEXP (SET_SRC (body), 0));
-               if (GET_CODE (XEXP (SET_SRC (body), 1)) == SUBREG)
-                 XEXP (SET_SRC (body), 1)
-                   = alter_subreg (XEXP (SET_SRC (body), 1));
-             }
-           if ((cc_status.value1 != 0
-                && rtx_equal_p (SET_SRC (body), cc_status.value1))
-               || (cc_status.value2 != 0
-                   && rtx_equal_p (SET_SRC (body), cc_status.value2)))
+           rtx set = single_set(insn);
+
+           if (set
+               && GET_CODE (SET_DEST (set)) == CC0
+               && insn != last_ignored_compare)
              {
-               /* Don't delete insn if it has an addressing side-effect.  */
-               if (! FIND_REG_INC_NOTE (insn, 0)
-                   /* or if anything in it is volatile.  */
-                   && ! volatile_refs_p (PATTERN (insn)))
+               if (GET_CODE (SET_SRC (set)) == SUBREG)
+                 SET_SRC (set) = alter_subreg (SET_SRC (set));
+               else if (GET_CODE (SET_SRC (set)) == COMPARE)
                  {
-                   /* We don't really delete the insn; just ignore it.  */
-                   last_ignored_compare = insn;
-                   break;
+                   if (GET_CODE (XEXP (SET_SRC (set), 0)) == SUBREG)
+                     XEXP (SET_SRC (set), 0)
+                       = alter_subreg (XEXP (SET_SRC (set), 0));
+                   if (GET_CODE (XEXP (SET_SRC (set), 1)) == SUBREG)
+                     XEXP (SET_SRC (set), 1)
+                       = alter_subreg (XEXP (SET_SRC (set), 1));
+                 }
+               if ((cc_status.value1 != 0
+                    && rtx_equal_p (SET_SRC (set), cc_status.value1))
+                   || (cc_status.value2 != 0
+                       && rtx_equal_p (SET_SRC (set), cc_status.value2)))
+                 {
+                   /* Don't delete insn if it has an addressing side-effect.  */
+                   if (! FIND_REG_INC_NOTE (insn, 0)
+                       /* or if anything in it is volatile.  */
+                       && ! volatile_refs_p (PATTERN (insn)))
+                     {
+                       /* We don't really delete the insn; just ignore it.  */
+                       last_ignored_compare = insn;
+                       break;
+                     }
                  }
              }
          }
@@ -1385,6 +1830,8 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
            && GET_CODE (body) == SET
            && SET_DEST (body) == pc_rtx
            && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE
+           && GET_RTX_CLASS (GET_CODE (XEXP (SET_SRC (body), 0))) == '<'
+           && XEXP (XEXP (SET_SRC (body), 0), 0) == cc0_rtx
            /* This is done during prescan; it is not done again
               in final scan when prescan has been done.  */
            && prescan >= 0)
@@ -1422,12 +1869,29 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
          }
 
        /* Make same adjustments to instructions that examine the
-          condition codes without jumping (if this machine has them).  */
+          condition codes without jumping and instructions that
+          handle conditional moves (if this machine has either one).  */
 
        if (cc_status.flags != 0
            && GET_CODE (body) == SET)
          {
-           switch (GET_CODE (SET_SRC (body)))
+           rtx cond_rtx, then_rtx, else_rtx;
+           
+           if (GET_CODE (insn) != JUMP_INSN
+               && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE)
+             {
+               cond_rtx = XEXP (SET_SRC (body), 0);
+               then_rtx = XEXP (SET_SRC (body), 1);
+               else_rtx = XEXP (SET_SRC (body), 2);
+             }
+           else
+             {
+               cond_rtx = SET_SRC (body);
+               then_rtx = const_true_rtx;
+               else_rtx = const0_rtx;
+             }
+           
+           switch (GET_CODE (cond_rtx))
              {
              case GTU:
              case GT:
@@ -1441,18 +1905,26 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
              case NE:
                {
                  register int result;
-                 if (XEXP (SET_SRC (body), 0) != cc0_rtx)
+                 if (XEXP (cond_rtx, 0) != cc0_rtx)
                    break;
-                 result = alter_cond (SET_SRC (body));
+                 result = alter_cond (cond_rtx);
                  if (result == 1)
-                   validate_change (insn, &SET_SRC (body), const_true_rtx, 0);
+                   validate_change (insn, &SET_SRC (body), then_rtx, 0);
                  else if (result == -1)
-                   validate_change (insn, &SET_SRC (body), const0_rtx, 0);
+                   validate_change (insn, &SET_SRC (body), else_rtx, 0);
                  else if (result == 2)
                    INSN_CODE (insn) = -1;
+                 if (SET_DEST (body) == SET_SRC (body))
+                   {
+                     PUT_CODE (insn, NOTE);
+                     NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+                     NOTE_SOURCE_FILE (insn) = 0;
+                     break;
+                   }
                }
              }
          }
+
 #endif
 
        /* Do machine-specific peephole optimizations if desired.  */
@@ -1497,6 +1969,18 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
          {
            if (GET_CODE (recog_operand[i]) == SUBREG)
              recog_operand[i] = alter_subreg (recog_operand[i]);
+           else if (GET_CODE (recog_operand[i]) == PLUS
+                    || GET_CODE (recog_operand[i]) == MULT)
+             recog_operand[i] = walk_alter_subreg (recog_operand[i]);
+         }
+
+       for (i = 0; i < insn_n_dups[insn_code_number]; i++)
+         {
+           if (GET_CODE (*recog_dup_loc[i]) == SUBREG)
+             *recog_dup_loc[i] = alter_subreg (*recog_dup_loc[i]);
+           else if (GET_CODE (*recog_dup_loc[i]) == PLUS
+                    || GET_CODE (*recog_dup_loc[i]) == MULT)
+             *recog_dup_loc[i] = walk_alter_subreg (*recog_dup_loc[i]);
          }
 
 #ifdef REGISTER_CONSTRAINTS
@@ -1589,10 +2073,20 @@ output_source_line (file, insn)
      FILE *file;
      rtx insn;
 {
-  char ltext_label_name[100];
   register char *filename = NOTE_SOURCE_FILE (insn);
 
+  /* Remember filename for basic block profiling.
+     Filenames are allocated on the permanent obstack
+     or are passed in ARGV, so we don't have to save
+     the string.  */
+
+  if (profile_block_flag && last_filename != filename)
+    bb_file_label_num = add_bb_string (filename, TRUE);
+
+  last_filename = filename;
   last_linenum = NOTE_LINE_NUMBER (insn);
+  high_block_linenum = MAX (last_linenum, high_block_linenum);
+  high_function_linenum = MAX (last_linenum, high_function_linenum);
 
   if (write_symbols != NO_DEBUG)
     {
@@ -1615,19 +2109,15 @@ output_source_line (file, insn)
        }
 #endif
 
-#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
-      if (write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG)
-       {
-         dbxout_source_file (file, filename);
+#if defined (DBX_DEBUGGING_INFO)
+      if (write_symbols == DBX_DEBUG)
+       dbxout_source_line (file, filename, NOTE_LINE_NUMBER (insn));
+#endif
 
-#ifdef ASM_OUTPUT_SOURCE_LINE
-         ASM_OUTPUT_SOURCE_LINE (file, NOTE_LINE_NUMBER (insn));
-#else
-         fprintf (file, "\t%s %d,0,%d\n", ASM_STABD_OP, 
-                  N_SLINE, NOTE_LINE_NUMBER (insn));
+#if defined (XCOFF_DEBUGGING_INFO)
+      if (write_symbols == XCOFF_DEBUG)
+       xcoffout_source_line (file, filename, insn);
 #endif
-       }
-#endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */
 
 #ifdef DWARF_DEBUGGING_INFO
       if (write_symbols == DWARF_DEBUG)
@@ -1656,10 +2146,9 @@ alter_subreg (x)
   else if (GET_CODE (y) == MEM)
     {
       register int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
-#if BYTES_BIG_ENDIAN
-      offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x)))
-                - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (y))));
-#endif
+      if (BYTES_BIG_ENDIAN)
+       offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x)))
+                  - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (y))));
       PUT_CODE (x, MEM);
       MEM_VOLATILE_P (x) = MEM_VOLATILE_P (y);
       XEXP (x, 0) = plus_constant (XEXP (y, 0), offset);
@@ -1819,7 +2308,33 @@ alter_cond (cond)
        value = 2;
        break;
       }
-  
+
+  if (cc_status.flags & CC_NOT_SIGNED)
+    /* The flags are valid if signed condition operators are converted
+       to unsigned.  */
+    switch (GET_CODE (cond))
+      {
+      case LE:
+       PUT_CODE (cond, LEU);
+       value = 2;
+       break;
+
+      case LT:
+       PUT_CODE (cond, LTU);
+       value = 2;
+       break;
+
+      case GT:
+       PUT_CODE (cond, GTU);
+       value = 2;
+       break;
+
+      case GE:
+       PUT_CODE (cond, GEU);
+       value = 2;
+       break;
+      }
+
   return value;
 }
 #endif
@@ -1855,13 +2370,35 @@ output_operand_lossage (str)
       and print a constant expression for minus the value
       of the operand, with no other punctuation.  */
 
+static void
+output_asm_name ()
+{
+  if (flag_print_asm_name)
+    {
+      /* Annotate the assembly with a comment describing the pattern and
+        alternative used.  */
+      if (debug_insn)
+       {
+         register int num = INSN_CODE (debug_insn);
+         fprintf (asm_out_file, " %s %d %s", 
+                  ASM_COMMENT_START, INSN_UID (debug_insn), insn_name[num]);
+         if (insn_n_alternatives[num] > 1)
+           fprintf (asm_out_file, "/%d", which_alternative + 1);
+
+         /* Clear this so only the first assembler insn
+            of any rtl insn will get the special comment for -dp.  */
+         debug_insn = 0;
+       }
+    }
+}
+
 void
 output_asm_insn (template, operands)
      char *template;
      rtx *operands;
 {
   register char *p;
-  register int c;
+  register int c, i;
 
   /* An insn may return a null string template
      in a case where no assembler code is needed.  */
@@ -1876,115 +2413,133 @@ output_asm_insn (template, operands)
 #endif
 
   while (c = *p++)
-    {
+    switch (c)
+      {
+      case '\n':
+       output_asm_name ();
+       putc (c, asm_out_file);
 #ifdef ASM_OUTPUT_OPCODE
-      if (c == '\n')
-       {
-         putc (c, asm_out_file);
-         while ((c = *p) == '\t')
-           {
-             putc (c, asm_out_file);
-             p++;
-           }
-         ASM_OUTPUT_OPCODE (asm_out_file, p);
-       }
-      else
+       while ((c = *p) == '\t')
+         {
+           putc (c, asm_out_file);
+           p++;
+         }
+       ASM_OUTPUT_OPCODE (asm_out_file, p);
 #endif
-      if (c != '%')
-       putc (c, asm_out_file);
-      else
-       {
-         /* %% outputs a single %.  */
-         if (*p == '%')
-           {
+       break;
+
+#ifdef ASSEMBLER_DIALECT
+      case '{':
+       /* If we want the first dialect, do nothing.  Otherwise, skip
+          DIALECT_NUMBER of strings ending with '|'.  */
+       for (i = 0; i < dialect_number; i++)
+         {
+           while (*p && *p++ != '|')
+             ;
+
+           if (*p == '|')
              p++;
-             putc (c, asm_out_file);
-           }
-         /* %= outputs a number which is unique to each insn in the entire
-            compilation.  This is useful for making local labels that are
-            referred to more than once in a given insn.  */
-         else if (*p == '=')
+         }
+       break;
+
+      case '|':
+       /* Skip to close brace.  */
+       while (*p && *p++ != '}')
+         ;
+       break;
+
+      case '}':
+       break;
+#endif
+
+      case '%':
+       /* %% outputs a single %.  */
+       if (*p == '%')
+         {
+           p++;
+           putc (c, asm_out_file);
+         }
+       /* %= outputs a number which is unique to each insn in the entire
+          compilation.  This is useful for making local labels that are
+          referred to more than once in a given insn.  */
+       else if (*p == '=')
+         {
+           p++;
            fprintf (asm_out_file, "%d", insn_counter);
-         /* % followed by a letter and some digits
-            outputs an operand in a special way depending on the letter.
-            Letters `acln' are implemented directly.
-            Other letters are passed to `output_operand' so that
-            the PRINT_OPERAND macro can define them.  */
-         else if ((*p >= 'a' && *p <= 'z')
-                  || (*p >= 'A' && *p <= 'Z'))
-           {
-             int letter = *p++;
-             c = atoi (p);
-
-             if (! (*p >= '0' && *p <= '9'))
-               output_operand_lossage ("operand number missing after %-letter");
-             else if (this_is_asm_operands && c >= (unsigned) insn_noperands)
-               output_operand_lossage ("operand number out of range");
-             else if (letter == 'l')
-               output_asm_label (operands[c]);
-             else if (letter == 'a')
-               output_address (operands[c]);
-             else if (letter == 'c')
-               {
-                 if (CONSTANT_ADDRESS_P (operands[c]))
+         }
+       /* % followed by a letter and some digits
+          outputs an operand in a special way depending on the letter.
+          Letters `acln' are implemented directly.
+          Other letters are passed to `output_operand' so that
+          the PRINT_OPERAND macro can define them.  */
+       else if ((*p >= 'a' && *p <= 'z')
+                || (*p >= 'A' && *p <= 'Z'))
+         {
+           int letter = *p++;
+           c = atoi (p);
+
+           if (! (*p >= '0' && *p <= '9'))
+             output_operand_lossage ("operand number missing after %-letter");
+           else if (this_is_asm_operands && c >= (unsigned) insn_noperands)
+             output_operand_lossage ("operand number out of range");
+           else if (letter == 'l')
+             output_asm_label (operands[c]);
+           else if (letter == 'a')
+             output_address (operands[c]);
+           else if (letter == 'c')
+             {
+               if (CONSTANT_ADDRESS_P (operands[c]))
+                 output_addr_const (asm_out_file, operands[c]);
+               else
+                 output_operand (operands[c], 'c');
+             }
+           else if (letter == 'n')
+             {
+               if (GET_CODE (operands[c]) == CONST_INT)
+                 fprintf (asm_out_file,
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
+                          "%d",
+#else
+                          "%ld",
+#endif
+                          - INTVAL (operands[c]));
+               else
+                 {
+                   putc ('-', asm_out_file);
                    output_addr_const (asm_out_file, operands[c]);
-                 else
-                   output_operand (operands[c], 'c');
-               }
-             else if (letter == 'n')
-               {
-                 if (GET_CODE (operands[c]) == CONST_INT)
-                   fprintf (asm_out_file, "%d", - INTVAL (operands[c]));
-                 else
-                   {
-                     putc ('-', asm_out_file);
-                     output_addr_const (asm_out_file, operands[c]);
-                   }
-               }
-             else
-               output_operand (operands[c], letter);
-
-             while ((c = *p) >= '0' && c <= '9') p++;
-           }
-         /* % followed by a digit outputs an operand the default way.  */
-         else if (*p >= '0' && *p <= '9')
-           {
-             c = atoi (p);
-             if (this_is_asm_operands && c >= (unsigned) insn_noperands)
-               output_operand_lossage ("operand number out of range");
-             else
-               output_operand (operands[c], 0);
-             while ((c = *p) >= '0' && c <= '9') p++;
-           }
-         /* % followed by punctuation: output something for that
-            punctuation character alone, with no operand.
-            The PRINT_OPERAND macro decides what is actually done.  */
+                 }
+             }
+           else
+             output_operand (operands[c], letter);
+           
+           while ((c = *p) >= '0' && c <= '9') p++;
+         }
+       /* % followed by a digit outputs an operand the default way.  */
+       else if (*p >= '0' && *p <= '9')
+         {
+           c = atoi (p);
+           if (this_is_asm_operands && c >= (unsigned) insn_noperands)
+             output_operand_lossage ("operand number out of range");
+           else
+             output_operand (operands[c], 0);
+           while ((c = *p) >= '0' && c <= '9') p++;
+         }
+       /* % followed by punctuation: output something for that
+          punctuation character alone, with no operand.
+          The PRINT_OPERAND macro decides what is actually done.  */
 #ifdef PRINT_OPERAND_PUNCT_VALID_P
-         else if (PRINT_OPERAND_PUNCT_VALID_P (*p))
-           output_operand (0, *p++);
+       else if (PRINT_OPERAND_PUNCT_VALID_P (*p))
+         output_operand (NULL_RTX, *p++);
 #endif
-         else
-           output_operand_lossage ("invalid %%-code");
-       }
-    }
+       else
+         output_operand_lossage ("invalid %%-code");
+       break;
 
-  if (flag_print_asm_name)
-    {
-      /* Annotate the assembly with a comment describing the pattern and
-        alternative used.  */
-      if (debug_insn)
-       {
-         register int num = INSN_CODE (debug_insn);
-         fprintf (asm_out_file, " %s %d %s", 
-                  ASM_COMMENT_START, INSN_UID (debug_insn), insn_name[num]);
-         if (insn_n_alternatives[num] > 1)
-           fprintf (asm_out_file, "/%d", which_alternative + 1);
+      default:
+       putc (c, asm_out_file);
+      }
 
-         /* Clear this so only the first assembler insn
-            of any rtl insn will get the special comment for -dp.  */
-         debug_insn = 0;
-       }
-    }
+  output_asm_name ();
 
   putc ('\n', asm_out_file);
 }
@@ -2024,6 +2579,13 @@ output_operand (x, code)
 {
   if (x && GET_CODE (x) == SUBREG)
     x = alter_subreg (x);
+
+  /* If X is a pseudo-register, abort now rather than writing trash to the
+     assembler file.  */
+
+  if (x && GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER)
+    abort ();
+
   PRINT_OPERAND (asm_out_file, x, code);
 }
 
@@ -2066,16 +2628,22 @@ output_addr_const (file, x)
 
     case LABEL_REF:
       ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0)));
-      assemble_name (asm_out_file, buf);
+      assemble_name (file, buf);
       break;
 
     case CODE_LABEL:
       ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
-      assemble_name (asm_out_file, buf);
+      assemble_name (file, buf);
       break;
 
     case CONST_INT:
-      fprintf (file, "%d", INTVAL (x));
+      fprintf (file,
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
+              "%d",
+#else
+              "%ld",
+#endif
+              INTVAL (x));
       break;
 
     case CONST:
@@ -2087,12 +2655,39 @@ output_addr_const (file, x)
     case CONST_DOUBLE:
       if (GET_MODE (x) == VOIDmode)
        {
-         /* We can use %d if the number is <32 bits and positive.  */
-         if (CONST_DOUBLE_HIGH (x) || CONST_DOUBLE_LOW (x) < 0)
-           fprintf (file, "0x%x%08x",
+         /* We can use %d if the number is one word and positive.  */
+         if (CONST_DOUBLE_HIGH (x))
+           fprintf (file,
+#if HOST_BITS_PER_WIDE_INT == 64
+#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
+                    "0x%lx%016lx",
+#else
+                    "0x%x%016x",
+#endif
+#else
+#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
+                    "0x%lx%08lx",
+#else
+                    "0x%x%08x",
+#endif
+#endif
                     CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x));
+         else if  (CONST_DOUBLE_LOW (x) < 0)
+           fprintf (file,
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
+                    "0x%x",
+#else
+                    "0x%lx",
+#endif
+                    CONST_DOUBLE_LOW (x));
          else
-           fprintf (file, "%d", CONST_DOUBLE_LOW (x));
+           fprintf (file,
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
+                    "%d",
+#else
+                    "%ld",
+#endif
+                    CONST_DOUBLE_LOW (x));
        }
       else
        /* We can't handle floating point constants;
@@ -2119,9 +2714,28 @@ output_addr_const (file, x)
       break;
 
     case MINUS:
+      /* Avoid outputting things like x-x or x+5-x,
+        since some assemblers can't handle that.  */
+      x = simplify_subtraction (x);
+      if (GET_CODE (x) != MINUS)
+       goto restart;
+
       output_addr_const (file, XEXP (x, 0));
       fprintf (file, "-");
-      output_addr_const (file, XEXP (x, 1));
+      if (GET_CODE (XEXP (x, 1)) == CONST_INT
+         && INTVAL (XEXP (x, 1)) < 0)
+       {
+         fprintf (file, ASM_OPEN_PAREN);
+         output_addr_const (file, XEXP (x, 1));
+         fprintf (file, ASM_CLOSE_PAREN);
+       }
+      else
+       output_addr_const (file, XEXP (x, 1));
+      break;
+
+    case ZERO_EXTEND:
+    case SIGN_EXTEND:
+      output_addr_const (file, XEXP (x, 0));
       break;
 
     default:
@@ -2135,26 +2749,58 @@ output_addr_const (file, x)
    %U prints the value of USER_LABEL_PREFIX.
    %I prints the value of IMMEDIATE_PREFIX.
    %O runs ASM_OUTPUT_OPCODE to transform what follows in the string.
-   Also supported are %d, %x, %s, %e, %f, %g and %%.  */
+   Also supported are %d, %x, %s, %e, %f, %g and %%.
+
+   We handle alternate assembler dialects here, just like output_asm_insn.  */
 
 void
-asm_fprintf (va_alist)
-     va_dcl
+asm_fprintf VPROTO((FILE *file, char *p, ...))
 {
-  va_list argptr;
+#ifndef __STDC__
   FILE *file;
+  char *p;
+#endif
+  va_list argptr;
   char buf[10];
-  char *p, *q, c;
+  char *q, c;
+  int i;
 
-  va_start (argptr);
+  VA_START (argptr, p);
+
+#ifndef __STDC__
+  file = va_arg (argptr, FILE*);
+  p = va_arg (argptr, char*);
+#endif
 
-  file = va_arg (argptr, FILE *);
-  p = va_arg (argptr, char *);
   buf[0] = '%';
 
   while (c = *p++)
     switch (c)
       {
+#ifdef ASSEMBLER_DIALECT
+      case '{':
+       /* If we want the first dialect, do nothing.  Otherwise, skip
+          DIALECT_NUMBER of strings ending with '|'.  */
+       for (i = 0; i < dialect_number; i++)
+         {
+           while (*p && *p++ != '|')
+             ;
+
+           if (*p == '|')
+             p++;
+         }
+       break;
+
+      case '|':
+       /* Skip to close brace.  */
+       while (*p && *p++ != '}')
+         ;
+       break;
+
+      case '}':
+       break;
+#endif
+
       case '%':
        c = *p++;
        q = &buf[1];
@@ -2177,6 +2823,27 @@ asm_fprintf (va_alist)
            fprintf (file, buf, va_arg (argptr, int));
            break;
 
+         case 'w':
+           /* This is a prefix to the 'd', 'i', 'u', 'x', 'p', and 'X' cases,
+              but we do not check for those cases.  It means that the value
+              is a HOST_WIDE_INT, which may be either `int' or `long'.  */
+
+#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
+           *q++ = 'l';
+#endif
+
+           *q++ = *p++;
+           *q = 0;
+           fprintf (file, buf, va_arg (argptr, HOST_WIDE_INT));
+           break;
+
+         case 'l':
+           *q++ = c;
+           *q++ = *p++;
+           *q = 0;
+           fprintf (file, buf, va_arg (argptr, long));
+           break;
+
          case 'e':
          case 'f':
          case 'g':
@@ -2243,27 +2910,60 @@ split_double (value, first, second)
 {
   if (GET_CODE (value) == CONST_INT)
     {
-      /* The rule for using CONST_INT for a wider mode
-        is that we regard the value as signed.
-        So sign-extend it.  */
-      rtx high = (INTVAL (value) < 0 ? constm1_rtx : const0_rtx);
-#if WORDS_BIG_ENDIAN
-      *first = high;
-      *second = value;
-#else
-      *first = value;
-      *second = high;
-#endif
+      if (HOST_BITS_PER_WIDE_INT >= (2 * BITS_PER_WORD))
+       {
+         /* In this case the CONST_INT holds both target words.
+            Extract the bits from it into two word-sized pieces.  */
+         rtx low, high;
+         HOST_WIDE_INT word_mask;
+         /* Avoid warnings for shift count >= BITS_PER_WORD.  */
+         int shift_count = BITS_PER_WORD - 1;
+
+         word_mask = (HOST_WIDE_INT) 1 << shift_count;
+         word_mask |= word_mask - 1;
+         low = GEN_INT (INTVAL (value) & word_mask);
+         high = GEN_INT ((INTVAL (value) >> (shift_count + 1)) & word_mask);
+         if (WORDS_BIG_ENDIAN)
+           {
+             *first = high;
+             *second = low;
+           }
+         else
+           {
+             *first = low;
+             *second = high;
+           }
+       }
+      else
+       {
+         /* The rule for using CONST_INT for a wider mode
+            is that we regard the value as signed.
+            So sign-extend it.  */
+         rtx high = (INTVAL (value) < 0 ? constm1_rtx : const0_rtx);
+         if (WORDS_BIG_ENDIAN)
+           {
+             *first = high;
+             *second = value;
+           }
+         else
+           {
+             *first = value;
+             *second = high;
+           }
+       }
     }
   else if (GET_CODE (value) != CONST_DOUBLE)
     {
-#if WORDS_BIG_ENDIAN
-      *first = const0_rtx;
-      *second = value;
-#else
-      *first = value;
-      *second = const0_rtx;
-#endif
+      if (WORDS_BIG_ENDIAN)
+       {
+         *first = const0_rtx;
+         *second = value;
+       }
+      else
+       {
+         *first = value;
+         *second = const0_rtx;
+       }
     }
   else if (GET_MODE (value) == VOIDmode
           /* This is the old way we did CONST_DOUBLE integers.  */
@@ -2271,29 +2971,55 @@ split_double (value, first, second)
     {
       /* In an integer, the words are defined as most and least significant.
         So order them by the target's convention.  */
-#if WORDS_BIG_ENDIAN
-      *first = gen_rtx (CONST_INT, VOIDmode, CONST_DOUBLE_HIGH (value));
-      *second = gen_rtx (CONST_INT, VOIDmode, CONST_DOUBLE_LOW (value));
-#else
-      *first = gen_rtx (CONST_INT, VOIDmode, CONST_DOUBLE_LOW (value));
-      *second = gen_rtx (CONST_INT, VOIDmode, CONST_DOUBLE_HIGH (value));
-#endif
+      if (WORDS_BIG_ENDIAN)
+       {
+         *first = GEN_INT (CONST_DOUBLE_HIGH (value));
+         *second = GEN_INT (CONST_DOUBLE_LOW (value));
+       }
+      else
+       {
+         *first = GEN_INT (CONST_DOUBLE_LOW (value));
+         *second = GEN_INT (CONST_DOUBLE_HIGH (value));
+       }
     }
   else
     {
+#ifdef REAL_ARITHMETIC
+      REAL_VALUE_TYPE r; long l[2];
+      REAL_VALUE_FROM_CONST_DOUBLE (r, value);
+
+      /* Note, this converts the REAL_VALUE_TYPE to the target's
+        format, splits up the floating point double and outputs
+        exactly 32 bits of it into each of l[0] and l[1] --
+        not necessarily BITS_PER_WORD bits. */
+      REAL_VALUE_TO_TARGET_DOUBLE (r, l);
+
+      *first = GEN_INT ((HOST_WIDE_INT) l[0]);
+      *second = GEN_INT ((HOST_WIDE_INT) l[1]);
+#else
       if ((HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
-          || HOST_BITS_PER_INT != BITS_PER_WORD)
+          || HOST_BITS_PER_WIDE_INT != BITS_PER_WORD)
          && ! flag_pretend_float)
       abort ();
 
-#if defined (HOST_WORDS_BIG_ENDIAN) == WORDS_BIG_ENDIAN
-      /* Host and target agree => no need to swap.  */
-      *first = gen_rtx (CONST_INT, VOIDmode, CONST_DOUBLE_LOW (value));
-      *second = gen_rtx (CONST_INT, VOIDmode, CONST_DOUBLE_HIGH (value));
+      if (
+#ifdef HOST_WORDS_BIG_ENDIAN
+         WORDS_BIG_ENDIAN
 #else
-      *second = gen_rtx (CONST_INT, VOIDmode, CONST_DOUBLE_LOW (value));
-      *first = gen_rtx (CONST_INT, VOIDmode, CONST_DOUBLE_HIGH (value));
+         ! WORDS_BIG_ENDIAN
 #endif
+         )
+       {
+         /* Host and target agree => no need to swap.  */
+         *first = GEN_INT (CONST_DOUBLE_LOW (value));
+         *second = GEN_INT (CONST_DOUBLE_HIGH (value));
+       }
+      else
+       {
+         *second = GEN_INT (CONST_DOUBLE_LOW (value));
+         *first = GEN_INT (CONST_DOUBLE_HIGH (value));
+       }
+#endif /* no REAL_ARITHMETIC */
     }
 }
 \f
@@ -2352,7 +3078,8 @@ only_leaf_regs_used ()
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {
-      if (regs_ever_live[i] > permitted_reg_in_leaf_functions[i])
+      if ((regs_ever_live[i] || global_regs[i])
+         && ! permitted_reg_in_leaf_functions[i])
        return 0;
     }
   return 1;
@@ -2450,6 +3177,7 @@ leaf_renumber_regs_insn (in_rtx)
       case 's':
       case '0':
       case 'i':
+      case 'w':
       case 'n':
       case 'u':
        break;