a-clrefi.adb, [...]: New files
[gcc.git] / gcc / final.c
index 2b13fb907b9cdc151b31f788af0be436eef5864c..e3a27647527afc2ae51e7cdd0b8fc6c5544f2846 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, 2002, 2003, 2004, 2005
+   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -76,6 +76,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "timevar.h"
 #include "cgraph.h"
 #include "coverage.h"
+#include "vecprim.h"
 
 #ifdef XCOFF_DEBUGGING_INFO
 #include "xcoffout.h"          /* Needed for external data
@@ -137,8 +138,8 @@ static const char *last_filename;
 
 /* Whether to force emission of a line note before the next insn.  */
 static bool force_source_line = false;
-  
-extern int length_unit_log; /* This is defined in insn-attrtab.c.  */
+
+extern const 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 die.
@@ -320,7 +321,7 @@ dbr_sequence_length (void)
 
 static int *insn_lengths;
 
-varray_type insn_addresses_;
+VEC(int,heap) *insn_addresses_;
 
 /* Max uid for which the above arrays are valid.  */
 static int insn_lengths_max_uid;
@@ -380,7 +381,7 @@ init_insn_lengths (void)
 }
 
 /* Obtain the current length of an insn.  If branch shortening has been done,
-   get its actual length.  Otherwise, use FALLBACK_FN to calcualte the
+   get its actual length.  Otherwise, use FALLBACK_FN to calculate the
    length.  */
 static inline int
 get_attr_length_1 (rtx insn ATTRIBUTE_UNUSED,
@@ -676,7 +677,10 @@ insn_current_reference_address (rtx branch)
 }
 #endif /* HAVE_ATTR_length */
 \f
-void
+/* Compute branch alignments based on frequency information in the
+   CFG.  */
+
+static unsigned int
 compute_alignments (void)
 {
   int log, max_skip, max_log;
@@ -690,12 +694,11 @@ compute_alignments (void)
 
   max_labelno = max_label_num ();
   min_labelno = get_first_label_num ();
-  label_align = xcalloc (max_labelno - min_labelno + 1,
-                        sizeof (struct label_alignment));
+  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)
-    return;
+    return 0;
 
   FOR_EACH_BB (bb)
     {
@@ -758,6 +761,7 @@ compute_alignments (void)
       LABEL_TO_ALIGNMENT (label) = max_log;
       LABEL_TO_MAX_SKIP (label) = max_skip;
     }
+  return 0;
 }
 
 struct tree_opt_pass pass_compute_alignments =
@@ -813,8 +817,8 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
 
   /* Free uid_shuid before reallocating it.  */
   free (uid_shuid);
