OSDN Git Service

* common.opt (main_input_filename, main_input_basename,
[pf3gnuchains/gcc-fork.git] / gcc / final.c
index a33da0c..ebe21b6 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,
 /* 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, 2002, 2003, 2004, 2005, 2006, 2007
+   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
 
 This file is part of GCC.
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -58,20 +58,22 @@ along with GCC; see the file COPYING3.  If not see
 #include "recog.h"
 #include "conditions.h"
 #include "flags.h"
 #include "recog.h"
 #include "conditions.h"
 #include "flags.h"
-#include "real.h"
 #include "hard-reg-set.h"
 #include "output.h"
 #include "except.h"
 #include "function.h"
 #include "hard-reg-set.h"
 #include "output.h"
 #include "except.h"
 #include "function.h"
-#include "toplev.h"
+#include "rtl-error.h"
+#include "toplev.h" /* exact_log2, floor_log2 */
 #include "reload.h"
 #include "intl.h"
 #include "basic-block.h"
 #include "target.h"
 #include "reload.h"
 #include "intl.h"
 #include "basic-block.h"
 #include "target.h"
+#include "targhooks.h"
 #include "debug.h"
 #include "expr.h"
 #include "cfglayout.h"
 #include "tree-pass.h"
 #include "debug.h"
 #include "expr.h"
 #include "cfglayout.h"
 #include "tree-pass.h"
+#include "tree-flow.h"
 #include "timevar.h"
 #include "cgraph.h"
 #include "coverage.h"
 #include "timevar.h"
 #include "cgraph.h"
 #include "coverage.h"
@@ -86,9 +88,7 @@ along with GCC; see the file COPYING3.  If not see
                                   declarations for e.g. AIX 4.x.  */
 #endif
 
                                   declarations for e.g. AIX 4.x.  */
 #endif
 
-#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
 #include "dwarf2out.h"
 #include "dwarf2out.h"
-#endif
 
 #ifdef DBX_DEBUGGING_INFO
 #include "dbxout.h"
 
 #ifdef DBX_DEBUGGING_INFO
 #include "dbxout.h"
@@ -98,8 +98,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "sdbout.h"
 #endif
 
 #include "sdbout.h"
 #endif
 
-/* If we aren't using cc0, CC_STATUS_INIT shouldn't exist.  So define a
-   null default for it to save conditionalization later.  */
+/* Most ports that aren't using cc0 don't need to define CC_STATUS_INIT.
+   So define a null default for it to save conditionalization later.  */
 #ifndef CC_STATUS_INIT
 #define CC_STATUS_INIT
 #endif
 #ifndef CC_STATUS_INIT
 #define CC_STATUS_INIT
 #endif
@@ -130,6 +130,12 @@ rtx current_output_insn;
 /* Line number of last NOTE.  */
 static int last_linenum;
 
 /* Line number of last NOTE.  */
 static int last_linenum;
 
+/* Last discriminator written to assembly.  */
+static int last_discriminator;
+
+/* Discriminator of current block.  */
+static int discriminator;
+
 /* Highest line number in current block.  */
 static int high_block_linenum;
 
 /* Highest line number in current block.  */
 static int high_block_linenum;
 
@@ -178,12 +184,6 @@ CC_STATUS cc_status;
 CC_STATUS cc_prev_status;
 #endif
 
 CC_STATUS cc_prev_status;
 #endif
 
-/* Nonzero means current function must be given a frame pointer.
-   Initialized in function.c to 0.  Set only in reload1.c as per
-   the needs of the function.  */
-
-int frame_pointer_needed;
-
 /* Number of unmatched NOTE_INSN_BLOCK_BEG notes we have seen.  */
 
 static int block_depth;
 /* Number of unmatched NOTE_INSN_BLOCK_BEG notes we have seen.  */
 
 static int block_depth;
@@ -203,23 +203,23 @@ rtx final_sequence;
 static int dialect_number;
 #endif
 
 static int dialect_number;
 #endif
 
-#ifdef HAVE_conditional_execution
 /* Nonnull if the insn currently being emitted was a COND_EXEC pattern.  */
 rtx current_insn_predicate;
 /* Nonnull if the insn currently being emitted was a COND_EXEC pattern.  */
 rtx current_insn_predicate;
-#endif
+
+/* True if printing into -fdump-final-insns= dump.  */   
+bool final_insns_dump_p;
 
 #ifdef HAVE_ATTR_length
 static int asm_insn_count (rtx);
 #endif
 static void profile_function (FILE *);
 static void profile_after_prologue (FILE *);
 
 #ifdef HAVE_ATTR_length
 static int asm_insn_count (rtx);
 #endif
 static void profile_function (FILE *);
 static void profile_after_prologue (FILE *);
-static bool notice_source_line (rtx);
+static bool notice_source_line (rtx, bool *);
 static rtx walk_alter_subreg (rtx *, bool *);
 static void output_asm_name (void);
 static void output_alternate_entry_point (FILE *, rtx);
 static tree get_mem_expr_from_op (rtx, int *);
 static void output_asm_operand_names (rtx *, int *, int);
 static rtx walk_alter_subreg (rtx *, bool *);
 static void output_asm_name (void);
 static void output_alternate_entry_point (FILE *, rtx);
 static tree get_mem_expr_from_op (rtx, int *);
 static void output_asm_operand_names (rtx *, int *, int);
-static void output_operand (rtx, int);
 #ifdef LEAF_REGISTERS
 static void leaf_renumber_regs (rtx);
 #endif
 #ifdef LEAF_REGISTERS
 static void leaf_renumber_regs (rtx);
 #endif
@@ -390,6 +390,7 @@ get_attr_length_1 (rtx insn ATTRIBUTE_UNUSED,
       case NOTE:
       case BARRIER:
       case CODE_LABEL:
       case NOTE:
       case BARRIER:
       case CODE_LABEL:
+      case DEBUG_INSN:
        return 0;
 
       case CALL_INSN:
        return 0;
 
       case CALL_INSN:
@@ -416,7 +417,7 @@ get_attr_length_1 (rtx insn ATTRIBUTE_UNUSED,
          length = asm_insn_count (body) * fallback_fn (insn);
        else if (GET_CODE (body) == SEQUENCE)
          for (i = 0; i < XVECLEN (body, 0); i++)
          length = asm_insn_count (body) * fallback_fn (insn);
        else if (GET_CODE (body) == SEQUENCE)
          for (i = 0; i < XVECLEN (body, 0); i++)
-           length += get_attr_length (XVECEXP (body, 0, i));
+           length += get_attr_length_1 (XVECEXP (body, 0, i), fallback_fn);
        else
          length = fallback_fn (insn);
        break;
        else
          length = fallback_fn (insn);
        break;
@@ -497,33 +498,41 @@ get_attr_min_length (rtx insn)
 #define LABEL_ALIGN(LABEL) align_labels_log
 #endif
 
 #define LABEL_ALIGN(LABEL) align_labels_log
 #endif
 
-#ifndef LABEL_ALIGN_MAX_SKIP
-#define LABEL_ALIGN_MAX_SKIP align_labels_max_skip
-#endif
-
 #ifndef LOOP_ALIGN
 #define LOOP_ALIGN(LABEL) align_loops_log
 #endif
 
 #ifndef LOOP_ALIGN
 #define LOOP_ALIGN(LABEL) align_loops_log
 #endif
 
-#ifndef LOOP_ALIGN_MAX_SKIP
-#define LOOP_ALIGN_MAX_SKIP align_loops_max_skip
-#endif
-
 #ifndef LABEL_ALIGN_AFTER_BARRIER
 #define LABEL_ALIGN_AFTER_BARRIER(LABEL) 0
 #endif
 
 #ifndef LABEL_ALIGN_AFTER_BARRIER
 #define LABEL_ALIGN_AFTER_BARRIER(LABEL) 0
 #endif
 
-#ifndef LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP
-#define LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP 0
-#endif
-
 #ifndef JUMP_ALIGN
 #define JUMP_ALIGN(LABEL) align_jumps_log
 #endif
 
 #ifndef JUMP_ALIGN
 #define JUMP_ALIGN(LABEL) align_jumps_log
 #endif
 
-#ifndef JUMP_ALIGN_MAX_SKIP
-#define JUMP_ALIGN_MAX_SKIP align_jumps_max_skip
-#endif
+int
+default_label_align_after_barrier_max_skip (rtx insn ATTRIBUTE_UNUSED)
+{
+  return 0;
+}
+
+int
+default_loop_align_max_skip (rtx insn ATTRIBUTE_UNUSED)
+{
+  return align_loops_max_skip;
+}
+
+int
+default_label_align_max_skip (rtx insn ATTRIBUTE_UNUSED)
+{
+  return align_labels_max_skip;
+}
+
+int
+default_jump_align_max_skip (rtx insn ATTRIBUTE_UNUSED)
+{
+  return align_jumps_max_skip;
+}
 
 #ifndef ADDR_VEC_ALIGN
 static int
 
 #ifndef ADDR_VEC_ALIGN
 static int
@@ -559,7 +568,17 @@ static int min_labelno, max_labelno;
 int
 label_to_alignment (rtx label)
 {
 int
 label_to_alignment (rtx label)
 {
-  return LABEL_TO_ALIGNMENT (label);
+  if (CODE_LABEL_NUMBER (label) <= max_labelno)
+    return LABEL_TO_ALIGNMENT (label);
+  return 0;
+}
+
+int
+label_to_max_skip (rtx label)
+{
+  if (CODE_LABEL_NUMBER (label) <= max_labelno)
+    return LABEL_TO_MAX_SKIP (label);
+  return 0;
 }
 
 #ifdef HAVE_ATTR_length
 }
 
 #ifdef HAVE_ATTR_length
@@ -670,7 +689,7 @@ insn_current_reference_address (rtx branch)
 /* Compute branch alignments based on frequency information in the
    CFG.  */
 
 /* Compute branch alignments based on frequency information in the
    CFG.  */
 
-static unsigned int
+unsigned int
 compute_alignments (void)
 {
   int log, max_skip, max_log;
 compute_alignments (void)
 {
   int log, max_skip, max_log;
@@ -689,15 +708,15 @@ compute_alignments (void)
   label_align = XCNEWVEC (struct label_alignment, max_labelno - min_labelno + 1);
 
   /* If not optimizing or optimizing for size, don't assign any alignments.  */
   label_align = XCNEWVEC (struct label_alignment, max_labelno - min_labelno + 1);
 
   /* If not optimizing or optimizing for size, don't assign any alignments.  */
-  if (! optimize || optimize_size)
+  if (! optimize || optimize_function_for_size_p (cfun))
     return 0;
 
   if (dump_file)
     {
       dump_flow_info (dump_file, TDF_DETAILS);
       flow_loops_dump (dump_file, NULL, 1);
     return 0;
 
   if (dump_file)
     {
       dump_flow_info (dump_file, TDF_DETAILS);
       flow_loops_dump (dump_file, NULL, 1);
-      loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
     }
     }
+  loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
   FOR_EACH_BB (bb)
     if (bb->frequency > freq_max)
       freq_max = bb->frequency;
   FOR_EACH_BB (bb)
     if (bb->frequency > freq_max)
       freq_max = bb->frequency;
@@ -713,7 +732,7 @@ compute_alignments (void)
       edge_iterator ei;
 
       if (!LABEL_P (label)
       edge_iterator ei;
 
       if (!LABEL_P (label)
-         || probably_never_executed_bb_p (bb))
+         || optimize_bb_for_size_p (bb))
        {
          if (dump_file)
            fprintf(dump_file, "BB %4i freq %4i loop %2i loop_depth %2i skipped.\n",
        {
          if (dump_file)
            fprintf(dump_file, "BB %4i freq %4i loop %2i loop_depth %2i skipped.\n",
@@ -721,7 +740,7 @@ compute_alignments (void)
          continue;
        }
       max_log = LABEL_ALIGN (label);
          continue;
        }
       max_log = LABEL_ALIGN (label);
-      max_skip = LABEL_ALIGN_MAX_SKIP;
+      max_skip = targetm.asm_out.label_align_max_skip (label);
 
       FOR_EACH_EDGE (e, ei, bb->preds)
        {
 
       FOR_EACH_EDGE (e, ei, bb->preds)
        {
@@ -765,13 +784,13 @@ compute_alignments (void)
          if (max_log < log)
            {
              max_log = log;
          if (max_log < log)
            {
              max_log = log;
-             max_skip = JUMP_ALIGN_MAX_SKIP;
+             max_skip = targetm.asm_out.jump_align_max_skip (label);
            }
        }
       /* In case block is frequent and reached mostly by non-fallthru edge,
         align it.  It is most likely a first block of loop.  */
       if (has_fallthru
            }
        }
       /* In case block is frequent and reached mostly by non-fallthru edge,
         align it.  It is most likely a first block of loop.  */
       if (has_fallthru
-         && maybe_hot_bb_p (bb)
+         && optimize_bb_for_speed_p (bb)
          && branch_frequency + fallthru_frequency > freq_threshold
          && (branch_frequency
              > fallthru_frequency * PARAM_VALUE (PARAM_ALIGN_LOOP_ITERATIONS)))
          && branch_frequency + fallthru_frequency > freq_threshold
          && (branch_frequency
              > fallthru_frequency * PARAM_VALUE (PARAM_ALIGN_LOOP_ITERATIONS)))
@@ -782,34 +801,36 @@ compute_alignments (void)
          if (max_log < log)
            {
              max_log = log;
          if (max_log < log)
            {
              max_log = log;
-             max_skip = LOOP_ALIGN_MAX_SKIP;
+             max_skip = targetm.asm_out.loop_align_max_skip (label);
            }
        }
       LABEL_TO_ALIGNMENT (label) = max_log;
       LABEL_TO_MAX_SKIP (label) = max_skip;
     }
 
            }
        }
       LABEL_TO_ALIGNMENT (label) = max_log;
       LABEL_TO_MAX_SKIP (label) = max_skip;
     }
 
-  if (dump_file)
-    loop_optimizer_finalize ();
+  loop_optimizer_finalize ();
+  free_dominance_info (CDI_DOMINATORS);
   return 0;
 }
 
   return 0;
 }
 
-struct tree_opt_pass pass_compute_alignments =
+struct rtl_opt_pass pass_compute_alignments =
 {
 {
+ {
+  RTL_PASS,
   "alignments",                         /* name */
   NULL,                                 /* gate */
   compute_alignments,                   /* execute */
   NULL,                                 /* sub */
   NULL,                                 /* next */
   0,                                    /* static_pass_number */
   "alignments",                         /* name */
   NULL,                                 /* gate */
   compute_alignments,                   /* execute */
   NULL,                                 /* sub */
   NULL,                                 /* next */
   0,                                    /* static_pass_number */
-  0,                                    /* tv_id */
+  TV_NONE,                              /* tv_id */
   0,                                    /* properties_required */
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
   TODO_dump_func | TODO_verify_rtl_sharing
   0,                                    /* properties_required */
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
   TODO_dump_func | TODO_verify_rtl_sharing
-  | TODO_ggc_collect,                   /* todo_flags_finish */
-  0                                     /* letter */
+  | TODO_ggc_collect                    /* todo_flags_finish */
+ }
 };
 
 \f
 };
 
 \f
@@ -862,8 +883,7 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
       n_labels = max_labelno - min_labelno + 1;
       n_old_labels = old - min_labelno + 1;
 
       n_labels = max_labelno - min_labelno + 1;
       n_old_labels = old - min_labelno + 1;
 
-      label_align = xrealloc (label_align,
-                             n_labels * sizeof (struct label_alignment));
+      label_align = XRESIZEVEC (struct label_alignment, label_align, n_labels);
 
       /* Range of labels grows monotonically in the function.  Failing here
          means that the initialization of array got lost.  */
 
       /* Range of labels grows monotonically in the function.  Failing here
          means that the initialization of array got lost.  */
@@ -893,6 +913,7 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
       if (LABEL_P (insn))
        {
          rtx next;
       if (LABEL_P (insn))
        {
          rtx next;
+         bool next_is_jumptable;
 
          /* Merge in alignments computed by compute_alignments.  */
          log = LABEL_TO_ALIGNMENT (insn);
 
          /* Merge in alignments computed by compute_alignments.  */
          log = LABEL_TO_ALIGNMENT (insn);
@@ -902,31 +923,30 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
              max_skip = LABEL_TO_MAX_SKIP (insn);
            }
 
              max_skip = LABEL_TO_MAX_SKIP (insn);
            }
 
-         log = LABEL_ALIGN (insn);
-         if (max_log < log)
+         next = next_nonnote_insn (insn);
+         next_is_jumptable = next && JUMP_TABLE_DATA_P (next);
+         if (!next_is_jumptable)
            {
            {
-             max_log = log;
-             max_skip = LABEL_ALIGN_MAX_SKIP;
+             log = LABEL_ALIGN (insn);
+             if (max_log < log)
+               {
+                 max_log = log;
+                 max_skip = targetm.asm_out.label_align_max_skip (insn);
+               }
            }
            }
-         next = next_nonnote_insn (insn);
          /* ADDR_VECs only take room if read-only data goes into the text
             section.  */
          /* ADDR_VECs only take room if read-only data goes into the text
             section.  */
-         if (JUMP_TABLES_IN_TEXT_SECTION
-             || readonly_data_section == text_section)
-           if (next && JUMP_P (next))
-             {
-               rtx nextbody = PATTERN (next);
-               if (GET_CODE (nextbody) == ADDR_VEC
-                   || GET_CODE (nextbody) == ADDR_DIFF_VEC)
-                 {
-                   log = ADDR_VEC_ALIGN (next);
-                   if (max_log < log)
-                     {
-                       max_log = log;
-                       max_skip = LABEL_ALIGN_MAX_SKIP;
-                     }
-                 }
-             }
+         if ((JUMP_TABLES_IN_TEXT_SECTION
+              || readonly_data_section == text_section)
+             && next_is_jumptable)
+           {
+             log = ADDR_VEC_ALIGN (next);
+             if (max_log < log)
+               {
+                 max_log = log;
+                 max_skip = targetm.asm_out.label_align_max_skip (insn);
+               }
+           }
          LABEL_TO_ALIGNMENT (insn) = max_log;
          LABEL_TO_MAX_SKIP (insn) = max_skip;
          max_log = 0;
          LABEL_TO_ALIGNMENT (insn) = max_log;
          LABEL_TO_MAX_SKIP (insn) = max_skip;
          max_log = 0;
@@ -944,7 +964,7 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
                if (max_log < log)
                  {
                    max_log = log;
                if (max_log < log)
                  {
                    max_log = log;
-                   max_skip = LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP;
+                   max_skip = targetm.asm_out.label_align_after_barrier_max_skip (label);
                  }
                break;
              }
                  }
                break;
              }
