OSDN Git Service

* pt.c (can_complete_type_without_circularity): Add static to
[pf3gnuchains/gcc-fork.git] / gcc / final.c
index fcaaf37..3b3dfcd 100644 (file)
@@ -1,6 +1,6 @@
 /* Convert RTL to assembler code and output it, for GNU compiler.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+   1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -68,6 +68,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "target.h"
 #include "debug.h"
 #include "expr.h"
+#include "profile.h"
+#include "cfglayout.h"
 
 #ifdef XCOFF_DEBUGGING_INFO
 #include "xcoffout.h"          /* Needed for external data
@@ -98,6 +100,12 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #define JUMP_TABLES_IN_TEXT_SECTION 0
 #endif
 
+#if defined(READONLY_DATA_SECTION) || defined(READONLY_DATA_SECTION_ASM_OP)
+#define HAVE_READONLY_DATA_SECTION 1
+#else
+#define HAVE_READONLY_DATA_SECTION 0
+#endif
+
 /* Last insn processed by final_scan_insn.  */
 static rtx debug_insn;
 rtx current_output_insn;
@@ -114,15 +122,12 @@ static int high_function_linenum;
 /* Filename of last NOTE.  */
 static const char *last_filename;
 
-/* Number of instrumented arcs when profile_arc_flag is set.  */
-extern int count_instrumented_edges;
-
 extern int length_unit_log; /* This is defined in insn-attrtab.c.  */
 
 /* Nonzero while outputting an `asm' with operands.
    This means that inconsistencies are the user's fault, so don't abort.
    The precise value is the insn being output, to pass to error_for_asm.  */
-static rtx this_is_asm_operands;
+rtx this_is_asm_operands;
 
 /* Number of operands of this insn, for an `asm' with operands.  */
 static unsigned int insn_noperands;
@@ -170,10 +175,6 @@ char regs_ever_live[FIRST_PSEUDO_REGISTER];
 
 int frame_pointer_needed;
 
-/* Assign unique numbers to labels generated for profiling.  */
-
-int profile_label_no;
-
 /* Number of unmatched NOTE_INSN_BLOCK_BEG notes we have seen.  */
 
 static int block_depth;
@@ -202,25 +203,16 @@ static char *line_note_exists;
 rtx current_insn_predicate;
 #endif
 
-/* Linked list to hold line numbers for each basic block.  */
-
-struct bb_list
+struct function_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 */
+  struct function_list *next;  /* next function */
+  const char *name;            /* function name */
+  long cfg_checksum;           /* function checksum */
+  long count_edges;            /* number of intrumented edges in this function */
 };
 
-/* Linked list to hold the strings for each file and function name output.  */
-
-struct bb_str
-{
-  struct bb_str *next;         /* pointer to next string */
-  const char *string;          /* string */
-  int label_num;               /* label number */
-  int length;                  /* string length */
-};
+static struct function_list *functions_head = 0;
+static struct function_list **functions_tail = &functions_head;
 
 #ifdef HAVE_ATTR_length
 static int asm_insn_count      PARAMS ((rtx));