-  
-  uid_shuid = xmalloc (max_uid * sizeof *uid_shuid);
+
+  uid_shuid = XNEWVEC (int, max_uid);
 
   if (max_labelno != max_label_num ())
     {
@@ -853,14 +857,9 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
 
       INSN_SHUID (insn) = i++;
       if (INSN_P (insn))
-       {
-         /* reorg might make the first insn of a loop being run once only,
-             and delete the label in front of it.  Then we want to apply
-             the loop alignment to the new label created by reorg, which
-             is separated by the former loop start insn from the
-            NOTE_INSN_LOOP_BEG.  */
-       }
-      else if (LABEL_P (insn))
+       continue;
+
+      if (LABEL_P (insn))
        {
          rtx next;
 
@@ -923,20 +922,20 @@ shorten_branches (rtx first ATTRIBUTE_UNUSED)
 #ifdef HAVE_ATTR_length
 
   /* Allocate the rest of the arrays.  */
-  insn_lengths = xmalloc (max_uid * sizeof (*insn_lengths));
+  insn_lengths = XNEWVEC (int, max_uid);
   insn_lengths_max_uid = max_uid;
   /* Syntax errors can lead to labels being outside of the main insn stream.
      Initialize insn_addresses, so that we get reproducible results.  */
   INSN_ADDRESSES_ALLOC (max_uid);
 
-  varying_length = xcalloc (max_uid, sizeof (char));
+  varying_length = XCNEWVEC (char, max_uid);
 
   /* Initialize uid_align.  We scan instructions
      from end to start, and keep in align_tab[n] the last seen insn
      that does an alignment of at least n+1, i.e. the successor
      in the alignment chain for an insn that does / has a known
      alignment of n.  */
-  uid_align = xcalloc (max_uid, sizeof *uid_align);
+  uid_align = XCNEWVEC (rtx, max_uid);
 
   for (i = MAX_CODE_ALIGN; --i >= 0;)
     align_tab[i] = NULL_RTX;
@@ -1358,7 +1357,7 @@ asm_insn_count (rtx body)
   if (GET_CODE (body) == ASM_INPUT)
     template = XSTR (body, 0);
   else
-    template = decode_asm_operands (body, NULL, NULL, NULL, NULL);
+    template = decode_asm_operands (body, NULL, NULL, NULL, NULL, NULL);
 
   for (; *template; template++)
     if (IS_ASM_LOGICAL_LINE_SEPARATOR (*template) || *template == '\n')
@@ -1419,7 +1418,6 @@ final_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file,
      function.  */
   if (write_symbols)
     {
-      remove_unnecessary_notes ();
       reemit_insn_block_notes ();
       number_blocks (current_function_decl);
       /* We never actually put out begin/end notes for the top-level
@@ -1547,33 +1545,6 @@ final (rtx first, FILE *file, int optimize)
 
   last_ignored_compare = 0;
 
-#ifdef SDB_DEBUGGING_INFO
-  /* When producing SDB debugging info, delete troublesome line number
-     notes from inlined functions in other files as well as duplicate
-     line number notes.  */
-  if (write_symbols == SDB_DEBUG)
-    {
-      rtx last = 0;
-      for (insn = first; insn; insn = NEXT_INSN (insn))
-       if (NOTE_P (insn) && NOTE_LINE_NUMBER (insn) > 0)
-         {
-           if (last != 0
-#ifdef USE_MAPPED_LOCATION
-               && NOTE_SOURCE_LOCATION (insn) == NOTE_SOURCE_LOCATION (last)
-#else
-               && NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last)
-               && NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last)
-#endif
-             )
-             {
-               delete_insn (insn);     /* Use delete_note.  */
-               continue;
-             }
-           last = insn;
-         }
-    }
-#endif
-
   for (insn = first; insn; insn = NEXT_INSN (insn))
     {
       if (INSN_UID (insn) > max_uid)       /* Find largest UID.  */
@@ -1597,7 +1568,7 @@ final (rtx first, FILE *file, int optimize)
   CC_STATUS_INIT;
 
   /* Output the insns.  */
-  for (insn = NEXT_INSN (first); insn;)
+  for (insn = first; insn;)
     {
 #ifdef HAVE_ATTR_length
       if ((unsigned) INSN_UID (insn) >= INSN_ADDRESSES_SIZE ())
@@ -1697,14 +1668,9 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
   switch (GET_CODE (insn))
     {
     case NOTE:
-      switch (NOTE_LINE_NUMBER (insn))
+      switch (NOTE_KIND (insn))
        {
        case NOTE_INSN_DELETED:
-       case NOTE_INSN_LOOP_BEG:
-       case NOTE_INSN_LOOP_END:
-       case NOTE_INSN_FUNCTION_END:
-       case NOTE_INSN_REPEATED_LINE_NUMBER:
-       case NOTE_INSN_EXPECTED_VALUE:
          break;
 
        case NOTE_INSN_SWITCH_TEXT_SECTIONS:
@@ -1712,9 +1678,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
          (*debug_hooks->switch_text_section) ();
          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
@@ -1826,11 +1791,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
          (*debug_hooks->var_location) (insn);
          break;
 
-       case 0:
-         break;
-
        default:
-         gcc_assert (NOTE_LINE_NUMBER (insn) > 0);
+         gcc_unreachable ();
          break;
        }
       break;
@@ -1958,6 +1920,10 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
        int insn_code_number;
        const char *template;
 
+#ifdef HAVE_conditional_execution
+       /* 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.  */
 
@@ -2072,12 +2038,27 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 
            if (string[0])
              {
+               location_t loc;
+
                if (! app_on)
                  {
                    fputs (ASM_APP_ON, file);
                    app_on = 1;
                  }
+#ifdef USE_MAPPED_LOCATION
+               loc = 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);
                fprintf (asm_out_file, "\t%s\n", string);
+#if HAVE_AS_LINE_ZERO
+               if (*loc.file && loc.line)
+                 fprintf (asm_out_file, "%s 0 \"\" 2\n", ASM_COMMENT_START);
+#endif
              }
            break;
          }
@@ -2088,12 +2069,13 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
            unsigned int noperands = asm_noperands (body);
            rtx *ops = alloca (noperands * sizeof (rtx));
            const char *string;
+           location_t loc;
 
            /* There's no telling what that did to the condition codes.  */
            CC_STATUS_INIT;
 
            /* Get out the operand values.  */
-           string = decode_asm_operands (body, ops, NULL, NULL, NULL);
+           string = decode_asm_operands (body, ops, NULL, NULL, NULL, &loc);
            /* Inhibit dieing on what would otherwise be compiler bugs.  */
            insn_noperands = noperands;
            this_is_asm_operands = insn;
@@ -2110,7 +2092,14 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
                    fputs (ASM_APP_ON, file);
                    app_on = 1;
                  }
+               if (loc.file && loc.line)
+                 fprintf (asm_out_file, "%s %i \"%s\" 1\n",
+                          ASM_COMMENT_START, loc.line, loc.file);
                output_asm_insn (string, ops);
+#if HAVE_AS_LINE_ZERO
+               if (loc.file && loc.line)
+                 fprintf (asm_out_file, "%s 0 \"\" 2\n", ASM_COMMENT_START);
+#endif
              }
 
            this_is_asm_operands = 0;