@@ -1065,7 +1085,7 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
       INSN_ADDRESSES (uid) = insn_current_address + insn_lengths[uid];
 
       if (NOTE_P (insn) || BARRIER_P (insn)
       INSN_ADDRESSES (uid) = insn_current_address + insn_lengths[uid];
 
       if (NOTE_P (insn) || BARRIER_P (insn)
-         || LABEL_P (insn))
+         || LABEL_P (insn) || DEBUG_INSN_P(insn))
        continue;
       if (INSN_DELETED_P (insn))
        continue;
        continue;
       if (INSN_DELETED_P (insn))
        continue;
@@ -1382,22 +1402,34 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
 static int
 asm_insn_count (rtx body)
 {
 static int
 asm_insn_count (rtx body)
 {
-  const char *template;
-  int count = 1;
+  const char *templ;
 
   if (GET_CODE (body) == ASM_INPUT)
 
   if (GET_CODE (body) == ASM_INPUT)
-    template = XSTR (body, 0);
+    templ = XSTR (body, 0);
   else
   else
-    template = decode_asm_operands (body, NULL, NULL, NULL, NULL, NULL);
+    templ = decode_asm_operands (body, NULL, NULL, NULL, NULL, NULL);
+
+  return asm_str_count (templ);
+}
+#endif
+
+/* Return the number of machine instructions likely to be generated for the
+   inline-asm template. */
+int
+asm_str_count (const char *templ)
+{
+  int count = 1;
 
 
-  for (; *template; template++)
-    if (IS_ASM_LOGICAL_LINE_SEPARATOR (*template, template)
-       || *template == '\n')
+  if (!*templ)
+    return 0;
+
+  for (; *templ; templ++)
+    if (IS_ASM_LOGICAL_LINE_SEPARATOR (*templ, templ)
+       || *templ == '\n')
       count++;
 
   return count;
 }
       count++;
 
   return count;
 }
-#endif
 \f
 /* ??? This is probably the wrong place for these.  */
 /* Structure recording the mapping from source file and directory
 \f
 /* ??? This is probably the wrong place for these.  */
 /* Structure recording the mapping from source file and directory
@@ -1432,10 +1464,10 @@ add_debug_prefix_map (const char *arg)
       return;
     }
   map = XNEW (debug_prefix_map);
       return;
     }
   map = XNEW (debug_prefix_map);
-  map->old_prefix = ggc_alloc_string (arg, p - arg);
+  map->old_prefix = xstrndup (arg, p - arg);
   map->old_len = p - arg;
   p++;
   map->old_len = p - arg;
   p++;
-  map->new_prefix = ggc_strdup (p);
+  map->new_prefix = xstrdup (p);
   map->new_len = strlen (p);
   map->next = debug_prefix_maps;
   debug_prefix_maps = map;
   map->new_len = strlen (p);
   map->next = debug_prefix_maps;
   debug_prefix_maps = map;
@@ -1465,6 +1497,20 @@ remap_debug_filename (const char *filename)
   return ggc_strdup (s);
 }
 \f
   return ggc_strdup (s);
 }
 \f
+/* Return true if DWARF2 debug info can be emitted for DECL.  */
+
+static bool
+dwarf2_debug_info_emitted_p (tree decl)
+{
+  if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG)
+    return false;
+
+  if (DECL_IGNORED_P (decl))
+    return false;
+
+  return true;
+}
+
 /* Output assembler code for the start of a function,
    and initialize some of the variables in this file
    for the new function.  The label for the function and associated
 /* Output assembler code for the start of a function,
    and initialize some of the variables in this file
    for the new function.  The label for the function and associated
@@ -1472,12 +1518,12 @@ remap_debug_filename (const char *filename)
 
    FIRST is the first insn of the rtl for the function being compiled.
    FILE is the file to write assembler code to.
 
    FIRST is the first insn of the rtl for the function being compiled.
    FILE is the file to write assembler code to.
-   OPTIMIZE is nonzero if we should eliminate redundant
+   OPTIMIZE_P is nonzero if we should eliminate redundant
      test and compare insns.  */
 
 void
 final_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file,
      test and compare insns.  */
 
 void
 final_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file,
