OSDN Git Service

contrib:
[pf3gnuchains/gcc-fork.git] / gcc / final.c
index 008a773..9816624 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, 2006, 2007
+   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -78,6 +78,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "df.h"
 #include "vecprim.h"
 #include "ggc.h"
+#include "cfgloop.h"
+#include "params.h"
 
 #ifdef XCOFF_DEBUGGING_INFO
 #include "xcoffout.h"          /* Needed for external data
@@ -109,7 +111,7 @@ along with GCC; see the file COPYING3.  If not see
 
 /* Is the given character a logical line separator for the assembler?  */
 #ifndef IS_ASM_LOGICAL_LINE_SEPARATOR
-#define IS_ASM_LOGICAL_LINE_SEPARATOR(C) ((C) == ';')
+#define IS_ASM_LOGICAL_LINE_SEPARATOR(C, STR) ((C) == ';')
 #endif
 
 #ifndef JUMP_TABLES_IN_TEXT_SECTION
@@ -137,6 +139,10 @@ static int high_function_linenum;
 /* Filename of last NOTE.  */
 static const char *last_filename;
 
+/* Override filename and line number.  */
+static const char *override_filename;
+static int override_linenum;
+
 /* Whether to force emission of a line note before the next insn.  */
 static bool force_source_line = false;
 
@@ -669,6 +675,8 @@ compute_alignments (void)
 {
   int log, max_skip, max_log;
   basic_block bb;
+  int freq_max = 0;
+  int freq_threshold = 0;
 
   if (label_align)
     {
@@ -684,6 +692,19 @@ compute_alignments (void)
   if (! optimize || optimize_size)
     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);
+    }
+  FOR_EACH_BB (bb)
+    if (bb->frequency > freq_max)
+      freq_max = bb->frequency;
+  freq_threshold = freq_max / PARAM_VALUE (PARAM_ALIGN_THRESHOLD);
+
+  if (dump_file)
+    fprintf(dump_file, "freq_max: %i\n",freq_max);
   FOR_EACH_BB (bb)
     {
       rtx label = BB_HEAD (bb);
@@ -693,7 +714,12 @@ compute_alignments (void)
 
       if (!LABEL_P (label)
          || probably_never_executed_bb_p (bb))
-       continue;
+       {
+         if (dump_file)
+           fprintf(dump_file, "BB %4i freq %4i loop %2i loop_depth %2i skipped.\n",
+                   bb->index, bb->frequency, bb->loop_father->num, bb->loop_depth);
+         continue;
+       }
       max_log = LABEL_ALIGN (label);
       max_skip = LABEL_ALIGN_MAX_SKIP;
 
@@ -704,6 +730,18 @@ compute_alignments (void)
          else
            branch_frequency += EDGE_FREQUENCY (e);
        }
