/* 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, 2008
Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
/* This is the final pass of the compiler.
It looks at the rtl code for a function and outputs assembler code.
#include "timevar.h"
#include "cgraph.h"
#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;
-
-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.
CC_STATUS cc_prev_status;
#endif
-/* Indexed by hardware reg number, is 1 if that register is ever
- used in the current function.
-
- In life_analysis, or in stupid_life_analysis, this is set
- up to record the hard regs used explicitly. Reload adds
- in the hard regs used for holding pseudo regs. Final uses
- it to generate the code in the function prologue and epilogue
- to save and restore registers as needed. */
-
-char regs_ever_live[FIRST_PSEUDO_REGISTER];
-
-/* Like regs_ever_live, but 1 if a reg is set or clobbered from an asm.
- Unlike regs_ever_live, elements of this array corresponding to
- eliminable regs like the frame pointer are set if an asm sets them. */
-
-char regs_asm_clobbered[FIRST_PSEUDO_REGISTER];
-
-/* 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;
static void profile_function (FILE *);
static void profile_after_prologue (FILE *);
static bool notice_source_line (rtx);
-static rtx walk_alter_subreg (rtx *);
+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 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;
}
/* 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,
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;
/* Compute branch alignments based on frequency information in the
CFG. */
-static void
+static unsigned int
compute_alignments (void)
{
int log, max_skip, max_log;
basic_block bb;
+ int freq_max = 0;
+ int freq_threshold = 0;
if (label_align)
{
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;
+
+ 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
/* 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 ())
{
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. */
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;
#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;
static int
asm_insn_count (rtx body)
{
- const char *template;
+ const char *templ;
int count = 1;
if (GET_CODE (body) == ASM_INPUT)
- template = XSTR (body, 0);
+ templ = XSTR (body, 0);
else
- template = decode_asm_operands (body, NULL, NULL, NULL, NULL);
+ templ = decode_asm_operands (body, NULL, NULL, NULL, NULL, NULL);
- for (; *template; template++)
- if (IS_ASM_LOGICAL_LINE_SEPARATOR (*template) || *template == '\n')
+ if (!*templ)
+ return 0;
+
+ for (; *templ; templ++)
+ if (IS_ASM_LOGICAL_LINE_SEPARATOR (*templ, templ)
+ || *templ == '\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 */
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
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
}
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. */
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 ())
}
}
+/* 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.
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:
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;
-
+
case NOTE_INSN_BASIC_BLOCK:
-
#ifdef TARGET_UNWIND_INFO
targetm.asm_out.unwind_emit (asm_out_file, insn);
#endif
/* 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:
(*debug_hooks->var_location) (insn);
break;
- case 0:
- break;
-
default:
- gcc_assert (NOTE_LINE_NUMBER (insn) > 0);
+ gcc_unreachable ();
break;
}
break;
}
#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))
{
rtx body = PATTERN (insn);
int insn_code_number;
- const char *template;
+ const char *templ;
+#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. */
if (string[0])
{
+ expanded_location loc;
+
if (! app_on)
{
fputs (ASM_APP_ON, file);
app_on = 1;
}
+ 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);
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;
}
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;
/* 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);
- /* Inhibit dieing on what would otherwise be compiler bugs. */
+ string = decode_asm_operands (body, ops, NULL, NULL, NULL, &loc);
+ /* 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 (expanded.file && expanded.line)
+ fprintf (asm_out_file, "%s %i \"%s\" 1\n",
+ ASM_COMMENT_START, expanded.line, expanded.file);
output_asm_insn (string, ops);
+#if HAVE_AS_LINE_ZERO
+ if (expanded.file && expanded.line)
+ fprintf (asm_out_file, "%s 0 \"\" 2\n", ASM_COMMENT_START);
+#endif
}
this_is_asm_operands = 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). */
#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
#endif
/* 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 (template == 0)
+ if (templ == 0)
{
rtx prev;
/* 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 (new == insn && PATTERN (new) == body)
+ if (new_rtx == insn && PATTERN (new_rtx) == body)
fatal_insn ("could not split insn", insn);
#ifdef HAVE_ATTR_length
gcc_unreachable ();
#endif
- return new;
+ return new_rtx;
}
#ifdef TARGET_UNWIND_INFO
targetm.asm_out.unwind_emit (asm_out_file, insn);
#endif
+ 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_asm_insn (template, recog_data.operand);
+ output_asm_insn (templ, recog_data.operand);
/* If necessary, report the effect that the instruction has on
the unwind info. We've already done this for delay slots
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
cleanup_subreg_operands (rtx insn)
{
int i;
+ bool changed = false;
extract_insn_cached (insn);
for (i = 0; i < recog_data.n_operands; i++)
{
matches the else clause. Instead we test the underlying
expression directly. */
if (GET_CODE (*recog_data.operand_loc[i]) == SUBREG)
- recog_data.operand[i] = alter_subreg (recog_data.operand_loc[i]);
+ {
+ recog_data.operand[i] = alter_subreg (recog_data.operand_loc[i]);
+ changed = true;
+ }
else if (GET_CODE (recog_data.operand[i]) == PLUS
|| GET_CODE (recog_data.operand[i]) == MULT
|| MEM_P (recog_data.operand[i]))
- recog_data.operand[i] = walk_alter_subreg (recog_data.operand_loc[i]);
+ recog_data.operand[i] = walk_alter_subreg (recog_data.operand_loc[i], &changed);
}
for (i = 0; i < recog_data.n_dups; i++)
{
if (GET_CODE (*recog_data.dup_loc[i]) == SUBREG)
- *recog_data.dup_loc[i] = alter_subreg (recog_data.dup_loc[i]);
+ {
+ *recog_data.dup_loc[i] = alter_subreg (recog_data.dup_loc[i]);
+ changed = true;
+ }
else if (GET_CODE (*recog_data.dup_loc[i]) == PLUS
|| GET_CODE (*recog_data.dup_loc[i]) == MULT
|| MEM_P (*recog_data.dup_loc[i]))
- *recog_data.dup_loc[i] = walk_alter_subreg (recog_data.dup_loc[i]);
+ *recog_data.dup_loc[i] = walk_alter_subreg (recog_data.dup_loc[i], &changed);
}
+ if (changed)
+ df_insn_rescan (insn);
}
/* If X is a SUBREG, replace it with a REG or a MEM,
}
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));
- 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. */
- 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);
}
}
/* Do alter_subreg on all the SUBREGs contained in X. */
static rtx
-walk_alter_subreg (rtx *xp)
+walk_alter_subreg (rtx *xp, bool *changed)
{
rtx x = *xp;
switch (GET_CODE (x))
case PLUS:
case MULT:
case AND:
- XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0));
- XEXP (x, 1) = walk_alter_subreg (&XEXP (x, 1));
+ XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0), changed);
+ XEXP (x, 1) = walk_alter_subreg (&XEXP (x, 1), changed);
break;
case MEM:
case ZERO_EXTEND:
- XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0));
+ XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0), changed);
break;
case SUBREG:
+ *changed = true;
return alter_subreg (xp);
default:
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;
/* 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);
- p = template;
+ p = templ;
putc ('\t', asm_out_file);
#ifdef ASM_OUTPUT_OPCODE
int letter = *p++;
unsigned long opnum;
char *endptr;
-
+
opnum = strtoul (p, &endptr, 10);
if (endptr == p)
{
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");
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");
gcc_assert (!x || !REG_P (x) || REGNO (x) < FIRST_PSEUDO_REGISTER);
PRINT_OPERAND (asm_out_file, x, code);
+ 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);
+ }
}
/* Print a memory reference operand for address X
void
output_address (rtx x)
{
- walk_alter_subreg (&x);
+ bool changed = false;
+ walk_alter_subreg (&x, &changed);
PRINT_OPERAND_ADDRESS (asm_out_file, x);
}
\f
/* 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))
{
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));
const char *const permitted_reg_in_leaf_functions = LEAF_REGISTERS;
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if ((regs_ever_live[i] || global_regs[i])
+ if ((df_regs_ever_live_p (i) || global_regs[i])
&& ! 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)))
}
newreg = LEAF_REG_REMAP (newreg);
gcc_assert (newreg >= 0);
- regs_ever_live[REGNO (in_rtx)] = 0;
- regs_ever_live[newreg] = 1;
- REGNO (in_rtx) = newreg;
+ df_set_regs_ever_live (REGNO (in_rtx), false);
+ df_set_regs_ever_live (newreg, true);
+ SET_REGNO (in_rtx, newreg);
in_rtx->used = 1;
}
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
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;
}
\f
/* Turn the RTL into assembly. */
-static void
+static unsigned int
rest_of_handle_final (void)
{
rtx x;
#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;
+ /* Free up reg info memory. */
+ free_reg_info ();
+
if (! quiet_flag)
fflush (asm_out_file);
- /* Release all memory allocated by flow. */
- free_basic_block_vars ();
-
/* Write DBX symbols if requested. */
/* Note that for those inline functions where we don't initially
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 =
+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 */
+ }
};
-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 =
+
+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 */
+ }
};
-static void
+static unsigned int
rest_of_clean_state (void)
{
rtx insn, next;
reload_completed = 0;
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. */
/* Show no temporary slots allocated. */
init_temp_slots ();
- free_basic_block_vars ();
free_bb_for_insn ();
-
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;
}
/* 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 =
+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 */
+ }
};