-                     int optimize ATTRIBUTE_UNUSED)
+                     int optimize_p ATTRIBUTE_UNUSED)
 {
   block_depth = 0;
 
 {
   block_depth = 0;
 
@@ -1485,15 +1531,15 @@ final_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file,
 
   last_filename = locator_file (prologue_locator);
   last_linenum = locator_line (prologue_locator);
 
   last_filename = locator_file (prologue_locator);
   last_linenum = locator_line (prologue_locator);
+  last_discriminator = discriminator = 0;
 
   high_block_linenum = high_function_linenum = last_linenum;
 
 
   high_block_linenum = high_function_linenum = last_linenum;
 
-  (*debug_hooks->begin_prologue) (last_linenum, last_filename);
+  if (!DECL_IGNORED_P (current_function_decl))
+    debug_hooks->begin_prologue (last_linenum, last_filename);
 
 
-#if defined (DWARF2_UNWIND_INFO) || defined (TARGET_UNWIND_INFO)
-  if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG)
+  if (!dwarf2_debug_info_emitted_p (current_function_decl))
     dwarf2out_begin_prologue (0, NULL);
     dwarf2out_begin_prologue (0, NULL);
-#endif
 
 #ifdef LEAF_REG_REMAP
   if (current_function_uses_only_leaf_regs)
 
 #ifdef LEAF_REG_REMAP
   if (current_function_uses_only_leaf_regs)
@@ -1502,12 +1548,10 @@ final_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file,
 
   /* The Sun386i and perhaps other machines don't work right
      if the profiling code comes after the prologue.  */
 
   /* The Sun386i and perhaps other machines don't work right
      if the profiling code comes after the prologue.  */
-#ifdef PROFILE_BEFORE_PROLOGUE
-  if (current_function_profile)
+  if (targetm.profile_before_prologue () && crtl->profile)
     profile_function (file);
     profile_function (file);
-#endif /* PROFILE_BEFORE_PROLOGUE */
 
 
-#if defined (DWARF2_UNWIND_INFO) && defined (HAVE_prologue)
+#if defined (HAVE_prologue)
   if (dwarf2out_do_frame ())
     dwarf2out_frame_debug (NULL_RTX, false);
 #endif
   if (dwarf2out_do_frame ())
     dwarf2out_frame_debug (NULL_RTX, false);
 #endif
@@ -1524,6 +1568,15 @@ final_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file,
       TREE_ASM_WRITTEN (DECL_INITIAL (current_function_decl)) = 1;
     }
 
       TREE_ASM_WRITTEN (DECL_INITIAL (current_function_decl)) = 1;
     }
 
+  if (warn_frame_larger_than
+    && get_frame_size () > frame_larger_than_size)
+  {
+      /* Issue a warning */
+      warning (OPT_Wframe_larger_than_,
+               "the frame size of %wd bytes is larger than %wd bytes",
+               get_frame_size (), frame_larger_than_size);
+  }
+
   /* First output the function prologue: code to set up the stack frame.  */
   targetm.asm_out.function_prologue (file, get_frame_size ());
 
   /* First output the function prologue: code to set up the stack frame.  */
   targetm.asm_out.function_prologue (file, get_frame_size ());
 
@@ -1538,10 +1591,8 @@ final_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file,
 static void
 profile_after_prologue (FILE *file ATTRIBUTE_UNUSED)
 {
 static void
 profile_after_prologue (FILE *file ATTRIBUTE_UNUSED)
 {
-#ifndef PROFILE_BEFORE_PROLOGUE
-  if (current_function_profile)
+  if (!targetm.profile_before_prologue () && crtl->profile)
     profile_function (file);
     profile_function (file);
-#endif /* not PROFILE_BEFORE_PROLOGUE */
 }
 
 static void
 }
 
 static void
@@ -1550,12 +1601,14 @@ profile_function (FILE *file ATTRIBUTE_UNUSED)
 #ifndef NO_PROFILE_COUNTERS
 # define NO_PROFILE_COUNTERS   0
 #endif
 #ifndef NO_PROFILE_COUNTERS
 # define NO_PROFILE_COUNTERS   0
 #endif
-#if defined(ASM_OUTPUT_REG_PUSH)
-  int sval = current_function_returns_struct;
-  rtx svrtx = targetm.calls.struct_value_rtx (TREE_TYPE (current_function_decl), 1);
-#if defined(STATIC_CHAIN_INCOMING_REGNUM) || defined(STATIC_CHAIN_REGNUM)
-  int cxt = cfun->static_chain_decl != NULL;
-#endif
+#ifdef ASM_OUTPUT_REG_PUSH
+  rtx sval = NULL, chain = NULL;
+
+  if (cfun->returns_struct)
+    sval = targetm.calls.struct_value_rtx (TREE_TYPE (current_function_decl),
+                                          true);
+  if (cfun->static_chain_decl)
+    chain = targetm.calls.static_chain (current_function_decl, true);
 #endif /* ASM_OUTPUT_REG_PUSH */
 
   if (! NO_PROFILE_COUNTERS)
 #endif /* ASM_OUTPUT_REG_PUSH */
 
   if (! NO_PROFILE_COUNTERS)
@@ -1569,44 +1622,20 @@ profile_function (FILE *file ATTRIBUTE_UNUSED)
 
   switch_to_section (current_function_section ());
 
 
   switch_to_section (current_function_section ());
 
-#if defined(ASM_OUTPUT_REG_PUSH)
-  if (sval && svrtx != NULL_RTX && REG_P (svrtx))
-    {
-      ASM_OUTPUT_REG_PUSH (file, REGNO (svrtx));
-    }
-#endif
-
-#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
-  if (cxt)
-    ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_INCOMING_REGNUM);
-#else
-#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
-  if (cxt)
-    {
-      ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_REGNUM);
-    }
-#endif
+#ifdef ASM_OUTPUT_REG_PUSH
+  if (sval && REG_P (sval))
+    ASM_OUTPUT_REG_PUSH (file, REGNO (sval));
+  if (chain && REG_P (chain))
+    ASM_OUTPUT_REG_PUSH (file, REGNO (chain));
 #endif
 
   FUNCTION_PROFILER (file, current_function_funcdef_no);
 
 #endif
 
   FUNCTION_PROFILER (file, current_function_funcdef_no);
 
-#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
-  if (cxt)
-    ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_INCOMING_REGNUM);
-#else
-#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
-  if (cxt)
-    {
-      ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_REGNUM);
-    }
-#endif
-#endif
-
-#if defined(ASM_OUTPUT_REG_PUSH)
-  if (sval && svrtx != NULL_RTX && REG_P (svrtx))
-    {
-      ASM_OUTPUT_REG_POP (file, REGNO (svrtx));
-    }
+#ifdef ASM_OUTPUT_REG_PUSH
+  if (chain && REG_P (chain))
+    ASM_OUTPUT_REG_POP (file, REGNO (chain));
+  if (sval && REG_P (sval))
+    ASM_OUTPUT_REG_POP (file, REGNO (sval));
 #endif
 }
 
 #endif
 }
 
@@ -1619,27 +1648,27 @@ final_end_function (void)
 {
   app_disable ();
 
 {
   app_disable ();
 
-  (*debug_hooks->end_function) (high_function_linenum);
+  if (!DECL_IGNORED_P (current_function_decl))
+    debug_hooks->end_function (high_function_linenum);
 
   /* Finally, output the function epilogue:
      code to restore the stack frame and return to the caller.  */
   targetm.asm_out.function_epilogue (asm_out_file, get_frame_size ());
 
   /* And debug output.  */
 
   /* Finally, output the function epilogue:
      code to restore the stack frame and return to the caller.  */
   targetm.asm_out.function_epilogue (asm_out_file, get_frame_size ());
 
   /* And debug output.  */
-  (*debug_hooks->end_epilogue) (last_linenum, last_filename);
+  if (!DECL_IGNORED_P (current_function_decl))
+    debug_hooks->end_epilogue (last_linenum, last_filename);
 
 
-#if defined (DWARF2_UNWIND_INFO)
-  if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG
+  if (!dwarf2_debug_info_emitted_p (current_function_decl)
       && dwarf2out_do_frame ())
     dwarf2out_end_epilogue (last_linenum, last_filename);
       && dwarf2out_do_frame ())
     dwarf2out_end_epilogue (last_linenum, last_filename);
-#endif
 }
 \f
 /* Output assembler code for some insns: all or part of a function.
    For description of args, see `final_start_function', above.  */
 
 void
 }
 \f
 /* Output assembler code for some insns: all or part of a function.
    For description of args, see `final_start_function', above.  */
 
 void
-final (rtx first, FILE *file, int optimize)
+final (rtx first, FILE *file, int optimize_p)
 {
   rtx insn;
   int max_uid = 0;
 {
   rtx insn;
   int max_uid = 0;
@@ -1654,7 +1683,7 @@ final (rtx first, FILE *file, int optimize)
 #ifdef HAVE_cc0
       /* If CC tracking across branches is enabled, record the insn which
         jumps to each branch only reached from one place.  */
 #ifdef HAVE_cc0
       /* If CC tracking across branches is enabled, record the insn which
         jumps to each branch only reached from one place.  */
-      if (optimize && JUMP_P (insn))
+      if (optimize_p && JUMP_P (insn))
        {
          rtx lab = JUMP_LABEL (insn);
          if (lab && LABEL_NUSES (lab) == 1)
        {
          rtx lab = JUMP_LABEL (insn);
          if (lab && LABEL_NUSES (lab) == 1)
@@ -1684,7 +1713,7 @@ final (rtx first, FILE *file, int optimize)
        insn_current_address = INSN_ADDRESSES (INSN_UID (insn));
 #endif /* HAVE_ATTR_length */
 
        insn_current_address = INSN_ADDRESSES (INSN_UID (insn));
 #endif /* HAVE_ATTR_length */
 
-      insn = final_scan_insn (insn, file, optimize, 0, &seen);
+      insn = final_scan_insn (insn, file, optimize_p, 0, &seen);
     }
 }
 \f
     }
 }
 \f
@@ -1737,6 +1766,34 @@ output_alternate_entry_point (FILE *file, rtx insn)
     }
 }
 
     }
 }
 
+/* Given a CALL_INSN, find and return the nested CALL. */
+static rtx
+call_from_call_insn (rtx insn)
+{
+  rtx x;
+  gcc_assert (CALL_P (insn));
+  x = PATTERN (insn);
+
+  while (GET_CODE (x) != CALL)
+    {
+      switch (GET_CODE (x))
+       {
+       default:
+         gcc_unreachable ();
+       case COND_EXEC:
+         x = COND_EXEC_CODE (x);
+         break;
+       case PARALLEL:
+         x = XVECEXP (x, 0, 0);
+         break;
+       case SET:
+         x = XEXP (x, 1);
+         break;
+       }
+    }
+  return x;
+}
+
 /* The final scan for one insn, INSN.
    Args are same as in `final', except that INSN
    is the insn being scanned.
 /* The final scan for one insn, INSN.
    Args are same as in `final', except that INSN
    is the insn being scanned.
@@ -1752,7 +1809,7 @@ output_alternate_entry_point (FILE *file, rtx insn)
    first.  */
 
 rtx
    first.  */
 
 rtx