@@ -261,137 +253,269 @@ init_final (filename)
 }
 
 /* Called at end of source file,
-   to output the block-profiling table for this entire compilation.  */
+   to output the arc-profiling table for this entire compilation.  */
 
 void
 end_final (filename)
      const char *filename;
 {
-  if (profile_arc_flag)
+  if (profile_arc_flag && profile_info.count_instrumented_edges)
     {
       char name[20];
-      int align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
-      int size, rounded;
-      int long_bytes = LONG_TYPE_SIZE / BITS_PER_UNIT;
-      int gcov_type_bytes = GCOV_TYPE_SIZE / BITS_PER_UNIT;
-      int pointer_bytes = POINTER_SIZE / BITS_PER_UNIT;
-      unsigned int align2 = LONG_TYPE_SIZE;
-
-      size = gcov_type_bytes * count_instrumented_edges;
-      rounded = size;
-
-      rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;
-      rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
-                * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
-
-      /* ??? This _really_ ought to be done with a structure layout
-        and with assemble_constructor.  If long_bytes != pointer_bytes
-        we'll be emitting unaligned data at some point.  */
-      if (long_bytes != pointer_bytes)
-       abort ();
+      tree string_type, string_cst;
+      tree structure_decl, structure_value, structure_pointer_type;
+      tree field_decl, decl_chain, value_chain;
+      tree sizeof_field_value, domain_type;
 
-      data_section ();
+      /* Build types.  */
+      string_type = build_pointer_type (char_type_node);
 
-      /* 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.
+      /* Libgcc2 bb structure.  */
+      structure_decl = make_node (RECORD_TYPE);
+      structure_pointer_type = build_pointer_type (structure_decl);
 
-         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.  */
+      /* Output the main header, of 7 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, libgcc2 uses this as a pointer to next ``struct bb''
 
-      ASM_OUTPUT_ALIGN (asm_out_file, align);
+         The following are GNU extensions:
 
-      ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 0);
+         5:  Number of bytes in this header.
+         6:  address of table of function checksums (LPBX7).  */
 
-      /* Zero word.  */
-      assemble_integer (const0_rtx, long_bytes, align2, 1);
+      /* The zero word.  */
+      decl_chain =
+       build_decl (FIELD_DECL, get_identifier ("zero_word"),
+                   long_integer_type_node);
+      value_chain = build_tree_list (decl_chain,
+                                    convert (long_integer_type_node,
+                                             integer_zero_node));
 
       /* Address of filename.  */
-      ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 1);
-      assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes,
-                       align2, 1);
+      {
+       char *cwd, *da_filename;
+       int da_filename_len;
+
+       field_decl =
+         build_decl (FIELD_DECL, get_identifier ("filename"), string_type);
+       TREE_CHAIN (field_decl) = decl_chain;
+       decl_chain = field_decl;
+
+       cwd = getpwd ();
+       da_filename_len = strlen (filename) + strlen (cwd) + 4 + 1;
+       da_filename = (char *) alloca (da_filename_len);
+       strcpy (da_filename, cwd);
+       strcat (da_filename, "/");
+       strcat (da_filename, filename);
+       strip_off_ending (da_filename, da_filename_len - 3);
+       strcat (da_filename, ".da");
+       da_filename_len = strlen (da_filename);
+       string_cst = build_string (da_filename_len + 1, da_filename);
+       domain_type = build_index_type (build_int_2 (da_filename_len, 0));
+       TREE_TYPE (string_cst)
+         = build_array_type (char_type_node, domain_type);
+       value_chain = tree_cons (field_decl,
+                                build1 (ADDR_EXPR, string_type, string_cst),
+                                value_chain);
+      }
 
-      /* Address of count table.  */
-      ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2);
-      assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes,
-                       align2, 1);
+      /* Table of counts.  */
+      {
+       tree gcov_type_type = make_unsigned_type (GCOV_TYPE_SIZE);
+       tree gcov_type_pointer_type = build_pointer_type (gcov_type_type);
+       tree domain_tree
+         = build_index_type (build_int_2 (profile_info.
+                                          count_instrumented_edges - 1, 0));
+       tree gcov_type_array_type
+         = build_array_type (gcov_type_type, domain_tree);
+       tree gcov_type_array_pointer_type
+         = build_pointer_type (gcov_type_array_type);
+       tree counts_table;
+
+       field_decl =
+         build_decl (FIELD_DECL, get_identifier ("counts"),
+                     gcov_type_pointer_type);
+       TREE_CHAIN (field_decl) = decl_chain;
+       decl_chain = field_decl;
+
+       /* No values.  */
+       counts_table
+         = build (VAR_DECL, gcov_type_array_type, NULL_TREE, NULL_TREE);
+       TREE_STATIC (counts_table) = 1;
+       ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2);
+       DECL_NAME (counts_table) = get_identifier (name);
+       assemble_variable (counts_table, 0, 0, 0);
+
+       value_chain = tree_cons (field_decl,
+                                build1 (ADDR_EXPR,
+                                        gcov_type_array_pointer_type,
+                                        counts_table), value_chain);
+      }
 
       /* Count of the # of instrumented arcs.  */