@@ -2272,6 +2261,76 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
              INSN_CODE (insn) = -1;
          }
 
+       /* If this is a conditional trap, maybe modify it if the cc's
+          are in a nonstandard state so that it accomplishes the same
+          thing that it would do straightforwardly if the cc's were
+          set up normally.  */
+       if (cc_status.flags != 0
+           && NONJUMP_INSN_P (insn)
+           && GET_CODE (body) == TRAP_IF
+           && COMPARISON_P (TRAP_CONDITION (body))
+           && XEXP (TRAP_CONDITION (body), 0) == cc0_rtx)
+         {
+           /* This function may alter the contents of its argument
+              and clear some of the cc_status.flags bits.
+              It may also return 1 meaning condition now always true
+              or -1 meaning condition now always false
+              or 2 meaning condition nontrivial but altered.  */
+           int result = alter_cond (TRAP_CONDITION (body));
+
+           /* If TRAP_CONDITION has become always false, delete the
+              instruction.  */
+           if (result == -1)
+             {
+               delete_insn (insn);
+               break;
+             }
+
+           /* If TRAP_CONDITION has become always true, replace
+              TRAP_CONDITION with const_true_rtx.  */
+           if (result == 1)
+             TRAP_CONDITION (body) = const_true_rtx;
+
+           /* Rerecognize the instruction if it has changed.  */
+           if (result != 0)
+             INSN_CODE (insn) = -1;
+         }
+
+       /* If this is a conditional trap, maybe modify it if the cc's
+          are in a nonstandard state so that it accomplishes the same
+          thing that it would do straightforwardly if the cc's were
+          set up normally.  */
+       if (cc_status.flags != 0
+           && NONJUMP_INSN_P (insn)
+           && GET_CODE (body) == TRAP_IF
+           && COMPARISON_P (TRAP_CONDITION (body))
+           && XEXP (TRAP_CONDITION (body), 0) == cc0_rtx)
+         {
+           /* This function may alter the contents of its argument
+              and clear some of the cc_status.flags bits.
+              It may also return 1 meaning condition now always true
+              or -1 meaning condition now always false
+              or 2 meaning condition nontrivial but altered.  */
+           int result = alter_cond (TRAP_CONDITION (body));
+
+           /* If TRAP_CONDITION has become always false, delete the
+              instruction.  */
+           if (result == -1)
+             {
+               delete_insn (insn);
+               break;
+             }
+
+           /* If TRAP_CONDITION has become always true, replace
+              TRAP_CONDITION with const_true_rtx.  */
+           if (result == 1)
+             TRAP_CONDITION (body) = const_true_rtx;
+
+           /* Rerecognize the instruction if it has changed.  */
+           if (result != 0)
+             INSN_CODE (insn) = -1;
+         }
+
        /* Make same adjustments to instructions that examine the
           condition codes without jumping and instructions that
           handle conditional moves (if this machine has either one).  */
@@ -2393,8 +2452,6 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 #ifdef HAVE_conditional_execution
        if (GET_CODE (PATTERN (insn)) == COND_EXEC)
          current_insn_predicate = COND_EXEC_TEST (PATTERN (insn));
-       else
-         current_insn_predicate = NULL_RTX;
 #endif
 
 #ifdef HAVE_cc0