-final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
+final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
                 int nopeepholes ATTRIBUTE_UNUSED, int *seen)
 {
 #ifdef HAVE_cc0
                 int nopeepholes ATTRIBUTE_UNUSED, int *seen)
 {
 #ifdef HAVE_cc0
@@ -1777,20 +1834,18 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 
        case NOTE_INSN_SWITCH_TEXT_SECTIONS:
          in_cold_section_p = !in_cold_section_p;
 
        case NOTE_INSN_SWITCH_TEXT_SECTIONS:
          in_cold_section_p = !in_cold_section_p;
-#ifdef DWARF2_UNWIND_INFO
+
          if (dwarf2out_do_frame ())
            dwarf2out_switch_text_section ();
          if (dwarf2out_do_frame ())
            dwarf2out_switch_text_section ();
-         else
-#endif
-           (*debug_hooks->switch_text_section) ();
+         else if (!DECL_IGNORED_P (current_function_decl))
+           debug_hooks->switch_text_section ();
 
          switch_to_section (current_function_section ());
          break;
 
        case NOTE_INSN_BASIC_BLOCK:
 
          switch_to_section (current_function_section ());
          break;
 
        case NOTE_INSN_BASIC_BLOCK:
-#ifdef TARGET_UNWIND_INFO
-         targetm.asm_out.unwind_emit (asm_out_file, insn);
-#endif
+         if (targetm.asm_out.unwind_emit)
+           targetm.asm_out.unwind_emit (asm_out_file, insn);
 
          if (flag_debug_asm)
            fprintf (asm_out_file, "\t%s basic block %d\n",
 
          if (flag_debug_asm)
            fprintf (asm_out_file, "\t%s basic block %d\n",
@@ -1804,6 +1859,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
          else
            *seen |= SEEN_BB;
 
          else
            *seen |= SEEN_BB;
 
+          discriminator = NOTE_BASIC_BLOCK (insn)->discriminator;
+
          break;
 
        case NOTE_INSN_EH_REGION_BEG:
          break;
 
        case NOTE_INSN_EH_REGION_BEG:
@@ -1831,12 +1888,22 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
          break;
 
        case NOTE_INSN_EPILOGUE_BEG:
          break;
 
        case NOTE_INSN_EPILOGUE_BEG:
+#if defined (HAVE_epilogue)
+         if (dwarf2out_do_frame ())
+           dwarf2out_cfi_begin_epilogue (insn);
+#endif
+         (*debug_hooks->begin_epilogue) (last_linenum, last_filename);
          targetm.asm_out.function_begin_epilogue (file);
          break;
 
          targetm.asm_out.function_begin_epilogue (file);
          break;
 
+       case NOTE_INSN_CFA_RESTORE_STATE:
+         dwarf2out_frame_debug_restore_state ();
+         break;
+
        case NOTE_INSN_FUNCTION_BEG:
          app_disable ();
        case NOTE_INSN_FUNCTION_BEG:
          app_disable ();
-         (*debug_hooks->end_prologue) (last_linenum, last_filename);
+         if (!DECL_IGNORED_P (current_function_decl))
+           debug_hooks->end_prologue (last_linenum, last_filename);
 
          if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE)
            {
 
          if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE)
            {
@@ -1862,7 +1929,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
              high_block_linenum = last_linenum;
 
              /* Output debugging info about the symbol-block beginning.  */
              high_block_linenum = last_linenum;
 
              /* Output debugging info about the symbol-block beginning.  */
-             (*debug_hooks->begin_block) (last_linenum, n);
+             if (!DECL_IGNORED_P (current_function_decl))
+               debug_hooks->begin_block (last_linenum, n);
 
              /* Mark this block as output.  */
              TREE_ASM_WRITTEN (NOTE_BLOCK (insn)) = 1;
 
              /* Mark this block as output.  */
              TREE_ASM_WRITTEN (NOTE_BLOCK (insn)) = 1;
@@ -1896,7 +1964,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
              --block_depth;
              gcc_assert (block_depth >= 0);
 
              --block_depth;
              gcc_assert (block_depth >= 0);
 
-             (*debug_hooks->end_block) (high_block_linenum, n);
+             if (!DECL_IGNORED_P (current_function_decl))
+               debug_hooks->end_block (high_block_linenum, n);
            }
          if (write_symbols == DBX_DEBUG
              || write_symbols == SDB_DEBUG)
            }
          if (write_symbols == DBX_DEBUG
              || write_symbols == SDB_DEBUG)
@@ -1926,7 +1995,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
          break;
 
        case NOTE_INSN_VAR_LOCATION:
          break;
 
        case NOTE_INSN_VAR_LOCATION:
-         (*debug_hooks->var_location) (insn);
+         if (!DECL_IGNORED_P (current_function_decl))
+           debug_hooks->var_location (insn);
          break;
 
        default:
          break;
 
        default:
@@ -1936,10 +2006,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
       break;
 
     case BARRIER:
       break;
 
     case BARRIER:
-#if defined (DWARF2_UNWIND_INFO)
       if (dwarf2out_do_frame ())
        dwarf2out_frame_debug (insn, false);
       if (dwarf2out_do_frame ())
        dwarf2out_frame_debug (insn, false);
-#endif
       break;
 
     case CODE_LABEL:
       break;
 
     case CODE_LABEL:
@@ -1965,86 +2033,49 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 #endif
            }
        }
 #endif
            }
        }
-#ifdef HAVE_cc0
       CC_STATUS_INIT;
       CC_STATUS_INIT;
-      /* If this label is reached from only one place, set the condition
-        codes from the instruction just before the branch.  */
-
-      /* Disabled because some insns set cc_status in the C output code
-        and NOTICE_UPDATE_CC alone can set incorrect status.  */
-      if (0 /* optimize && LABEL_NUSES (insn) == 1*/)
-       {
-         rtx jump = LABEL_REFS (insn);
-         rtx barrier = prev_nonnote_insn (insn);
-         rtx prev;
-         /* If the LABEL_REFS field of this label has been set to point
-            at a branch, the predecessor of the branch is a regular
-            insn, and that branch is the only way to reach this label,
-            set the condition codes based on the branch and its
-            predecessor.  */
-         if (barrier && BARRIER_P (barrier)
-             && jump && JUMP_P (jump)
-             && (prev = prev_nonnote_insn (jump))
-             && NONJUMP_INSN_P (prev))
-           {
-             NOTICE_UPDATE_CC (PATTERN (prev), prev);
-             NOTICE_UPDATE_CC (PATTERN (jump), jump);
-           }
-       }
-#endif
 
 
-      if (LABEL_NAME (insn))
-       (*debug_hooks->label) (insn);
+      if (!DECL_IGNORED_P (current_function_decl) && LABEL_NAME (insn))
+       debug_hooks->label (insn);
 
 
-      if (app_on)
-       {
-         fputs (ASM_APP_OFF, file);
-         app_on = 0;
-       }
+      app_disable ();
 
       next = next_nonnote_insn (insn);
 
       next = next_nonnote_insn (insn);
-      if (next != 0 && JUMP_P (next))
+      /* If this label is followed by a jump-table, make sure we put
+        the label in the read-only section.  Also possibly write the
+        label and jump table together.  */
+      if (next != 0 && JUMP_TABLE_DATA_P (next))
        {
        {
-         rtx nextbody = PATTERN (next);
-
-         /* If this label is followed by a jump-table,
-            make sure we put the label in the read-only section.  Also
-            possibly write the label and jump table together.  */
-
-         if (GET_CODE (nextbody) == ADDR_VEC
-             || GET_CODE (nextbody) == ADDR_DIFF_VEC)
-           {
 #if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)
 #if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)
-             /* In this case, the case vector is being moved by the
-                target, so don't output the label at all.  Leave that
-                to the back end macros.  */
+         /* In this case, the case vector is being moved by the
+            target, so don't output the label at all.  Leave that
+            to the back end macros.  */
 #else
 #else
-             if (! JUMP_TABLES_IN_TEXT_SECTION)
-               {
-                 int log_align;
+         if (! JUMP_TABLES_IN_TEXT_SECTION)
+           {
+             int log_align;
 
 
-                 switch_to_section (targetm.asm_out.function_rodata_section
-                                    (current_function_decl));
+             switch_to_section (targetm.asm_out.function_rodata_section
+                                (current_function_decl));
 
 #ifdef ADDR_VEC_ALIGN
 
 #ifdef ADDR_VEC_ALIGN
-                 log_align = ADDR_VEC_ALIGN (next);
+             log_align = ADDR_VEC_ALIGN (next);
 #else
 #else
-                 log_align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
+             log_align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
 #endif
 #endif
-                 ASM_OUTPUT_ALIGN (file, log_align);
-               }
-             else
-               switch_to_section (current_function_section ());
+             ASM_OUTPUT_ALIGN (file, log_align);
+           }
+         else
+           switch_to_section (current_function_section ());
 
 #ifdef ASM_OUTPUT_CASE_LABEL
 
 #ifdef ASM_OUTPUT_CASE_LABEL
-             ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn),
-                                    next);
+         ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn),
+                                next);
 #else
 #else
-             targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (insn));
+         targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (insn));
 #endif
 #endif
 #endif
 #endif
-             break;
-           }
+         break;
        }
       if (LABEL_ALT_ENTRY_P (insn))
        output_alternate_entry_point (file, insn);
        }
       if (LABEL_ALT_ENTRY_P (insn))
        output_alternate_entry_point (file, insn);
@@ -2056,12 +2087,12 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
       {
        rtx body = PATTERN (insn);
        int insn_code_number;
       {
        rtx body = PATTERN (insn);
        int insn_code_number;
-       const char *template;
+       const char *templ;
+       bool is_stmt;
 
 
-#ifdef HAVE_conditional_execution
        /* Reset this early so it is correct for ASM statements.  */
        current_insn_predicate = NULL_RTX;
        /* Reset this early so it is correct for ASM statements.  */
        current_insn_predicate = NULL_RTX;
-#endif
+
        /* An INSN, JUMP_INSN or CALL_INSN.
           First check for special kinds that recog doesn't recognize.  */
 
        /* An INSN, JUMP_INSN or CALL_INSN.
           First check for special kinds that recog doesn't recognize.  */
 
@@ -2100,11 +2131,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
            else
              switch_to_section (current_function_section ());
 
            else
              switch_to_section (current_function_section ());
 
-           if (app_on)
-             {
-               fputs (ASM_APP_OFF, file);
-               app_on = 0;
-             }
+           app_disable ();
 
 #if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)
            if (GET_CODE (body) == ADDR_VEC)
 
 #if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)
            if (GET_CODE (body) == ADDR_VEC)
@@ -2162,10 +2189,10 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
          }
        /* Output this line note if it is the first or the last line
           note in a row.  */
          }
        /* Output this line note if it is the first or the last line
           note in a row.  */