-      assemble_integer (GEN_INT (count_instrumented_edges),
-                       long_bytes, align2, 1);
+      field_decl
+       = build_decl (FIELD_DECL, get_identifier ("ncounts"),
+                     long_integer_type_node);
+      TREE_CHAIN (field_decl) = decl_chain;
+      decl_chain = field_decl;
+
+      value_chain = tree_cons (field_decl,
+                              convert (long_integer_type_node,
+                                       build_int_2 (profile_info.
+                                                    count_instrumented_edges,
+                                                    0)), value_chain);
+      /* Pointer to the next bb.  */
+      field_decl
+       = build_decl (FIELD_DECL, get_identifier ("next"),
+                     structure_pointer_type);
+      TREE_CHAIN (field_decl) = decl_chain;
+      decl_chain = field_decl;
+
+      value_chain = tree_cons (field_decl, null_pointer_node, value_chain);
+
+      /* sizeof(struct bb).  We'll set this after entire structure
+        is laid out.  */
+      field_decl
+       = build_decl (FIELD_DECL, get_identifier ("sizeof_bb"),
+                     long_integer_type_node);
+      TREE_CHAIN (field_decl) = decl_chain;
+      decl_chain = field_decl;
+
+      sizeof_field_value = tree_cons (field_decl, NULL, value_chain);
+      value_chain = sizeof_field_value;
+
+      /* struct bb_function [].  */
+      {
+       struct function_list *item;
+       int num_nodes;
+       tree checksum_field, arc_count_field, name_field;
+       tree domain;
+       tree array_value_chain = NULL_TREE;
+       tree bb_fn_struct_type;
+       tree bb_fn_struct_array_type;
+       tree bb_fn_struct_array_pointer_type;
+       tree bb_fn_struct_pointer_type;
+       tree field_value, field_value_chain;
 
-      /* Zero word (link field).  */
-      assemble_integer (const0_rtx, pointer_bytes, align2, 1);
+       bb_fn_struct_type = make_node (RECORD_TYPE);
 
-      assemble_integer (const0_rtx, pointer_bytes, align2, 1);
+       checksum_field = build_decl (FIELD_DECL, get_identifier ("checksum"),
+                                    long_integer_type_node);
 
-      /* Byte count for extended structure.  */
-      assemble_integer (GEN_INT (11 * UNITS_PER_WORD), long_bytes, align2, 1);
+       arc_count_field
+         = build_decl (FIELD_DECL, get_identifier ("arc_count"),
+                       integer_type_node);
+       TREE_CHAIN (checksum_field) = arc_count_field;
 
-      /* Address of function name table.  */
-      assemble_integer (const0_rtx, pointer_bytes, align2, 1);
+       name_field
+         = build_decl (FIELD_DECL, get_identifier ("name"), string_type);
+       TREE_CHAIN (arc_count_field) = name_field;
 
-      /* Address of line number and filename tables if debugging.  */
-      assemble_integer (const0_rtx, pointer_bytes, align2, 1);
-      assemble_integer (const0_rtx, pointer_bytes, align2, 1);
+       TYPE_FIELDS (bb_fn_struct_type) = checksum_field;
 
-      /* Space for extension ptr (link field).  */
-      assemble_integer (const0_rtx, UNITS_PER_WORD, align2, 1);
+       num_nodes = 0;
 
-      /* Output the file name changing the suffix to .d for
-        Sun tcov compatibility.  */
-      ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 1);
-      {
-       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, ".da");
-       assemble_string (data_file, strlen (data_file) + 1);
+       for (item = functions_head; item != 0; item = item->next)
+         num_nodes++;
+
+       /* Note that the array contains a terminator, hence no - 1.  */
+       domain = build_index_type (build_int_2 (num_nodes, 0));
+
+       bb_fn_struct_pointer_type = build_pointer_type (bb_fn_struct_type);
+       bb_fn_struct_array_type
+         = build_array_type (bb_fn_struct_type, domain);
+       bb_fn_struct_array_pointer_type
+         = build_pointer_type (bb_fn_struct_array_type);
+
+       layout_type (bb_fn_struct_type);
+       layout_type (bb_fn_struct_pointer_type);
+       layout_type (bb_fn_struct_array_type);
+       layout_type (bb_fn_struct_array_pointer_type);
+
+       for (item = functions_head; item != 0; item = item->next)
+         {
+           size_t name_len;
+
+           /* create constructor for structure.  */
+           field_value_chain
+             = build_tree_list (checksum_field,
+                                convert (long_integer_type_node,
+                                         build_int_2 (item->cfg_checksum, 0)));
+           field_value_chain
+             = tree_cons (arc_count_field,
+                          convert (integer_type_node,
+                                   build_int_2 (item->count_edges, 0)),
+                          field_value_chain);
+
+           name_len = strlen (item->name);
+           string_cst = build_string (name_len + 1, item->name);
+           domain_type = build_index_type (build_int_2 (name_len, 0));
+           TREE_TYPE (string_cst)
+             = build_array_type (char_type_node, domain_type);
+           field_value_chain = tree_cons (name_field,
+                                          build1 (ADDR_EXPR, string_type,
+                                                  string_cst),
+                                          field_value_chain);
+
+           /* Add to chain.  */
+           array_value_chain
+             = tree_cons (NULL_TREE, build (CONSTRUCTOR,
+                                            bb_fn_struct_type, NULL_TREE,
+                                            nreverse (field_value_chain)),
+                          array_value_chain);
+         }
+
+       /* Add terminator.  */
+       field_value = build_tree_list (arc_count_field,
+                                      convert (integer_type_node,
+                                               build_int_2 (-1, 0)));
+
+       array_value_chain = tree_cons (NULL_TREE,
+                                      build (CONSTRUCTOR, bb_fn_struct_type,
+                                             NULL_TREE, field_value),
+                                      array_value_chain);
+
+
+       /* Create constructor for array.  */
+       field_decl
+         = build_decl (FIELD_DECL, get_identifier ("function_infos"),
+                       bb_fn_struct_pointer_type);
+       value_chain = tree_cons (field_decl,
+                                build1 (ADDR_EXPR,
+                                        bb_fn_struct_array_pointer_type,
+                                        build (CONSTRUCTOR,
+                                               bb_fn_struct_array_type,
+                                               NULL_TREE,
+                                               nreverse
+                                               (array_value_chain))),
+                                value_chain);
+       TREE_CHAIN (field_decl) = decl_chain;
+       decl_chain = field_decl;
       }
 
