/* 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.
#include "coverage.h"
#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
/* 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
/* 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;
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;
{
int log, max_skip, max_log;
basic_block bb;
+ int freq_max = 0;
+ int freq_threshold = 0;
if (label_align)
{
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);
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;
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
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;
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;
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 */
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
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;
}
#endif
\f
+/* ??? This is probably the wrong place for these. */
+/* Structure recording the mapping from source file and directory
+ names at compile time to those to be embedded in debug
+ information. */
+typedef struct debug_prefix_map
+{
+ const char *old_prefix;
+ const char *new_prefix;
+ size_t old_len;
+ size_t new_len;
+ struct debug_prefix_map *next;
+} debug_prefix_map;
+
+/* Linked list of such structures. */
+debug_prefix_map *debug_prefix_maps;
+
+
+/* Record a debug file prefix mapping. ARG is the argument to
+ -fdebug-prefix-map and must be of the form OLD=NEW. */
+
+void
+add_debug_prefix_map (const char *arg)
+{
+ debug_prefix_map *map;
+ const char *p;
+
+ p = strchr (arg, '=');
+ if (!p)
+ {
+ error ("invalid argument %qs to -fdebug-prefix-map", arg);
+ return;
+ }
+ map = XNEW (debug_prefix_map);
+ map->old_prefix = ggc_alloc_string (arg, p - arg);
+ map->old_len = p - arg;
+ p++;
+ map->new_prefix = ggc_strdup (p);
+ map->new_len = strlen (p);
+ map->next = debug_prefix_maps;
+ debug_prefix_maps = map;
+}
+
+/* Perform user-specified mapping of debug filename prefixes. Return
+ the new name corresponding to FILENAME. */
+
+const char *
+remap_debug_filename (const char *filename)
+{
+ debug_prefix_map *map;
+ char *s;
+ const char *name;
+ size_t name_len;
+
+ for (map = debug_prefix_maps; map; map = map->next)
+ if (strncmp (filename, map->old_prefix, map->old_len) == 0)
+ break;
+ if (!map)
+ return filename;
+ name = filename + map->old_len;
+ name_len = strlen (name) + 1;
+ s = (char *) alloca (name_len + map->new_len);
+ memcpy (s, map->new_prefix, map->new_len);
+ memcpy (s + map->new_len, name, name_len);
+ return ggc_strdup (s);
+}
+\f
/* 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
/* 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 (crtl->profile)
profile_function (file);
#endif /* PROFILE_BEFORE_PROLOGUE */
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 ());
profile_after_prologue (FILE *file ATTRIBUTE_UNUSED)
{
#ifndef PROFILE_BEFORE_PROLOGUE
- if (current_function_profile)
+ if (crtl->profile)
profile_function (file);
#endif /* not PROFILE_BEFORE_PROLOGUE */
}
# define NO_PROFILE_COUNTERS 0
#endif
#if defined(ASM_OUTPUT_REG_PUSH)
- int sval = current_function_returns_struct;
+ int sval = cfun->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;
#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)
#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
}
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;
/* 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:
(*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:
}
#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))
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);
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);
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
}
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). */
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
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);
}
}
/* 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)
- 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));
}
output_operand_lossage ("floating constant misused");
break;
+ case CONST_FIXED:
+ 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). */
if (GET_CODE (XEXP (x, 0)) == CONST_INT)
case ZERO_EXTEND:
case SIGN_EXTEND:
case SUBREG:
+ case TRUNCATE:
output_addr_const (file, XEXP (x, 0));
break;
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))
&& ! 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))
{
&& ! 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)])
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)))
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 */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_ggc_collect, /* todo_flags_finish */
- 0 /* letter */
+ TODO_ggc_collect /* todo_flags_finish */
+ }
};
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 */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_dump_func, /* todo_flags_finish */
- 0 /* letter */
+ TODO_dump_func /* todo_flags_finish */
+ }
};
if (targetm.binds_local_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;
}
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 */
0, /* properties_provided */
PROP_rtl, /* properties_destroyed */
0, /* todo_flags_start */
- 0, /* todo_flags_finish */
- 0 /* letter */
+ 0 /* todo_flags_finish */
+ }
};