-       if (notice_source_line (insn))
-         {
-           (*debug_hooks->source_line) (last_linenum, last_filename);
-         }
+       if (!DECL_IGNORED_P (current_function_decl)
+           && notice_source_line (insn, &is_stmt))
+         (*debug_hooks->source_line) (last_linenum, last_filename,
+                                      last_discriminator, is_stmt);
 
        if (GET_CODE (body) == ASM_INPUT)
          {
 
        if (GET_CODE (body) == ASM_INPUT)
          {
@@ -2178,17 +2205,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
              {
                expanded_location loc;
 
              {
                expanded_location loc;
 
-               if (! app_on)
-                 {
-                   fputs (ASM_APP_ON, file);
-                   app_on = 1;
-                 }
-#ifdef USE_MAPPED_LOCATION
+               app_enable ();
                loc = expand_location (ASM_INPUT_SOURCE_LOCATION (body));
                loc = expand_location (ASM_INPUT_SOURCE_LOCATION (body));
-#else
-               loc.file = ASM_INPUT_SOURCE_FILE (body);
-               loc.line = ASM_INPUT_SOURCE_LINE (body);
-#endif
                if (*loc.file && loc.line)
                  fprintf (asm_out_file, "%s %i \"%s\" 1\n",
                           ASM_COMMENT_START, loc.line, loc.file);
                if (*loc.file && loc.line)
                  fprintf (asm_out_file, "%s %i \"%s\" 1\n",
                           ASM_COMMENT_START, loc.line, loc.file);
@@ -2205,7 +2223,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
        if (asm_noperands (body) >= 0)
          {
            unsigned int noperands = asm_noperands (body);
        if (asm_noperands (body) >= 0)
          {
            unsigned int noperands = asm_noperands (body);
-           rtx *ops = alloca (noperands * sizeof (rtx));
+           rtx *ops = XALLOCAVEC (rtx, noperands);
            const char *string;
            location_t loc;
            expanded_location expanded;
            const char *string;
            location_t loc;
            expanded_location expanded;
@@ -2215,7 +2233,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 
            /* Get out the operand values.  */
            string = decode_asm_operands (body, ops, NULL, NULL, NULL, &loc);
 
            /* Get out the operand values.  */
            string = decode_asm_operands (body, ops, NULL, NULL, NULL, &loc);
-           /* Inhibit dieing on what would otherwise be compiler bugs.  */
+           /* Inhibit dying on what would otherwise be compiler bugs.  */
            insn_noperands = noperands;
            this_is_asm_operands = insn;
            expanded = expand_location (loc);
            insn_noperands = noperands;
            this_is_asm_operands = insn;
            expanded = expand_location (loc);
@@ -2227,11 +2245,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
            /* Output the insn using them.  */
            if (string[0])
              {
            /* Output the insn using them.  */
            if (string[0])
              {
-               if (! app_on)
-                 {
-                   fputs (ASM_APP_ON, file);
-                   app_on = 1;
-                 }
+               app_enable ();
                if (expanded.file && expanded.line)
                  fprintf (asm_out_file, "%s %i \"%s\" 1\n",
                           ASM_COMMENT_START, expanded.line, expanded.file);
                if (expanded.file && expanded.line)
                  fprintf (asm_out_file, "%s %i \"%s\" 1\n",
                           ASM_COMMENT_START, expanded.line, expanded.file);
@@ -2242,15 +2256,15 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 #endif
              }
 
 #endif
              }
 
+           if (targetm.asm_out.final_postscan_insn)
+             targetm.asm_out.final_postscan_insn (file, insn, ops,
+                                                  insn_noperands);
+
            this_is_asm_operands = 0;
            break;
          }
 
            this_is_asm_operands = 0;
            break;
          }
 
-       if (app_on)
-         {
-           fputs (ASM_APP_OFF, file);
-           app_on = 0;
-         }
+       app_disable ();
 
        if (GET_CODE (body) == SEQUENCE)
          {
 
        if (GET_CODE (body) == SEQUENCE)
          {
@@ -2261,11 +2275,9 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 
            /* Record the delay slots' frame information before the branch.
               This is needed for delayed calls: see execute_cfa_program().  */
 
            /* Record the delay slots' frame information before the branch.
               This is needed for delayed calls: see execute_cfa_program().  */
-#if defined (DWARF2_UNWIND_INFO)
            if (dwarf2out_do_frame ())
              for (i = 1; i < XVECLEN (body, 0); i++)
                dwarf2out_frame_debug (XVECEXP (body, 0, i), false);
            if (dwarf2out_do_frame ())
              for (i = 1; i < XVECLEN (body, 0); i++)
                dwarf2out_frame_debug (XVECEXP (body, 0, i), false);
-#endif
 
            /* The first insn in this SEQUENCE might be a JUMP_INSN that will
               force the restoration of a comparison that was previously
 
            /* The first insn in this SEQUENCE might be a JUMP_INSN that will
               force the restoration of a comparison that was previously
@@ -2321,15 +2333,19 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
           and the next statement should reexamine the variable
           to compute the condition codes.  */
 
           and the next statement should reexamine the variable
           to compute the condition codes.  */
 
-       if (optimize)
+       if (optimize_p)
          {
            if (set
                && GET_CODE (SET_DEST (set)) == CC0
                && insn != last_ignored_compare)
              {
          {
            if (set
                && GET_CODE (SET_DEST (set)) == CC0
                && insn != last_ignored_compare)
              {
+               rtx src1, src2;
                if (GET_CODE (SET_SRC (set)) == SUBREG)
                  SET_SRC (set) = alter_subreg (&SET_SRC (set));
                if (GET_CODE (SET_SRC (set)) == SUBREG)
                  SET_SRC (set) = alter_subreg (&SET_SRC (set));
-               else if (GET_CODE (SET_SRC (set)) == COMPARE)
+
+               src1 = SET_SRC (set);
+               src2 = NULL_RTX;
+               if (GET_CODE (SET_SRC (set)) == COMPARE)
                  {
                    if (GET_CODE (XEXP (SET_SRC (set), 0)) == SUBREG)
                      XEXP (SET_SRC (set), 0)
                  {
                    if (GET_CODE (XEXP (SET_SRC (set), 0)) == SUBREG)
                      XEXP (SET_SRC (set), 0)
@@ -2337,11 +2353,18 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
                    if (GET_CODE (XEXP (SET_SRC (set), 1)) == SUBREG)
                      XEXP (SET_SRC (set), 1)
                        = alter_subreg (&XEXP (SET_SRC (set), 1));
                    if (GET_CODE (XEXP (SET_SRC (set), 1)) == SUBREG)
                      XEXP (SET_SRC (set), 1)
                        = alter_subreg (&XEXP (SET_SRC (set), 1));
+                   if (XEXP (SET_SRC (set), 1)
+                       == CONST0_RTX (GET_MODE (XEXP (SET_SRC (set), 0))))
+                     src2 = XEXP (SET_SRC (set), 0);
                  }
                if ((cc_status.value1 != 0
                  }
                if ((cc_status.value1 != 0
-                    && rtx_equal_p (SET_SRC (set), cc_status.value1))
+                    && rtx_equal_p (src1, cc_status.value1))
                    || (cc_status.value2 != 0
                    || (cc_status.value2 != 0
-                       && rtx_equal_p (SET_SRC (set), cc_status.value2)))
+                       && rtx_equal_p (src1, cc_status.value2))
+                   || (src2 != 0 && cc_status.value1 != 0
+                       && rtx_equal_p (src2, cc_status.value1))
+                   || (src2 != 0 && cc_status.value2 != 0
+                       && rtx_equal_p (src2, cc_status.value2)))
                  {
                    /* Don't delete insn if it has an addressing side-effect.  */
                    if (! FIND_REG_INC_NOTE (insn, NULL_RTX)
                  {
                    /* Don't delete insn if it has an addressing side-effect.  */
                    if (! FIND_REG_INC_NOTE (insn, NULL_RTX)
@@ -2355,9 +2378,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
                  }
              }
          }
                  }
              }
          }
-#endif
 
 
-#ifdef HAVE_cc0
        /* If this is a conditional branch, maybe modify it
           if the cc's are in a nonstandard state
           so that it accomplishes the same thing that it would
        /* If this is a conditional branch, maybe modify it
           if the cc's are in a nonstandard state
           so that it accomplishes the same thing that it would
@@ -2497,7 +2518,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 #ifdef HAVE_peephole
        /* Do machine-specific peephole optimizations if desired.  */
 
 #ifdef HAVE_peephole
        /* Do machine-specific peephole optimizations if desired.  */
 
-       if (optimize && !flag_no_peephole && !nopeepholes)
+       if (optimize_p && !flag_no_peephole && !nopeepholes)
          {
            rtx next = peephole (insn);
            /* When peepholing, if there were notes within the peephole,
          {
            rtx next = peephole (insn);
            /* When peepholing, if there were notes within the peephole,
@@ -2508,7 +2529,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 
                for (note = NEXT_INSN (insn); note != next;
                     note = NEXT_INSN (note))
 
                for (note = NEXT_INSN (insn); note != next;
                     note = NEXT_INSN (note))
-                 final_scan_insn (note, file, optimize, nopeepholes, seen);
+                 final_scan_insn (note, file, optimize_p, nopeepholes, seen);
 
                /* Put the notes in the proper position for a later
                   rescan.  For example, the SH target can do this
 
                /* Put the notes in the proper position for a later
                   rescan.  For example, the SH target can do this
@@ -2554,10 +2575,9 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
        FINAL_PRESCAN_INSN (insn, recog_data.operand, recog_data.n_operands);
 #endif
 
        FINAL_PRESCAN_INSN (insn, recog_data.operand, recog_data.n_operands);
 #endif
 
-#ifdef HAVE_conditional_execution
-       if (GET_CODE (PATTERN (insn)) == COND_EXEC)
+       if (targetm.have_conditional_execution ()
+           && GET_CODE (PATTERN (insn)) == COND_EXEC)
          current_insn_predicate = COND_EXEC_TEST (PATTERN (insn));
          current_insn_predicate = COND_EXEC_TEST (PATTERN (insn));
-#endif
 
 #ifdef HAVE_cc0
        cc_prev_status = cc_status;
 
 #ifdef HAVE_cc0
        cc_prev_status = cc_status;
@@ -2572,18 +2592,16 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 
        current_output_insn = debug_insn = insn;
 
 
        current_output_insn = debug_insn = insn;
 
-#if defined (DWARF2_UNWIND_INFO)
        if (CALL_P (insn) && dwarf2out_do_frame ())
          dwarf2out_frame_debug (insn, false);
        if (CALL_P (insn) && dwarf2out_do_frame ())
          dwarf2out_frame_debug (insn, false);
-#endif
 
        /* Find the proper template for this insn.  */
 
        /* Find the proper template for this insn.  */
-       template = get_insn_template (insn_code_number, insn);
+       templ = get_insn_template (insn_code_number, insn);
 
        /* If the C code returns 0, it means that it is a jump insn
           which follows a deleted test insn, and that test insn
           needs to be reinserted.  */
 
        /* If the C code returns 0, it means that it is a jump insn
           which follows a deleted test insn, and that test insn
           needs to be reinserted.  */
-       if (template == 0)
+       if (templ == 0)
          {
            rtx prev;
 
          {
            rtx prev;
 
@@ -2606,12 +2624,12 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 
        /* If the template is the string "#", it means that this insn must
           be split.  */
 
        /* If the template is the string "#", it means that this insn must
           be split.  */
-       if (template[0] == '#' && template[1] == '\0')
+       if (templ[0] == '#' && templ[1] == '\0')
          {
          {
-           rtx new = try_split (body, insn, 0);
+           rtx new_rtx = try_split (body, insn, 0);
 
            /* If we didn't split the insn, go away.  */
 
            /* If we didn't split the insn, go away.  */
-           if (new == insn && PATTERN (new) == body)
+           if (new_rtx == insn && PATTERN (new_rtx) == body)
              fatal_insn ("could not split insn", insn);
 
 #ifdef HAVE_ATTR_length
              fatal_insn ("could not split insn", insn);
 
 #ifdef HAVE_ATTR_length
@@ -2621,30 +2639,72 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
            gcc_unreachable ();
 #endif
 
            gcc_unreachable ();
 #endif
 
-           return new;
+           return new_rtx;
          }
 
          }
 
-#ifdef TARGET_UNWIND_INFO
        /* ??? This will put the directives in the wrong place if
           get_insn_template outputs assembly directly.  However calling it
           before get_insn_template breaks if the insns is split.  */
        /* ??? This will put the directives in the wrong place if
           get_insn_template outputs assembly directly.  However calling it
           before get_insn_template breaks if the insns is split.  */
-       targetm.asm_out.unwind_emit (asm_out_file, insn);
-#endif
+       if (targetm.asm_out.unwind_emit_before_insn
+           && targetm.asm_out.unwind_emit)
+         targetm.asm_out.unwind_emit (asm_out_file, insn);
+
+       if (CALL_P (insn))
+         {
+           rtx x = call_from_call_insn (insn);
+           x = XEXP (x, 0);
+           if (x && MEM_P (x) && GET_CODE (XEXP (x, 0)) == SYMBOL_REF)
+             {
+               tree t;
+               x = XEXP (x, 0);
+               t = SYMBOL_REF_DECL (x);
+               if (t)
+                 assemble_external (t);
+             }
+         }
 
        /* Output assembler code from the template.  */
 
        /* Output assembler code from the template.  */
-       output_asm_insn (template, recog_data.operand);
+       output_asm_insn (templ, recog_data.operand);
+
+       /* Record point-of-call information for ICF debugging.  */
+       if (flag_enable_icf_debug && CALL_P (insn))
+         {
+           rtx x = call_from_call_insn (insn);
+           x = XEXP (x, 0);
+           if (x && MEM_P (x))
+             {
+               if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF)
+                 {
+                   tree t;
+                   x = XEXP (x, 0);
+                   t = SYMBOL_REF_DECL (x);
+                   if (t)
+                     (*debug_hooks->direct_call) (t);
+                 }
+               else
+                 (*debug_hooks->virtual_call) (INSN_UID (insn));
+             }
+         }
+
+       /* Some target machines need to postscan each insn after
+          it is output.  */
+       if (targetm.asm_out.final_postscan_insn)
+         targetm.asm_out.final_postscan_insn (file, insn, recog_data.operand,
+                                              recog_data.n_operands);
 
        /* If necessary, report the effect that the instruction has on
           the unwind info.   We've already done this for delay slots
           and call instructions.  */
 
        /* If necessary, report the effect that the instruction has on
           the unwind info.   We've already done this for delay slots
           and call instructions.  */
-#if defined (DWARF2_UNWIND_INFO)
        if (final_sequence == 0
 #if !defined (HAVE_prologue)
            && !ACCUMULATE_OUTGOING_ARGS
 #endif
            && dwarf2out_do_frame ())
          dwarf2out_frame_debug (insn, true);
        if (final_sequence == 0
 #if !defined (HAVE_prologue)
            && !ACCUMULATE_OUTGOING_ARGS
 #endif
            && dwarf2out_do_frame ())
          dwarf2out_frame_debug (insn, true);
-#endif
+
+       if (!targetm.asm_out.unwind_emit_before_insn
+           && targetm.asm_out.unwind_emit)
+         targetm.asm_out.unwind_emit (asm_out_file, insn);
 
        current_output_insn = debug_insn = 0;
       }
 
        current_output_insn = debug_insn = 0;
       }
@@ -2652,10 +2712,12 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
   return NEXT_INSN (insn);
 }
 \f
   return NEXT_INSN (insn);
 }
 \f
-/* Return whether a source line note needs to be emitted before INSN.  */
+/* Return whether a source line note needs to be emitted before INSN.
+   Sets IS_STMT to TRUE if the line should be marked as a possible
+   breakpoint location.  */
 
 static bool
 
 static bool
-notice_source_line (rtx insn)
+notice_source_line (rtx insn, bool *is_stmt)
 {
   const char *filename;
   int linenum;
 {
   const char *filename;
   int linenum;
@@ -2671,18 +2733,33 @@ notice_source_line (rtx insn)
       linenum = insn_line (insn);
     }
 
       linenum = insn_line (insn);
     }
 
-  if (filename
-      && (force_source_line
-         || filename != last_filename
-         || last_linenum != linenum))
+  if (filename == NULL)
+    return false;
+
+  if (force_source_line
+      || filename != last_filename
+      || last_linenum != linenum)
     {
       force_source_line = false;
       last_filename = filename;
       last_linenum = linenum;
     {
       force_source_line = false;
       last_filename = filename;
       last_linenum = linenum;
+      last_discriminator = discriminator;
+      *is_stmt = true;
       high_block_linenum = MAX (last_linenum, high_block_linenum);
       high_function_linenum = MAX (last_linenum, high_function_linenum);
       return true;
     }
       high_block_linenum = MAX (last_linenum, high_block_linenum);
       high_function_linenum = MAX (last_linenum, high_function_linenum);
       return true;
     }
+
+  if (SUPPORTS_DISCRIMINATOR && last_discriminator != discriminator)
+    {
+      /* If the discriminator changed, but the line number did not,
+         output the line table entry with is_stmt false so the
+         debugger does not treat this as a breakpoint location.  */
+      last_discriminator = discriminator;
+      *is_stmt = false;
+      return true;
+    }
+
   return false;
 }
 \f
   return false;
 }
 \f
@@ -2761,11 +2838,11 @@ alter_subreg (rtx *xp)
     }
   else
     {
     }
   else
     {
-      rtx new = simplify_subreg (GET_MODE (x), y, GET_MODE (y),
+      rtx new_rtx = simplify_subreg (GET_MODE (x), y, GET_MODE (y),
                                 SUBREG_BYTE (x));
 
                                 SUBREG_BYTE (x));
 
-      if (new != 0)
-       *xp = new;
+      if (new_rtx != 0)
+       *xp = new_rtx;
       else if (REG_P (y))
        {
          /* Simplify_subreg can't handle some REG cases, but we have to.  */
       else if (REG_P (y))
        {
          /* Simplify_subreg can't handle some REG cases, but we have to.  */
@@ -3062,7 +3139,7 @@ get_mem_expr_from_op (rtx op, int *paddressp)
           && (expr = get_mem_expr_from_op (XEXP (op, 1), &inner_addressp)))
     return expr;
 
           && (expr = get_mem_expr_from_op (XEXP (op, 1), &inner_addressp)))
     return expr;
 
-  while (GET_RTX_CLASS (GET_CODE (op)) == RTX_UNARY
+  while (UNARY_P (op)
         || GET_RTX_CLASS (GET_CODE (op)) == RTX_BIN_ARITH)
     op = XEXP (op, 0);
 
         || GET_RTX_CLASS (GET_CODE (op)) == RTX_BIN_ARITH)
     op = XEXP (op, 0);
 
@@ -3119,7 +3196,7 @@ output_asm_operand_names (rtx *operands, int *oporder, int nops)
       of the operand, with no other punctuation.  */
 
 void
       of the operand, with no other punctuation.  */
 
 void
-output_asm_insn (const char *template, rtx *operands)
+output_asm_insn (const char *templ, rtx *operands)
 {
   const char *p;
   int c;
 {
   const char *p;
   int c;
@@ -3132,11 +3209,11 @@ output_asm_insn (const char *template, rtx *operands)
 
   /* An insn may return a null string template
      in a case where no assembler code is needed.  */
 
   /* An insn may return a null string template
      in a case where no assembler code is needed.  */
-  if (*template == 0)
+  if (*templ == 0)
     return;
 
   memset (opoutput, 0, sizeof opoutput);
     return;
 
   memset (opoutput, 0, sizeof opoutput);
-  p = template;
+  p = templ;
   putc ('\t', asm_out_file);
 
 #ifdef ASM_OUTPUT_OPCODE
   putc ('\t', asm_out_file);
 
 #ifdef ASM_OUTPUT_OPCODE
@@ -3238,7 +3315,7 @@ output_asm_insn (const char *template, rtx *operands)
           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
           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.  */
+          the TARGET_PRINT_OPERAND hook can define them.  */
        else if (ISALPHA (*p))
          {
            int letter = *p++;
        else if (ISALPHA (*p))
          {
            int letter = *p++;
@@ -3265,7 +3342,7 @@ output_asm_insn (const char *template, rtx *operands)
              }
            else if (letter == 'n')
              {
              }
            else if (letter == 'n')
              {
-               if (GET_CODE (operands[opnum]) == CONST_INT)
+               if (CONST_INT_P (operands[opnum]))
                  fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC,
                           - INTVAL (operands[opnum]));
                else
                  fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC,
                           - INTVAL (operands[opnum]));
                else
@@ -3304,12 +3381,10 @@ output_asm_insn (const char *template, rtx *operands)
            c = *p;
          }
        /* % followed by punctuation: output something for that
            c = *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 ((unsigned char) *p))
+          punctuation character alone, with no operand.  The
+          TARGET_PRINT_OPERAND hook decides what is actually done.  */
+       else if (targetm.asm_out.print_operand_punct_valid_p ((unsigned char) *p))
          output_operand (NULL_RTX, *p++);
          output_operand (NULL_RTX, *p++);
-#endif
        else
          output_operand_lossage ("invalid %%-code");
        break;
        else
          output_operand_lossage ("invalid %%-code");
        break;
@@ -3346,17 +3421,50 @@ output_asm_label (rtx x)
   assemble_name (asm_out_file, buf);
 }
 
   assemble_name (asm_out_file, buf);
 }
 
+/* Helper rtx-iteration-function for mark_symbol_refs_as_used and
+   output_operand.  Marks SYMBOL_REFs as referenced through use of
+   assemble_external.  */
+
+static int
+mark_symbol_ref_as_used (rtx *xp, void *dummy ATTRIBUTE_UNUSED)
+{
+  rtx x = *xp;
+
+  /* If we have a used symbol, we may have to emit assembly
+     annotations corresponding to whether the symbol is external, weak
+     or has non-default visibility.  */
+  if (GET_CODE (x) == SYMBOL_REF)
+    {
+      tree t;
+
+      t = SYMBOL_REF_DECL (x);
+      if (t)
+       assemble_external (t);
+
+      return -1;
+    }
+
+  return 0;
+}
+
+/* Marks SYMBOL_REFs in x as referenced through use of assemble_external.  */
+
+void
+mark_symbol_refs_as_used (rtx x)
+{
+  for_each_rtx (&x, mark_symbol_ref_as_used, NULL);
+}
+
 /* Print operand X using machine-dependent assembler syntax.
 /* Print operand X using machine-dependent assembler syntax.
-   The macro PRINT_OPERAND is defined just to control this function.
    CODE is a non-digit that preceded the operand-number in the % spec,
    such as 'z' if the spec was `%z3'.  CODE is 0 if there was no char
    between the % and the digits.
    When CODE is a non-letter, X is 0.
 
    The meanings of the letters are machine-dependent and controlled
    CODE is a non-digit that preceded the operand-number in the % spec,
    such as 'z' if the spec was `%z3'.  CODE is 0 if there was no char
    between the % and the digits.
    When CODE is a non-letter, X is 0.
 
    The meanings of the letters are machine-dependent and controlled
-   by PRINT_OPERAND.  */
+   by TARGET_PRINT_OPERAND.  */
 
 
-static void
+void
 output_operand (rtx x, int code ATTRIBUTE_UNUSED)
 {
   if (x && GET_CODE (x) == SUBREG)
 output_operand (rtx x, int code ATTRIBUTE_UNUSED)
 {
   if (x && GET_CODE (x) == SUBREG)
@@ -3365,19 +3473,23 @@ output_operand (rtx x, int code ATTRIBUTE_UNUSED)
   /* X must not be a pseudo reg.  */
   gcc_assert (!x || !REG_P (x) || REGNO (x) < FIRST_PSEUDO_REGISTER);
 
   /* X must not be a pseudo reg.  */
   gcc_assert (!x || !REG_P (x) || REGNO (x) < FIRST_PSEUDO_REGISTER);
 
-  PRINT_OPERAND (asm_out_file, x, code);
+  targetm.asm_out.print_operand (asm_out_file, x, code);
+
+  if (x == NULL_RTX)
+    return;
+
+  for_each_rtx (&x, mark_symbol_ref_as_used, NULL);
 }
 
 }
 
-/* Print a memory reference operand for address X
-   using machine-dependent assembler syntax.
-   The macro PRINT_OPERAND_ADDRESS exists just to control this function.  */
+/* Print a memory reference operand for address X using
+   machine-dependent assembler syntax.  */
 
 void
 output_address (rtx x)
 {
   bool changed = false;
   walk_alter_subreg (&x, &changed);
 
 void
 output_address (rtx x)
 {
   bool changed = false;
   walk_alter_subreg (&x, &changed);
-  PRINT_OPERAND_ADDRESS (asm_out_file, x);
+  targetm.asm_out.print_operand_address (asm_out_file, x);
 }
 \f
 /* Print an integer constant expression in assembler syntax.
 }
 \f
 /* Print an integer constant expression in assembler syntax.
@@ -3398,7 +3510,7 @@ output_addr_const (FILE *file, rtx x)
 
     case SYMBOL_REF:
       if (SYMBOL_REF_DECL (x))
 
     case SYMBOL_REF:
       if (SYMBOL_REF_DECL (x))
-       mark_decl_referenced (SYMBOL_REF_DECL (x));
+       assemble_external (SYMBOL_REF_DECL (x));
 #ifdef ASM_OUTPUT_SYMBOL_REF
       ASM_OUTPUT_SYMBOL_REF (file, x);
 #else
 #ifdef ASM_OUTPUT_SYMBOL_REF
       ASM_OUTPUT_SYMBOL_REF (file, x);
 #else
@@ -3434,9 +3546,11 @@ output_addr_const (FILE *file, rtx x)
          /* We can use %d if the number is one word and positive.  */
          if (CONST_DOUBLE_HIGH (x))
            fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
          /* We can use %d if the number is one word and positive.  */
          if (CONST_DOUBLE_HIGH (x))
            fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
-                    CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x));
+                    (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (x),
+                    (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (x));
          else if (CONST_DOUBLE_LOW (x) < 0)
          else if (CONST_DOUBLE_LOW (x) < 0)
-           fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (x));
+           fprintf (file, HOST_WIDE_INT_PRINT_HEX,
+                    (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (x));
          else
            fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x));
        }
          else
            fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x));
        }