-      /* Make space for the table of counts.  */
-      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_DECL_LOCAL
-           ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, NULL_TREE, name,
-                                          size, BIGGEST_ALIGNMENT);
-#else
-#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
-#endif
-       }
+      /* Finish structure.  */
+      TYPE_FIELDS (structure_decl) = nreverse (decl_chain);
+      layout_type (structure_decl);
+
+      structure_value
+       = build (VAR_DECL, structure_decl, NULL_TREE, NULL_TREE);
+      DECL_INITIAL (structure_value)
+       = build (CONSTRUCTOR, structure_decl, NULL_TREE,
+                nreverse (value_chain));
+      TREE_STATIC (structure_value) = 1;
+      ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 0);
+      DECL_NAME (structure_value) = get_identifier (name);
+
+      /* Size of this structure.  */
+      TREE_VALUE (sizeof_field_value)
+       = convert (long_integer_type_node,
+                  build_int_2 (int_size_in_bytes (structure_decl), 0));
+
+      /* Build structure.  */
+      assemble_variable (structure_value, 0, 0, 0);
     }
 }
 
@@ -462,9 +586,7 @@ dbr_sequence_length ()
 
 static int *insn_lengths;
 
-#ifdef HAVE_ATTR_length
 varray_type insn_addresses_;
-#endif
 
 /* Max uid for which the above arrays are valid.  */
 static int insn_lengths_max_uid;
@@ -475,7 +597,7 @@ int insn_current_address;
 /* Address of insn being processed in previous iteration.  */
 int insn_last_address;
 
