/* 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
+ 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;
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 *);
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;
{
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
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. */
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);
+
+ if (!*templ)
+ return 0;
- for (; *template; template++)
- if (IS_ASM_LOGICAL_LINE_SEPARATOR (*template) || *template == '\n')
+ 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 */
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. */
}
}
+/* 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:
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;
/* 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. */
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). */
#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
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))
{
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;
}
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;
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 */
+ }
};
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 */
+ }
};
reload_completed = 0;
epilogue_completed = 0;
- flow2_completed = 0;
- no_new_pseudos = 0;
#ifdef STACK_REGS
regstack_completed = 0;
#endif
/* 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;
}
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 */
+ }
};