+      if (dump_file)
+       {
+         fprintf(dump_file, "BB %4i freq %4i loop %2i loop_depth %2i fall %4i branch %4i",
+                 bb->index, bb->frequency, bb->loop_father->num,
+                 bb->loop_depth,
+                 fallthru_frequency, branch_frequency);
+         if (!bb->loop_father->inner && bb->loop_father->num)
+           fprintf (dump_file, " inner_loop");
+         if (bb->loop_father->header == bb)
+           fprintf (dump_file, " loop_header");
+         fprintf (dump_file, "\n");
+       }
 
       /* There are two purposes to align block with no fallthru incoming edge:
         1) to avoid fetch stalls when branch destination is near cache boundary
@@ -716,12 +754,14 @@ compute_alignments (void)
         when function is called.  */
 
       if (!has_fallthru
-         && (branch_frequency > BB_FREQ_MAX / 10
+         && (branch_frequency > freq_threshold
              || (bb->frequency > bb->prev_bb->frequency * 10
                  && (bb->prev_bb->frequency
                      <= ENTRY_BLOCK_PTR->frequency / 2))))
        {
          log = JUMP_ALIGN (label);
+         if (dump_file)
+           fprintf(dump_file, "  jump alignment added.\n");
          if (max_log < log)
            {
              max_log = log;
@@ -732,10 +772,13 @@ compute_alignments (void)
         align it.  It is most likely a first block of loop.  */
       if (has_fallthru
          && maybe_hot_bb_p (bb)
-         && branch_frequency + fallthru_frequency > BB_FREQ_MAX / 10
-         && branch_frequency > fallthru_frequency * 2)
+         && branch_frequency + fallthru_frequency > freq_threshold
+         && (branch_frequency
+             > fallthru_frequency * PARAM_VALUE (PARAM_ALIGN_LOOP_ITERATIONS)))
        {
          log = LOOP_ALIGN (label);
+         if (dump_file)
+           fprintf(dump_file, "  internal loop alignment added.\n");
          if (max_log < log)
            {
              max_log = log;
@@ -745,12 +788,17 @@ compute_alignments (void)
       LABEL_TO_ALIGNMENT (label) = max_log;
       LABEL_TO_MAX_SKIP (label) = max_skip;
     }
+
+  if (dump_file)
+    loop_optimizer_finalize ();
   return 0;
 }
 
-struct tree_opt_pass pass_compute_alignments =
+struct rtl_opt_pass pass_compute_alignments =
 {
-  NULL,                                 /* name */
+ {
+  RTL_PASS,
+  "alignments",                         /* name */
   NULL,                                 /* gate */
   compute_alignments,                   /* execute */
   NULL,                                 /* sub */
@@ -761,8 +809,9 @@ struct tree_opt_pass pass_compute_alignments =
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
-  0,                                    /* todo_flags_finish */
-  0                                     /* letter */
+  TODO_dump_func | TODO_verify_rtl_sharing
+  | TODO_ggc_collect                    /* todo_flags_finish */
+ }
 };
 
 \f
@@ -1344,7 +1393,8 @@ asm_insn_count (rtx body)
     template = decode_asm_operands (body, NULL, NULL, NULL, NULL, NULL);
 
   for (; *template; template++)
-    if (IS_ASM_LOGICAL_LINE_SEPARATOR (*template) || *template == '\n')
+    if (IS_ASM_LOGICAL_LINE_SEPARATOR (*template, template)
+       || *template == '\n')
       count++;
 
   return count;
@@ -1476,6 +1526,15 @@ final_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file,
       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 ());
 
@@ -1523,7 +1582,9 @@ profile_function (FILE *file ATTRIBUTE_UNUSED)
 
 #if defined(ASM_OUTPUT_REG_PUSH)
   if (sval && svrtx != NULL_RTX && REG_P (svrtx))
-    ASM_OUTPUT_REG_PUSH (file, REGNO (svrtx));
+    {
+      ASM_OUTPUT_REG_PUSH (file, REGNO (svrtx));
+    }
 #endif
 
 #if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
@@ -1554,7 +1615,9 @@ profile_function (FILE *file ATTRIBUTE_UNUSED)
 
 #if defined(ASM_OUTPUT_REG_PUSH)
   if (sval && svrtx != NULL_RTX && REG_P (svrtx))
-    ASM_OUTPUT_REG_POP (file, REGNO (svrtx));
+    {
+      ASM_OUTPUT_REG_POP (file, REGNO (svrtx));
+    }
 #endif
 }
 
@@ -1725,7 +1788,13 @@ 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;
-         (*debug_hooks->switch_text_section) ();
+#ifdef DWARF2_UNWIND_INFO
+         if (dwarf2out_do_frame ())
+           dwarf2out_switch_text_section ();
+         else
+#endif
+           (*debug_hooks->switch_text_section) ();
+
          switch_to_section (current_function_section ());
          break;
 
@@ -1809,6 +1878,18 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
              /* Mark this block as output.  */
              TREE_ASM_WRITTEN (NOTE_BLOCK (insn)) = 1;
            }
+         if (write_symbols == DBX_DEBUG
+             || write_symbols == SDB_DEBUG)
+           {
+             location_t *locus_ptr
+               = block_nonartificial_location (NOTE_BLOCK (insn));
+
+             if (locus_ptr != NULL)
+               {
+                 override_filename = LOCATION_FILE (*locus_ptr);
+                 override_linenum = LOCATION_LINE (*locus_ptr);
+               }
+           }
          break;
 
        case NOTE_INSN_BLOCK_END:
@@ -1828,6 +1909,24 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 
              (*debug_hooks->end_block) (high_block_linenum, n);
            }
+         if (write_symbols == DBX_DEBUG
+             || write_symbols == SDB_DEBUG)
+           {
+             tree outer_block = BLOCK_SUPERCONTEXT (NOTE_BLOCK (insn));
+             location_t *locus_ptr
+               = block_nonartificial_location (outer_block);
+
+             if (locus_ptr != NULL)
+               {
+                 override_filename = LOCATION_FILE (*locus_ptr);
+                 override_linenum = LOCATION_LINE (*locus_ptr);
+               }
+             else
+               {
+                 override_filename = NULL;
+                 override_linenum = 0;
+               }
+           }
          break;
 
        case NOTE_INSN_DELETED_LABEL:
@@ -1879,30 +1978,6 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
        }
 #ifdef HAVE_cc0
       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))