-/* konwn invariant alignment of insn being processed.  */
+/* known invariant alignment of insn being processed.  */
 int insn_current_align;
 
 /* After shorten_branches, for any insn, uid_align[INSN_UID (insn)]
@@ -551,7 +673,7 @@ get_attr_length (insn)
 
       case JUMP_INSN:
        body = PATTERN (insn);
-        if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
+       if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
          {
            /* Alignment is machine-dependent and should be handled by
               ADDR_VEC_ALIGN.  */
@@ -717,7 +839,7 @@ label_to_alignment (label)
    For casesi tables, we also want to know worst case minimum amounts of
    address difference, in case a machine description wants to introduce
    some common offset that is added to all offsets in a table.
-   For this purpose, align_fuzz with a growth argument of 0 comuptes the
+   For this purpose, align_fuzz with a growth argument of 0 computes the
    appropriate adjustment.  */
 
 /* Compute the maximum delta by which the difference of the addresses of
@@ -811,8 +933,8 @@ insn_current_reference_address (branch)
 void
 compute_alignments ()
 {
-  int i;
   int log, max_skip, max_log;
+  basic_block bb;
 
   if (label_align)
     {
@@ -829,9 +951,8 @@ compute_alignments ()
   if (! optimize || optimize_size)
     return;
 
-  for (i = 0; i < n_basic_blocks; i++)
+  FOR_EACH_BB (bb)
     {
-      basic_block bb = BASIC_BLOCK (i);
       rtx label = bb->head;
       int fallthru_frequency = 0, branch_frequency = 0, has_fallthru = 0;
       edge e;
@@ -851,7 +972,7 @@ compute_alignments ()
 
       /* There are two purposes to align block with no fallthru incoming edge:
         1) to avoid fetch stalls when branch destination is near cache boundary
-        2) to improve cache effciency in case the previous block is not executed
+        2) to improve cache efficiency in case the previous block is not executed
            (so it does not need to be in the cache).
 
         We to catch first case, we align frequently executed blocks.
@@ -861,8 +982,8 @@ compute_alignments ()
 
       if (!has_fallthru
          && (branch_frequency > BB_FREQ_MAX / 10
-             || (bb->frequency > BASIC_BLOCK (i - 1)->frequency * 10
-                 && (BASIC_BLOCK (i - 1)->frequency
+             || (bb->frequency > bb->prev_bb->frequency * 10
+                 && (bb->prev_bb->frequency
                      <= ENTRY_BLOCK_PTR->frequency / 2))))
        {
          log = JUMP_ALIGN (label);
@@ -903,7 +1024,7 @@ compute_alignments ()
    port splits out-of-range conditional branches in MACHINE_DEPENDENT_REORG.
    In order to do this, it needs proper length information, which it obtains
    by calling shorten_branches.  This cannot be collapsed with
-   shorten_branches itself into a single pass unless we also want to intergate
+   shorten_branches itself into a single pass unless we also want to integrate
    reorg.c, since the branch splitting exposes new instructions with delay
    slots.  */
 