@@ -3447,12 +3561,13 @@ output_addr_const (FILE *file, rtx x)
       break;
 
     case CONST_FIXED:
       break;
 
     case CONST_FIXED:
-      fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_FIXED_VALUE_LOW (x));
+      fprintf (file, HOST_WIDE_INT_PRINT_HEX,
+              (unsigned HOST_WIDE_INT) CONST_FIXED_VALUE_LOW (x));
       break;
 
     case PLUS:
       /* Some assemblers need integer constants to appear last (eg masm).  */
       break;
 
     case PLUS:
       /* Some assemblers need integer constants to appear last (eg masm).  */
-      if (GET_CODE (XEXP (x, 0)) == CONST_INT)
+      if (CONST_INT_P (XEXP (x, 0)))
        {
          output_addr_const (file, XEXP (x, 1));
          if (INTVAL (XEXP (x, 0)) >= 0)
        {
          output_addr_const (file, XEXP (x, 1));
          if (INTVAL (XEXP (x, 0)) >= 0)
@@ -3462,7 +3577,7 @@ output_addr_const (FILE *file, rtx x)
       else
        {
          output_addr_const (file, XEXP (x, 0));
       else
        {
          output_addr_const (file, XEXP (x, 0));
-         if (GET_CODE (XEXP (x, 1)) != CONST_INT
+         if (!CONST_INT_P (XEXP (x, 1))
              || INTVAL (XEXP (x, 1)) >= 0)
            fprintf (file, "+");
          output_addr_const (file, XEXP (x, 1));
              || INTVAL (XEXP (x, 1)) >= 0)
            fprintf (file, "+");
          output_addr_const (file, XEXP (x, 1));
@@ -3478,7 +3593,7 @@ output_addr_const (FILE *file, rtx x)
 
       output_addr_const (file, XEXP (x, 0));
       fprintf (file, "-");
 
       output_addr_const (file, XEXP (x, 0));
       fprintf (file, "-");
-      if ((GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) >= 0)
+      if ((CONST_INT_P (XEXP (x, 1)) && 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));
          || GET_CODE (XEXP (x, 1)) == PC
          || GET_CODE (XEXP (x, 1)) == SYMBOL_REF)
        output_addr_const (file, XEXP (x, 1));
@@ -3493,20 +3608,44 @@ output_addr_const (FILE *file, rtx x)
     case ZERO_EXTEND:
     case SIGN_EXTEND:
     case SUBREG:
     case ZERO_EXTEND:
     case SIGN_EXTEND:
     case SUBREG:
+    case TRUNCATE:
       output_addr_const (file, XEXP (x, 0));
       break;
 
     default:
       output_addr_const (file, XEXP (x, 0));
       break;
 
     default:
-#ifdef OUTPUT_ADDR_CONST_EXTRA
-      OUTPUT_ADDR_CONST_EXTRA (file, x, fail);
-      break;
+      if (targetm.asm_out.output_addr_const_extra (file, x))
+       break;
 
 
-    fail:
-#endif
       output_operand_lossage ("invalid expression as operand");
     }
 }
 \f
       output_operand_lossage ("invalid expression as operand");
     }
 }
 \f