@@ -2088,19 +2163,14 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 
            if (string[0])
              {
-               location_t loc;
+               expanded_location 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
+               loc = expand_location (ASM_INPUT_SOURCE_LOCATION (body));
                if (*loc.file && loc.line)
                  fprintf (asm_out_file, "%s %i \"%s\" 1\n",
                           ASM_COMMENT_START, loc.line, loc.file);
@@ -2120,15 +2190,17 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
            rtx *ops = alloca (noperands * sizeof (rtx));
            const char *string;
            location_t loc;
+           expanded_location expanded;
 
            /* 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, &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);
 
 #ifdef FINAL_PRESCAN_INSN
            FINAL_PRESCAN_INSN (insn, ops, insn_noperands);
@@ -2142,12 +2214,12 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
                    fputs (ASM_APP_ON, file);
                    app_on = 1;
                  }
-               if (loc.file && loc.line)
+               if (expanded.file && expanded.line)
                  fprintf (asm_out_file, "%s %i \"%s\" 1\n",
-                          ASM_COMMENT_START, loc.line, loc.file);
+                          ASM_COMMENT_START, expanded.line, expanded.file);
                output_asm_insn (string, ops);
 #if HAVE_AS_LINE_ZERO
-               if (loc.file && loc.line)
+               if (expanded.file && expanded.line)
                  fprintf (asm_out_file, "%s 0 \"\" 2\n", ASM_COMMENT_START);
 #endif
              }
@@ -2346,41 +2418,6 @@ 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;
-         }
-
        /* Make same adjustments to instructions that examine the
           condition codes without jumping and instructions that
           handle conditional moves (if this machine has either one).  */
@@ -2602,8 +2639,19 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
 static bool
 notice_source_line (rtx insn)
 {
-  const char *filename = insn_file (insn);
-  int linenum = insn_line (insn);
+  const char *filename;
+  int linenum;
+
+  if (override_filename)
+    {
+      filename = override_filename;
+      linenum = override_linenum;
+    }
+  else
+    {
+      filename = insn_file (insn);
+      linenum = insn_line (insn);
+    }
 
   if (filename
       && (force_source_line
@@ -2703,8 +2751,15 @@ alter_subreg (rtx *xp)
       else if (REG_P (y))
        {
          /* Simplify_subreg can't handle some REG cases, but we have to.  */
-         unsigned int regno = subreg_regno (x);
-         *xp = gen_rtx_REG_offset (y, GET_MODE (x), regno, SUBREG_BYTE (x));
+         unsigned int regno;
+         HOST_WIDE_INT offset;
+
+         regno = subreg_regno (x);
+         if (subreg_lowpart_p (x))
+           offset = byte_lowpart_offset (GET_MODE (x), GET_MODE (y));
+         else
+           offset = SUBREG_BYTE (x);
+         *xp = gen_rtx_REG_offset (y, GET_MODE (x), regno, offset);
        }
     }
 
@@ -3373,6 +3428,10 @@ output_addr_const (FILE *file, rtx x)
        output_operand_lossage ("floating constant misused");
       break;
 
+    case CONST_FIXED:
+      fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_FIXED_VALUE_LOW (x));
+      break;
+
     case PLUS:
       /* Some assemblers need integer constants to appear last (eg masm).  */
       if (GET_CODE (XEXP (x, 0)) == CONST_INT)
@@ -3416,6 +3475,7 @@ output_addr_const (FILE *file, rtx x)
     case ZERO_EXTEND:
     case SIGN_EXTEND:
     case SUBREG:
+    case TRUNCATE:
       output_addr_const (file, XEXP (x, 0));
       break;
 
@@ -4087,8 +4147,10 @@ rest_of_handle_final (void)
   return 0;
 }
 
-struct tree_opt_pass pass_final =
+struct rtl_opt_pass pass_final =
 {
+ {
+  RTL_PASS,
   NULL,                                 /* name */
   NULL,                                 /* gate */
   rest_of_handle_final,                 /* execute */
@@ -4100,8 +4162,8 @@ struct tree_opt_pass pass_final =
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
-  TODO_ggc_collect,                     /* todo_flags_finish */
-  0                                     /* letter */
+  TODO_ggc_collect                      /* todo_flags_finish */
+ }
 };
 
 
@@ -4113,8 +4175,10 @@ rest_of_handle_shorten_branches (void)
   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 */
@@ -4126,8 +4190,8 @@ struct tree_opt_pass pass_shorten_branches =
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
-  TODO_dump_func,                       /* todo_flags_finish */
-  0                                     /* letter */
+  TODO_dump_func                        /* todo_flags_finish */
+ }
 };
 
 
@@ -4195,8 +4259,10 @@ rest_of_clean_state (void)
   return 0;
 }
 
-struct tree_opt_pass pass_clean_state =
+struct rtl_opt_pass pass_clean_state =
 {
+ {
+  RTL_PASS,
   NULL,                                 /* name */
   NULL,                                 /* gate */
   rest_of_clean_state,                  /* execute */
@@ -4208,7 +4274,7 @@ struct tree_opt_pass pass_clean_state =
   0,                                    /* properties_provided */
   PROP_rtl,                             /* properties_destroyed */
   0,                                    /* todo_flags_start */
-  0,                                    /* todo_flags_finish */
-  0                                     /* letter */
+  0                                     /* todo_flags_finish */
+ }
 };