@@ -980,7 +1101,7 @@ shorten_branches (first)
       else if (GET_CODE (insn) == CODE_LABEL)
        {
          rtx next;
-         
+
          /* Merge in alignments computed by compute_alignments.  */
          log = LABEL_TO_ALIGNMENT (insn);
          if (max_log < log)
@@ -998,11 +1119,7 @@ shorten_branches (first)
          next = NEXT_INSN (insn);
          /* ADDR_VECs only take room if read-only data goes into the text
             section.  */
-         if (JUMP_TABLES_IN_TEXT_SECTION
-#if !defined(READONLY_DATA_SECTION)
-             || 1
-#endif
-             )
+         if (JUMP_TABLES_IN_TEXT_SECTION || !HAVE_READONLY_DATA_SECTION)
            if (next && GET_CODE (next) == JUMP_INSN)
              {
                rtx nextbody = PATTERN (next);
@@ -1165,11 +1282,7 @@ shorten_branches (first)
        {
          /* This only takes room if read-only data goes into the text
             section.  */
-         if (JUMP_TABLES_IN_TEXT_SECTION
-#if !defined(READONLY_DATA_SECTION)
-             || 1
-#endif
-             )
+         if (JUMP_TABLES_IN_TEXT_SECTION || !HAVE_READONLY_DATA_SECTION)
            insn_lengths[uid] = (XVECLEN (body,
                                          GET_CODE (body) == ADDR_DIFF_VEC)
                                 * GET_MODE_SIZE (GET_MODE (body)));
@@ -1370,11 +1483,7 @@ shorten_branches (first)
              PUT_MODE (body, CASE_VECTOR_SHORTEN_MODE (min_addr - rel_addr,
                                                        max_addr - rel_addr,
                                                        body));
-             if (JUMP_TABLES_IN_TEXT_SECTION
-#if !defined(READONLY_DATA_SECTION)
-                 || 1
-#endif
-                 )
+             if (JUMP_TABLES_IN_TEXT_SECTION || !HAVE_READONLY_DATA_SECTION)
                {
                  insn_lengths[uid]
                    = (XVECLEN (body, 1) * GET_MODE_SIZE (GET_MODE (body)));
@@ -1404,7 +1513,7 @@ shorten_branches (first)
 
                      insn_current_address += insn_lengths[inner_uid];
                    }
-                }
+               }
              else
                insn_current_address += insn_lengths[uid];
 
@@ -1547,7 +1656,7 @@ final_start_function (first, file, optimize)
   /* The Sun386i and perhaps other machines don't work right
      if the profiling code comes after the prologue.  */
 #ifdef PROFILE_BEFORE_PROLOGUE
-  if (profile_flag)
+  if (current_function_profile)
     profile_function (file);
 #endif /* PROFILE_BEFORE_PROLOGUE */
 
@@ -1561,7 +1670,7 @@ final_start_function (first, file, optimize)
   if (write_symbols)
     {
       remove_unnecessary_notes ();
-      reorder_blocks ();
+      scope_to_insns_finalize ();
       number_blocks (current_function_decl);
       /* We never actually put out begin/end notes for the top-level
         block in the function.  But, conceptually, that block is
@@ -1584,8 +1693,6 @@ final_start_function (first, file, optimize)
   if (! HAVE_prologue)
 #endif
     profile_after_prologue (file);
-
-  profile_label_no++;
 }
 
 static void
@@ -1593,7 +1700,7 @@ profile_after_prologue (file)
      FILE *file ATTRIBUTE_UNUSED;
 {
 #ifndef PROFILE_BEFORE_PROLOGUE
-  if (profile_flag)
+  if (current_function_profile)
     profile_function (file);
 #endif /* not PROFILE_BEFORE_PROLOGUE */
 }
@@ -1617,7 +1724,7 @@ profile_function (file)
 #ifndef NO_PROFILE_COUNTERS
   data_section ();
   ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
-  ASM_OUTPUT_INTERNAL_LABEL (file, "LP", profile_label_no);
+  ASM_OUTPUT_INTERNAL_LABEL (file, "LP", current_function_funcdef_no);
   assemble_integer (const0_rtx, LONG_TYPE_SIZE / BITS_PER_UNIT, align, 1);
 #endif
 
@@ -1647,7 +1754,7 @@ profile_function (file)
 #endif
 #endif
 
-  FUNCTION_PROFILER (file, profile_label_no);
+  FUNCTION_PROFILER (file, current_function_funcdef_no);
 
 #if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
   if (cxt)
@@ -1789,16 +1896,12 @@ final (first, file, optimize, prescan)
 #ifdef HAVE_ATTR_length
       if ((unsigned) INSN_UID (insn) >= INSN_ADDRESSES_SIZE ())
        {
-#ifdef STACK_REGS
-         /* Irritatingly, the reg-stack pass is creating new instructions
-            and because of REG_DEAD note abuse it has to run after
-            shorten_branches.  Fake address of -1 then.  */
-         insn_current_address = -1;
-#else
          /* This can be triggered by bugs elsewhere in the compiler if
             new insns are created after init_insn_lengths is called.  */
-         abort ();
-#endif
+         if (GET_CODE (insn) == NOTE)
+           insn_current_address = -1;
+         else
+           abort ();
        }
       else
        insn_current_address = INSN_ADDRESSES (INSN_UID (insn));
@@ -1807,6 +1910,22 @@ final (first, file, optimize, prescan)
       insn = final_scan_insn (insn, file, optimize, prescan, 0);
     }
 