+/* Output a quoted string.  */
+
+void
+output_quoted_string (FILE *asm_file, const char *string)
+{
+#ifdef OUTPUT_QUOTED_STRING
+  OUTPUT_QUOTED_STRING (asm_file, string);
+#else
+  char c;
+
+  putc ('\"', asm_file);
+  while ((c = *string++) != 0)
+    {
+      if (ISPRINT (c))
+       {
+         if (c == '\"' || c == '\\')
+           putc ('\\', asm_file);
+         putc (c, asm_file);
+       }
+      else
+       fprintf (asm_file, "\\%03o", (unsigned char) c);
+    }
+  putc ('\"', asm_file);
+#endif
+}
+\f
 /* A poor man's fprintf, with the added features of %I, %R, %L, and %U.
    %R prints the value of REGISTER_PREFIX.
    %L prints the value of LOCAL_LABEL_PREFIX.
 /* A poor man's fprintf, with the added features of %I, %R, %L, and %U.
    %R prints the value of REGISTER_PREFIX.
    %L prints the value of LOCAL_LABEL_PREFIX.
@@ -3685,7 +3824,7 @@ asm_fprintf (FILE *file, const char *p, ...)
 void
 split_double (rtx value, rtx *first, rtx *second)
 {
 void
 split_double (rtx value, rtx *first, rtx *second)
 {
-  if (GET_CODE (value) == CONST_INT)
+  if (CONST_INT_P (value))
     {
       if (HOST_BITS_PER_WIDE_INT >= (2 * BITS_PER_WORD))
        {
     {
       if (HOST_BITS_PER_WIDE_INT >= (2 * BITS_PER_WORD))
        {
@@ -3694,10 +3833,11 @@ split_double (rtx value, rtx *first, rtx *second)
             Sign extend each half to HOST_WIDE_INT.  */
          unsigned HOST_WIDE_INT low, high;
          unsigned HOST_WIDE_INT mask, sign_bit, sign_extend;
             Sign extend each half to HOST_WIDE_INT.  */
          unsigned HOST_WIDE_INT low, high;
          unsigned HOST_WIDE_INT mask, sign_bit, sign_extend;
+         unsigned bits_per_word = BITS_PER_WORD;
 
          /* Set sign_bit to the most significant bit of a word.  */
          sign_bit = 1;
 
          /* Set sign_bit to the most significant bit of a word.  */
          sign_bit = 1;
-         sign_bit <<= BITS_PER_WORD - 1;
+         sign_bit <<= bits_per_word - 1;
 
          /* Set mask so that all bits of the word are set.  We could
             have used 1 << BITS_PER_WORD instead of basing the
 
          /* Set mask so that all bits of the word are set.  We could
             have used 1 << BITS_PER_WORD instead of basing the
@@ -3720,7 +3860,7 @@ split_double (rtx value, rtx *first, rtx *second)
          /* Pick the higher word, shifted to the least significant
             bits, and sign-extend it.  */
          high = INTVAL (value);
          /* Pick the higher word, shifted to the least significant
             bits, and sign-extend it.  */
          high = INTVAL (value);
-         high >>= BITS_PER_WORD - 1;
+         high >>= bits_per_word - 1;
          high >>= 1;
          high &= mask;
          if (high & sign_bit)
          high >>= 1;
          high &= mask;
          if (high & sign_bit)
@@ -3827,7 +3967,7 @@ leaf_function_p (void)
   rtx insn;
   rtx link;
 
   rtx insn;
   rtx link;
 
-  if (current_function_profile || profile_arc_flag)
+  if (crtl->profile || profile_arc_flag)
     return 0;
 
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
     return 0;
 
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
@@ -3841,7 +3981,7 @@ leaf_function_p (void)
          && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0)))
        return 0;
     }
          && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0)))
        return 0;
     }
-  for (link = current_function_epilogue_delay_list;
+  for (link = crtl->epilogue_delay_list;
        link;
        link = XEXP (link, 1))
     {
        link;
        link = XEXP (link, 1))
     {
@@ -3902,7 +4042,7 @@ only_leaf_regs_used (void)
        && ! permitted_reg_in_leaf_functions[i])
       return 0;
 
        && ! permitted_reg_in_leaf_functions[i])
       return 0;
 