@@ -3054,7 +3111,7 @@ output_asm_insn (const char *template, rtx *operands)
            int letter = *p++;
            unsigned long opnum;
            char *endptr;
-           
+
            opnum = strtoul (p, &endptr, 10);
 
            if (endptr == p)
@@ -3099,7 +3156,7 @@ output_asm_insn (const char *template, rtx *operands)
          {
            unsigned long opnum;
            char *endptr;
-           
+
            opnum = strtoul (p, &endptr, 10);
            if (this_is_asm_operands && opnum >= insn_noperands)
              output_operand_lossage ("operand number out of range");
@@ -3148,7 +3205,7 @@ output_asm_label (rtx x)
     x = XEXP (x, 0);
   if (LABEL_P (x)
       || (NOTE_P (x)
-         && NOTE_LINE_NUMBER (x) == NOTE_INSN_DELETED_LABEL))
+         && NOTE_KIND (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");
@@ -3673,7 +3730,7 @@ int
 final_forward_branch_p (rtx insn)
 {
   int insn_id, label_id;
-  
+
   gcc_assert (uid_shuid);
   insn_id = INSN_SHUID (insn);
   label_id = INSN_SHUID (JUMP_LABEL (insn));
@@ -3849,7 +3906,7 @@ debug_flush_symbol_queue (void)
 
   for (i = 0; i < symbol_queue_index; ++i)
     {
-      /* If we pushed queued symbols then such symbols are must be
+      /* If we pushed queued symbols then such symbols must be
          output no matter what anyone else says.  Specifically,
          we need to make sure dbxout_symbol() thinks the symbol was
          used and also we need to override TYPE_DECL_SUPPRESS_DEBUG
@@ -3901,7 +3958,7 @@ debug_free_queue (void)
 }
 \f
 /* Turn the RTL into assembly.  */
-static void
+static unsigned int
 rest_of_handle_final (void)
 {
   rtx x;
@@ -3924,14 +3981,14 @@ rest_of_handle_final (void)
 #ifdef TARGET_UNWIND_INFO
   /* ??? The IA-64 ".handlerdata" directive must be issued before
      the ".endp" directive that closes the procedure descriptor.  */
-  output_function_exception_table ();
+  output_function_exception_table (fnname);
 #endif
 
   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 ();
+  output_function_exception_table (fnname);
 #endif
 
   user_defined_section_attribute = false;
@@ -3956,6 +4013,17 @@ rest_of_handle_final (void)
   timevar_push (TV_SYMOUT);
   (*debug_hooks->function_decl) (current_function_decl);
   timevar_pop (TV_SYMOUT);
+  if (DECL_STATIC_CONSTRUCTOR (current_function_decl)
+      && targetm.have_ctors_dtors)
+    targetm.asm_out.constructor (XEXP (DECL_RTL (current_function_decl), 0),
+                                decl_init_priority_lookup
+                                  (current_function_decl));
+  if (DECL_STATIC_DESTRUCTOR (current_function_decl)
+      && targetm.have_ctors_dtors)
+    targetm.asm_out.destructor (XEXP (DECL_RTL (current_function_decl), 0),
+                               decl_fini_priority_lookup
+                                 (current_function_decl));
+  return 0;
 }
 
 struct tree_opt_pass pass_final =
@@ -3976,13 +4044,14 @@ struct tree_opt_pass pass_final =
 };
 
 
-static void
+static unsigned int
 rest_of_handle_shorten_branches (void)
 {
   /* Shorten branches.  */
   shorten_branches (get_insns ());
+  return 0;
 }
+
 struct tree_opt_pass pass_shorten_branches =
 {
   "shorten",                            /* name */
@@ -4001,7 +4070,7 @@ struct tree_opt_pass pass_shorten_branches =
 };
 
 
-static void
+static unsigned int
 rest_of_clean_state (void)
 {
   rtx insn, next;
@@ -4029,6 +4098,9 @@ rest_of_clean_state (void)
   epilogue_completed = 0;
   flow2_completed = 0;
   no_new_pseudos = 0;
+#ifdef STACK_REGS
+  regstack_completed = 0;
+#endif
 
   /* Clear out the insn_length contents now that they are no
      longer valid.  */
@@ -4063,6 +4135,7 @@ rest_of_clean_state (void)
   /* We're done with this function.  Free up memory if we can.  */
   free_after_parsing (cfun);
   free_after_compilation (cfun);
+  return 0;
 }
 
 struct tree_opt_pass pass_clean_state =