+  /* Store function names for edge-profiling.  */
+  /* ??? Probably should re-use the existing struct function.  */
+
+  if (cfun->arc_profile)
+    {
+      struct function_list *new_item = xmalloc (sizeof (struct function_list));
+
+      *functions_tail = new_item;
+      functions_tail = &new_item->next;
+
+      new_item->next = 0;
+      new_item->name = xstrdup (current_function_name);
+      new_item->cfg_checksum = profile_info.current_function_cfg_checksum;
+      new_item->count_edges = profile_info.count_edges_instrumented_now;
+    }
+
   free (line_note_exists);
   line_note_exists = NULL;
 }
@@ -1871,13 +1990,11 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
        case NOTE_INSN_DELETED:
        case NOTE_INSN_LOOP_BEG:
        case NOTE_INSN_LOOP_END:
+       case NOTE_INSN_LOOP_END_TOP_COND:
        case NOTE_INSN_LOOP_CONT:
        case NOTE_INSN_LOOP_VTOP:
        case NOTE_INSN_FUNCTION_END:
        case NOTE_INSN_REPEATED_LINE_NUMBER:
-       case NOTE_INSN_RANGE_BEG:
-       case NOTE_INSN_RANGE_END:
-       case NOTE_INSN_LIVE:
        case NOTE_INSN_EXPECTED_VALUE:
          break;
 
@@ -2392,7 +2509,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
                        && 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)
+                   if (! FIND_REG_INC_NOTE (insn, NULL_RTX)
                        /* or if anything in it is volatile.  */
                        && ! volatile_refs_p (PATTERN (insn)))
                      {
@@ -2564,13 +2681,13 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
        insn_code_number = recog_memoized (insn);
        cleanup_subreg_operands (insn);
 
-       /* Dump the insn in the assembly for debugging.  */
-       if (flag_dump_rtl_in_asm)
-         {
-           print_rtx_head = ASM_COMMENT_START;
-           print_rtl_single (asm_out_file, insn);
-           print_rtx_head = "";
-         }
+       /* Dump the insn in the assembly for debugging.  */
+       if (flag_dump_rtl_in_asm)
+         {
+           print_rtx_head = ASM_COMMENT_START;
+           print_rtl_single (asm_out_file, insn);
+           print_rtx_head = "";
+         }
 
        if (! constrain_operands_cached (1))
          fatal_insn_not_found (insn);
@@ -2774,12 +2891,13 @@ alter_subreg (xp)
       /* Simplify_subreg can't handle some REG cases, but we have to.  */
       else if (GET_CODE (y) == REG)
        {
-         REGNO (x) = subreg_hard_regno (x, 1);
+         unsigned int regno = subreg_hard_regno (x, 1);
          PUT_CODE (x, REG);
+         REGNO (x) = regno;
          ORIGINAL_REGNO (x) = ORIGINAL_REGNO (y);
          /* This field has a different meaning for REGs and SUBREGs.  Make
             sure to clear it!  */
-         x->used = 0;
+         RTX_FLAG (x, used) = 0;
        }
       else
        abort ();
@@ -2983,13 +3101,26 @@ alter_cond (cond)
    In an `asm', it's the user's fault; otherwise, the compiler's fault.  */
 
 void
-output_operand_lossage (msgid)
-     const char *msgid;
+output_operand_lossage VPARAMS ((const char *msgid, ...))
 {
+  char *fmt_string;
+  char *new_message;
+  const char *pfx_str;
+  VA_OPEN (ap, msgid);
+  VA_FIXEDARG (ap, const char *, msgid);
+
+  pfx_str = this_is_asm_operands ? _("invalid `asm': ") : "output_operand: ";
+  asprintf (&fmt_string, "%s%s", pfx_str, _(msgid));
+  vasprintf (&new_message, fmt_string, ap);
+
   if (this_is_asm_operands)
-    error_for_asm (this_is_asm_operands, "invalid `asm': %s", _(msgid));
+    error_for_asm (this_is_asm_operands, "%s", new_message);
   else
-    internal_error ("output_operand: %s", _(msgid));
+    internal_error ("%s", new_message);
+
+  free (fmt_string);
+  free (new_message);
+  VA_CLOSE (ap);
 }
 \f
 /* Output of assembler code from a template, and its subroutines.  */