-  if (current_function_uses_pic_offset_table
+  if (crtl->uses_pic_offset_table
       && pic_offset_table_rtx != 0
       && REG_P (pic_offset_table_rtx)
       && ! permitted_reg_in_leaf_functions[REGNO (pic_offset_table_rtx)])
       && pic_offset_table_rtx != 0
       && REG_P (pic_offset_table_rtx)
       && ! permitted_reg_in_leaf_functions[REGNO (pic_offset_table_rtx)])
@@ -3925,7 +4065,7 @@ leaf_renumber_regs (rtx first)
   for (insn = first; insn; insn = NEXT_INSN (insn))
     if (INSN_P (insn))
       leaf_renumber_regs_insn (PATTERN (insn));
   for (insn = first; insn; insn = NEXT_INSN (insn))
     if (INSN_P (insn))
       leaf_renumber_regs_insn (PATTERN (insn));
-  for (insn = current_function_epilogue_delay_list;
+  for (insn = crtl->epilogue_delay_list;
        insn;
        insn = XEXP (insn, 1))
     if (INSN_P (XEXP (insn, 0)))
        insn;
        insn = XEXP (insn, 1))
     if (INSN_P (XEXP (insn, 0)))
@@ -4076,8 +4216,7 @@ debug_queue_symbol (tree decl)
   if (symbol_queue_index >= symbol_queue_size)
     {
       symbol_queue_size += 10;
   if (symbol_queue_index >= symbol_queue_size)
     {
       symbol_queue_size += 10;
-      symbol_queue = xrealloc (symbol_queue,
-                              symbol_queue_size * sizeof (tree));
+      symbol_queue = XRESIZEVEC (tree, symbol_queue, symbol_queue_size);
     }
 
   symbol_queue[symbol_queue_index++] = decl;
     }
 
   symbol_queue[symbol_queue_index++] = decl;
@@ -4116,19 +4255,13 @@ rest_of_handle_final (void)
   final (get_insns (), asm_out_file, optimize);
   final_end_function ();
 
   final (get_insns (), asm_out_file, optimize);
   final_end_function ();
 
-#ifdef TARGET_UNWIND_INFO
-  /* ??? The IA-64 ".handlerdata" directive must be issued before
-     the ".endp" directive that closes the procedure descriptor.  */
+  /* The IA-64 ".handlerdata" directive must be issued before the ".endp"
+     directive that closes the procedure descriptor.  Similarly, for x64 SEH.
+     Otherwise it's not strictly necessary, but it doesn't hurt either.  */
   output_function_exception_table (fnname);
   output_function_exception_table (fnname);
-#endif
 
   assemble_end_function (current_function_decl, fnname);
 
 
   assemble_end_function (current_function_decl, fnname);
 
-#ifndef TARGET_UNWIND_INFO
-  /* Otherwise, it feels unclean to switch sections in the middle.  */
-  output_function_exception_table (fnname);
-#endif
-
   user_defined_section_attribute = false;
 
   /* Free up reg info memory.  */
   user_defined_section_attribute = false;
 
   /* Free up reg info memory.  */
@@ -4149,8 +4282,13 @@ rest_of_handle_final (void)
      *will* be routed past here.  */
 
   timevar_push (TV_SYMOUT);
      *will* be routed past here.  */
 
   timevar_push (TV_SYMOUT);
-  (*debug_hooks->function_decl) (current_function_decl);
+  if (!DECL_IGNORED_P (current_function_decl))
+    debug_hooks->function_decl (current_function_decl);
   timevar_pop (TV_SYMOUT);
   timevar_pop (TV_SYMOUT);
+
+  /* Release the blocks that are linked to DECL_INITIAL() to free the memory.  */
+  DECL_INITIAL (current_function_decl) = error_mark_node;
+
   if (DECL_STATIC_CONSTRUCTOR (current_function_decl)
       && targetm.have_ctors_dtors)
     targetm.asm_out.constructor (XEXP (DECL_RTL (current_function_decl), 0),
   if (DECL_STATIC_CONSTRUCTOR (current_function_decl)
       && targetm.have_ctors_dtors)
     targetm.asm_out.constructor (XEXP (DECL_RTL (current_function_decl), 0),
@@ -4164,9 +4302,11 @@ rest_of_handle_final (void)
   return 0;
 }
 
   return 0;
 }
 
-struct tree_opt_pass pass_final =
+struct rtl_opt_pass pass_final =
 {
 {
-  NULL,                                 /* name */
+ {
+  RTL_PASS,
+  "final",                              /* name */
   NULL,                                 /* gate */
   rest_of_handle_final,                 /* execute */
   NULL,                                 /* sub */
   NULL,                                 /* gate */
   rest_of_handle_final,                 /* execute */
   NULL,                                 /* sub */
@@ -4177,8 +4317,8 @@ struct tree_opt_pass pass_final =
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
-  TODO_ggc_collect,                     /* todo_flags_finish */
-  0                                     /* letter */
+  TODO_ggc_collect                      /* todo_flags_finish */
+ }
 };
 
 
 };
 
 
@@ -4190,8 +4330,10 @@ rest_of_handle_shorten_branches (void)
   return 0;
 }
 
   return 0;
 }
 
-struct tree_opt_pass pass_shorten_branches =
+struct rtl_opt_pass pass_shorten_branches =
 {
 {
+ {
+  RTL_PASS,
   "shorten",                            /* name */
   NULL,                                 /* gate */
   rest_of_handle_shorten_branches,      /* execute */
   "shorten",                            /* name */
   NULL,                                 /* gate */
   rest_of_handle_shorten_branches,      /* execute */
@@ -4203,8 +4345,8 @@ struct tree_opt_pass pass_shorten_branches =
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
-  TODO_dump_func,                       /* todo_flags_finish */
-  0                                     /* letter */
+  TODO_dump_func                        /* todo_flags_finish */
+ }
 };
 
 
 };
 
 
@@ -4212,6 +4354,47 @@ static unsigned int
 rest_of_clean_state (void)
 {
   rtx insn, next;
 rest_of_clean_state (void)
 {
   rtx insn, next;
+  FILE *final_output = NULL;
+  int save_unnumbered = flag_dump_unnumbered;
+  int save_noaddr = flag_dump_noaddr;
+
+  if (flag_dump_final_insns)
+    {
+      final_output = fopen (flag_dump_final_insns, "a");
+      if (!final_output)
+       {
+         error ("could not open final insn dump file %qs: %m",
+                flag_dump_final_insns);
+         flag_dump_final_insns = NULL;
+       }
+      else
+       {
+         const char *aname;
+         struct cgraph_node *node = cgraph_node (current_function_decl);
+
+         aname = (IDENTIFIER_POINTER
+                  (DECL_ASSEMBLER_NAME (current_function_decl)));
+         fprintf (final_output, "\n;; Function (%s) %s\n\n", aname,
+            node->frequency == NODE_FREQUENCY_HOT
+            ? " (hot)"
+            : node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED
+            ? " (unlikely executed)"
+            : node->frequency == NODE_FREQUENCY_EXECUTED_ONCE
+            ? " (executed once)"
+            : "");
+
+         flag_dump_noaddr = flag_dump_unnumbered = 1;
+         if (flag_compare_debug_opt || flag_compare_debug)
+           dump_flags |= TDF_NOUID;
+         final_insns_dump_p = true;
+
+         for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+           if (LABEL_P (insn))
+             INSN_UID (insn) = CODE_LABEL_NUMBER (insn);
+           else
+             INSN_UID (insn) = 0;
+       }
+    }
 
   /* It is very important to decompose the RTL instruction chain here:
      debug information keeps pointing into CODE_LABEL insns inside the function
 
   /* It is very important to decompose the RTL instruction chain here:
      debug information keeps pointing into CODE_LABEL insns inside the function
@@ -4222,6 +4405,29 @@ rest_of_clean_state (void)
       next = NEXT_INSN (insn);
       NEXT_INSN (insn) = NULL;
       PREV_INSN (insn) = NULL;
       next = NEXT_INSN (insn);
       NEXT_INSN (insn) = NULL;
       PREV_INSN (insn) = NULL;
+
+      if (final_output
+         && (!NOTE_P (insn) ||
+             (NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION
+              && NOTE_KIND (insn) != NOTE_INSN_BLOCK_BEG
+              && NOTE_KIND (insn) != NOTE_INSN_BLOCK_END
+              && NOTE_KIND (insn) != NOTE_INSN_CFA_RESTORE_STATE)))
+       print_rtl_single (final_output, insn);
+
+    }
+
+  if (final_output)
+    {
+      flag_dump_noaddr = save_noaddr;
+      flag_dump_unnumbered = save_unnumbered;
+      final_insns_dump_p = false;
+
+      if (fclose (final_output))
+       {
+         error ("could not close final insn dump file %qs: %m",
+                flag_dump_final_insns);
+         flag_dump_final_insns = NULL;
+       }
     }
 
   /* In case the function was not output,
     }
 
   /* In case the function was not output,
@@ -4232,6 +4438,7 @@ rest_of_clean_state (void)
     sdbout_types (NULL_TREE);
 #endif
 
     sdbout_types (NULL_TREE);
 #endif
 
+  flag_rerun_cse_after_global_opts = 0;
   reload_completed = 0;
   epilogue_completed = 0;
 #ifdef STACK_REGS
   reload_completed = 0;
   epilogue_completed = 0;
 #ifdef STACK_REGS
@@ -4247,11 +4454,16 @@ rest_of_clean_state (void)
 
   free_bb_for_insn ();
 
 
   free_bb_for_insn ();
 
-  if (targetm.binds_local_p (current_function_decl))
+  delete_tree_ssa ();
+
+  /* We can reduce stack alignment on call site only when we are sure that
+     the function body just produced will be actually used in the final
+     executable.  */
+  if (decl_binds_to_current_def_p (current_function_decl))
     {
     {
-      int pref = cfun->preferred_stack_boundary;
-      if (cfun->stack_alignment_needed > cfun->preferred_stack_boundary)
-        pref = cfun->stack_alignment_needed;
+      unsigned int pref = crtl->preferred_stack_boundary;
+      if (crtl->stack_alignment_needed > crtl->preferred_stack_boundary)
+        pref = crtl->stack_alignment_needed;
       cgraph_rtl_info (current_function_decl)->preferred_incoming_stack_boundary
         = pref;
     }
       cgraph_rtl_info (current_function_decl)->preferred_incoming_stack_boundary
         = pref;
     }
@@ -4272,9 +4484,11 @@ rest_of_clean_state (void)
   return 0;
 }
 
   return 0;
 }
 
-struct tree_opt_pass pass_clean_state =
+struct rtl_opt_pass pass_clean_state =
 {
 {
-  NULL,                                 /* name */
+ {
+  RTL_PASS,
+  "*clean_state",                       /* name */
   NULL,                                 /* gate */
   rest_of_clean_state,                  /* execute */
   NULL,                                 /* sub */
   NULL,                                 /* gate */
   rest_of_clean_state,                  /* execute */
   NULL,                                 /* sub */
@@ -4285,7 +4499,6 @@ struct tree_opt_pass pass_clean_state =
   0,                                    /* properties_provided */
   PROP_rtl,                             /* properties_destroyed */
   0,                                    /* todo_flags_start */
   0,                                    /* properties_provided */
   PROP_rtl,                             /* properties_destroyed */
   0,                                    /* todo_flags_start */
-  0,                                    /* todo_flags_finish */
-  0                                     /* letter */
+  0                                     /* todo_flags_finish */
+ }
 };
 };
-