@@ -3032,6 +3163,9 @@ get_mem_expr_from_op (op, paddressp)
 
   *paddressp = 0;
 
+  if (op == NULL)
+    return 0;
+
   if (GET_CODE (op) == REG && ORIGINAL_REGNO (op) >= FIRST_PSEUDO_REGISTER)
     return REGNO_DECL (ORIGINAL_REGNO (op));
   else if (GET_CODE (op) != MEM)
@@ -3060,7 +3194,7 @@ get_mem_expr_from_op (op, paddressp)
   expr = get_mem_expr_from_op (op, &inner_addressp);
   return inner_addressp ? 0 : expr;
 }
-  
+
 /* Output operand names for assembler instructions.  OPERANDS is the
    operand vector, OPORDER is the order to write the operands, and NOPS
    is the number of operands to write.  */
@@ -3194,7 +3328,7 @@ output_asm_insn (template, operands)
                    output_operand_lossage ("unterminated assembly dialect alternative");
                    break;
                  }
-             }   
+             }
            while (*p++ != '}');
            dialect = 0;
          }
@@ -3235,7 +3369,7 @@ output_asm_insn (template, operands)
            c = atoi (p);
 
            if (! ISDIGIT (*p))
-             output_operand_lossage ("operand number missing after %-letter");
+             output_operand_lossage ("operand number missing after %%-letter");
            else if (this_is_asm_operands
                     && (c < 0 || (unsigned int) c >= insn_noperands))
              output_operand_lossage ("operand number out of range");
@@ -3327,7 +3461,7 @@ output_asm_label (x)
          && NOTE_LINE_NUMBER (x) == NOTE_INSN_DELETED_LABEL))
     ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
   else
-    output_operand_lossage ("`%l' operand isn't a label");
+    output_operand_lossage ("`%%l' operand isn't a label");
 
   assemble_name (asm_out_file, buf);
 }
@@ -3465,20 +3599,21 @@ output_addr_const (file, x)
 
       output_addr_const (file, XEXP (x, 0));
       fprintf (file, "-");
-      if ((GET_CODE (XEXP (x, 1)) == CONST_INT
-          && INTVAL (XEXP (x, 1)) < 0)
-         || GET_CODE (XEXP (x, 1)) != CONST_INT)
+      if ((GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) >= 0)
+         || GET_CODE (XEXP (x, 1)) == PC
+         || GET_CODE (XEXP (x, 1)) == SYMBOL_REF)
+       output_addr_const (file, XEXP (x, 1));
+      else
        {
          fputs (targetm.asm_out.open_paren, file);
          output_addr_const (file, XEXP (x, 1));
          fputs (targetm.asm_out.close_paren, file);
        }
-      else
-       output_addr_const (file, XEXP (x, 1));
       break;
 
     case ZERO_EXTEND:
     case SIGN_EXTEND:
+    case SUBREG:
       output_addr_const (file, XEXP (x, 0));
       break;
 
@@ -3775,7 +3910,6 @@ split_double (value, first, second)
     }
   else
     {
-#ifdef REAL_ARITHMETIC
       REAL_VALUE_TYPE r;
       long l[2];
       REAL_VALUE_FROM_CONST_DOUBLE (r, value);
@@ -3804,30 +3938,6 @@ split_double (value, first, second)
 
       *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_WIDE_INT != BITS_PER_WORD)
-         && ! flag_pretend_float)
-       abort ();
-
-      if (
-#ifdef HOST_WORDS_BIG_ENDIAN
-         WORDS_BIG_ENDIAN
-#else
-         ! 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
@@ -3839,7 +3949,7 @@ leaf_function_p ()
   rtx insn;
   rtx link;
 
-  if (profile_flag || profile_arc_flag)
+  if (current_function_profile || profile_arc_flag)
     return 0;
 
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))