/* 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 Free Software Foundation, Inc.
+ 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ Free Software Foundation, Inc.
This file is part of GCC.
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, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
/* This is the final pass of the compiler.
It looks at the rtl code for a function and outputs assembler code.
#include "debug.h"
#include "expr.h"
#include "cfglayout.h"
+#include "tree-pass.h"
+#include "timevar.h"
+#include "cgraph.h"
+#include "coverage.h"
#ifdef XCOFF_DEBUGGING_INFO
#include "xcoffout.h" /* Needed for external data
#include "dbxout.h"
#endif
+#ifdef SDB_DEBUGGING_INFO
+#include "sdbout.h"
+#endif
+
/* If we aren't using cc0, CC_STATUS_INIT shouldn't exist. So define a
null default for it to save conditionalization later. */
#ifndef CC_STATUS_INIT
#define JUMP_TABLES_IN_TEXT_SECTION 0
#endif
-#if defined(READONLY_DATA_SECTION) || defined(READONLY_DATA_SECTION_ASM_OP)
-#define HAVE_READONLY_DATA_SECTION 1
-#else
-#define HAVE_READONLY_DATA_SECTION 0
-#endif
-
/* Bitflags used by final_scan_insn. */
#define SEEN_BB 1
#define SEEN_NOTE 2
/* Filename of last NOTE. */
static const char *last_filename;
+/* Whether to force emission of a line note before the next insn. */
+static bool force_source_line = false;
+
extern int length_unit_log; /* This is defined in insn-attrtab.c. */
/* Nonzero while outputting an `asm' with operands.
- This means that inconsistencies are the user's fault, so don't abort.
+ This means that inconsistencies are the user's fault, so don't die.
The precise value is the insn being output, to pass to error_for_asm. */
rtx this_is_asm_operands;
}
/* Obtain the current length of an insn. If branch shortening has been done,
- get its actual length. Otherwise, get its maximum length. */
-
-int
-get_attr_length (rtx insn ATTRIBUTE_UNUSED)
+ get its actual length. Otherwise, use FALLBACK_FN to calcualte the
+ length. */
+static inline int
+get_attr_length_1 (rtx insn ATTRIBUTE_UNUSED,
+ int (*fallback_fn) (rtx) ATTRIBUTE_UNUSED)
{
#ifdef HAVE_ATTR_length
rtx body;
return 0;
case CALL_INSN:
- length = insn_default_length (insn);
+ length = fallback_fn (insn);
break;
case JUMP_INSN:
ADDR_VEC_ALIGN. */
}
else
- length = insn_default_length (insn);
+ length = fallback_fn (insn);
break;
case INSN:
return 0;
else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0)
- length = asm_insn_count (body) * insn_default_length (insn);
+ 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));
else
- length = insn_default_length (insn);
+ length = fallback_fn (insn);
break;
default:
return length;
#else /* not HAVE_ATTR_length */
return 0;
+#define insn_default_length 0
+#define insn_min_length 0
#endif /* not HAVE_ATTR_length */
}
+
+/* Obtain the current length of an insn. If branch shortening has been done,
+ get its actual length. Otherwise, get its maximum length. */
+int
+get_attr_length (rtx insn)
+{
+ return get_attr_length_1 (insn, insn_default_length);
+}
+
+/* Obtain the current length of an insn. If branch shortening has been done,
+ get its actual length. Otherwise, get its minimum length. */
+int
+get_attr_min_length (rtx insn)
+{
+ return get_attr_length_1 (insn, insn_min_length);
+}
\f
/* Code to handle alignment inside shorten_branches. */
rtx label = BB_HEAD (bb);
int fallthru_frequency = 0, branch_frequency = 0, has_fallthru = 0;
edge e;
+ edge_iterator ei;
if (!LABEL_P (label)
|| probably_never_executed_bb_p (bb))
max_log = LABEL_ALIGN (label);
max_skip = LABEL_ALIGN_MAX_SKIP;
- for (e = bb->pred; e; e = e->pred_next)
+ FOR_EACH_EDGE (e, ei, bb->preds)
{
if (e->flags & EDGE_FALLTHRU)
has_fallthru = 1, fallthru_frequency += EDGE_FREQUENCY (e);
LABEL_TO_MAX_SKIP (label) = max_skip;
}
}
+
+struct tree_opt_pass pass_compute_alignments =
+{
+ NULL, /* name */
+ NULL, /* gate */
+ compute_alignments, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ 0, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
+ 0 /* letter */
+};
+
\f
/* Make a pass over all insns and compute their actual lengths by shortening
any branches of variable length if possible. */
/* Compute maximum UID and allocate label_align / uid_shuid. */
max_uid = get_max_uid ();
- /* Free uid_shuid before reallocating it. */
+ /* Free uid_shuid before reallocating it. */
free (uid_shuid);
uid_shuid = xmalloc (max_uid * sizeof *uid_shuid);
label_align = xrealloc (label_align,
n_labels * sizeof (struct label_alignment));
- /* Range of labels grows monotonically in the function. Abort here
+ /* Range of labels grows monotonically in the function. Failing here
means that the initialization of array got lost. */
- if (n_old_labels > n_labels)
- abort ();
+ gcc_assert (n_old_labels <= n_labels);
memset (label_align + n_old_labels, 0,
(n_labels - n_old_labels) * sizeof (struct label_alignment));
max_log = log;
max_skip = LABEL_ALIGN_MAX_SKIP;
}
- next = NEXT_INSN (insn);
+ next = next_nonnote_insn (insn);
/* ADDR_VECs only take room if read-only data goes into the text
section. */
- if (JUMP_TABLES_IN_TEXT_SECTION || !HAVE_READONLY_DATA_SECTION)
+ if (JUMP_TABLES_IN_TEXT_SECTION
+ || readonly_data_section == text_section)
if (next && JUMP_P (next))
{
rtx nextbody = PATTERN (next);
continue;
pat = PATTERN (insn);
len = XVECLEN (pat, 1);
- if (len <= 0)
- abort ();
+ gcc_assert (len > 0);
min_align = MAX_CODE_ALIGN;
for (min = max_shuid, max = min_shuid, i = len - 1; i >= 0; i--)
{
if (min_align > LABEL_TO_ALIGNMENT (lab))
min_align = LABEL_TO_ALIGNMENT (lab);
}
- XEXP (pat, 2) = gen_rtx_LABEL_REF (VOIDmode, min_lab);
- XEXP (pat, 3) = gen_rtx_LABEL_REF (VOIDmode, max_lab);
+ XEXP (pat, 2) = gen_rtx_LABEL_REF (Pmode, min_lab);
+ XEXP (pat, 3) = gen_rtx_LABEL_REF (Pmode, max_lab);
insn_shuid = INSN_SHUID (insn);
rel = INSN_SHUID (XEXP (XEXP (pat, 0), 0));
+ memset (&flags, 0, sizeof (flags));
flags.min_align = min_align;
flags.base_after_vec = rel > insn_shuid;
flags.min_after_vec = min > insn_shuid;
{
/* This only takes room if read-only data goes into the text
section. */
- if (JUMP_TABLES_IN_TEXT_SECTION || !HAVE_READONLY_DATA_SECTION)
+ if (JUMP_TABLES_IN_TEXT_SECTION
+ || readonly_data_section == text_section)
insn_lengths[uid] = (XVECLEN (body,
GET_CODE (body) == ADDR_DIFF_VEC)
* GET_MODE_SIZE (GET_MODE (body)));
PUT_MODE (body, CASE_VECTOR_SHORTEN_MODE (min_addr - rel_addr,
max_addr - rel_addr,
body));
- if (JUMP_TABLES_IN_TEXT_SECTION || !HAVE_READONLY_DATA_SECTION)
+ if (JUMP_TABLES_IN_TEXT_SECTION
+ || readonly_data_section == text_section)
{
insn_lengths[uid]
= (XVECLEN (body, 1) * GET_MODE_SIZE (GET_MODE (body)));
#if defined (DWARF2_UNWIND_INFO) && defined (HAVE_prologue)
if (dwarf2out_do_frame ())
- dwarf2out_frame_debug (NULL_RTX);
+ dwarf2out_frame_debug (NULL_RTX, false);
#endif
/* If debugging, assign block numbers to all of the blocks in this
if (! NO_PROFILE_COUNTERS)
{
int align = MIN (BIGGEST_ALIGNMENT, LONG_TYPE_SIZE);
- data_section ();
+ switch_to_section (data_section);
ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
targetm.asm_out.internal_label (file, "LP", current_function_funcdef_no);
assemble_integer (const0_rtx, LONG_TYPE_SIZE / BITS_PER_UNIT, align, 1);
}
- function_section (current_function_decl);
+ switch_to_section (current_function_section ());
#if defined(ASM_OUTPUT_REG_PUSH)
if (sval && svrtx != NULL_RTX && REG_P (svrtx))
}
\f
/* Output assembler code for some insns: all or part of a function.
- For description of args, see `final_start_function', above.
-
- PRESCAN is 1 if we are not really outputting,
- just scanning as if we were outputting.
- Prescanning deletes and rearranges insns just like ordinary output.
- PRESCAN is -2 if we are outputting after having prescanned.
- In this case, don't try to delete or rearrange insns
- because that has already been done.
- Prescanning is done only on certain machines. */
+ For description of args, see `final_start_function', above. */
void
-final (rtx first, FILE *file, int optimize, int prescan)
+final (rtx first, FILE *file, int optimize)
{
rtx insn;
int max_uid = 0;
{
/* This can be triggered by bugs elsewhere in the compiler if
new insns are created after init_insn_lengths is called. */
- if (NOTE_P (insn))
- insn_current_address = -1;
- else
- abort ();
+ gcc_assert (NOTE_P (insn));
+ insn_current_address = -1;
}
else
insn_current_address = INSN_ADDRESSES (INSN_UID (insn));
#endif /* HAVE_ATTR_length */
- insn = final_scan_insn (insn, file, optimize, prescan, 0, &seen);
+ insn = final_scan_insn (insn, file, optimize, 0, &seen);
}
}
\f
case INSN_OUTPUT_FORMAT_MULTI:
return insn_data[code].output.multi[which_alternative];
case INSN_OUTPUT_FORMAT_FUNCTION:
- if (insn == NULL)
- abort ();
+ gcc_assert (insn);
return (*insn_data[code].output.function) (recog_data.operand, insn);
default:
- abort ();
+ gcc_unreachable ();
}
}
case LABEL_NORMAL:
default:
- abort ();
- }
-}
-
-/* Return boolean indicating if there is a NOTE_INSN_UNLIKELY_EXECUTED_CODE
- note in the instruction chain (going forward) between the current
- instruction, and the next 'executable' instruction. */
-
-bool
-scan_ahead_for_unlikely_executed_note (rtx insn)
-{
- rtx temp;
- int bb_note_count = 0;
-
- for (temp = insn; temp; temp = NEXT_INSN (temp))
- {
- if (NOTE_P (temp)
- && NOTE_LINE_NUMBER (temp) == NOTE_INSN_UNLIKELY_EXECUTED_CODE)
- return true;
- if (NOTE_P (temp)
- && NOTE_LINE_NUMBER (temp) == NOTE_INSN_BASIC_BLOCK)
- {
- bb_note_count++;
- if (bb_note_count > 1)
- return false;
- }
- if (INSN_P (temp))
- return false;
+ gcc_unreachable ();
}
-
- return false;
}
/* The final scan for one insn, INSN.
rtx
final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
- int prescan, int nopeepholes ATTRIBUTE_UNUSED,
- int *seen)
+ int nopeepholes ATTRIBUTE_UNUSED, int *seen)
{
#ifdef HAVE_cc0
rtx set;
#endif
+ rtx next;
insn_counter++;
switch (GET_CODE (insn))
{
case NOTE:
- if (prescan > 0)
- break;
-
switch (NOTE_LINE_NUMBER (insn))
{
case NOTE_INSN_DELETED:
case NOTE_INSN_EXPECTED_VALUE:
break;
- case NOTE_INSN_UNLIKELY_EXECUTED_CODE:
+ case NOTE_INSN_SWITCH_TEXT_SECTIONS:
/* The presence of this note indicates that this basic block
belongs in the "cold" section of the .o file. If we are
not already writing to the cold section we need to change
to it. */
-
- unlikely_text_section ();
+
+ if (last_text_section == text_section)
+ {
+ (*debug_hooks->switch_text_section) ();
+ switch_to_section (unlikely_text_section ());
+ }
+ else
+ {
+ (*debug_hooks->switch_text_section) ();
+ switch_to_section (text_section);
+ }
break;
case NOTE_INSN_BASIC_BLOCK:
- /* If we are performing the optimization that partitions
- basic blocks into hot & cold sections of the .o file,
- then at the start of each new basic block, before
- beginning to write code for the basic block, we need to
- check to see whether the basic block belongs in the hot
- or cold section of the .o file, and change the section we
- are writing to appropriately. */
-
- if (flag_reorder_blocks_and_partition
- && !scan_ahead_for_unlikely_executed_note (insn))
- function_section (current_function_decl);
-
#ifdef TARGET_UNWIND_INFO
targetm.asm_out.unwind_emit (asm_out_file, insn);
#endif
if ((*seen & (SEEN_EMITTED | SEEN_BB)) == SEEN_BB)
{
*seen |= SEEN_EMITTED;
- last_filename = NULL;
+ force_source_line = true;
}
else
*seen |= SEEN_BB;
if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE)
{
*seen |= SEEN_EMITTED;
- last_filename = NULL;
+ force_source_line = true;
}
else
*seen |= SEEN_NOTE;
if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE)
{
*seen |= SEEN_EMITTED;
- last_filename = NULL;
+ force_source_line = true;
}
else
*seen |= SEEN_NOTE;
/* End of a symbol-block. */
--block_depth;
- if (block_depth < 0)
- abort ();
+ gcc_assert (block_depth >= 0);
(*debug_hooks->end_block) (high_block_linenum, n);
}
break;
default:
- if (NOTE_LINE_NUMBER (insn) <= 0)
- abort ();
+ gcc_assert (NOTE_LINE_NUMBER (insn) > 0);
break;
}
break;
case BARRIER:
#if defined (DWARF2_UNWIND_INFO)
if (dwarf2out_do_frame ())
- dwarf2out_frame_debug (insn);
+ dwarf2out_frame_debug (insn, false);
#endif
break;
}
}
#endif
- if (prescan > 0)
- break;
if (LABEL_NAME (insn))
(*debug_hooks->label) (insn);
- /* If we are doing the optimization that partitions hot & cold
- basic blocks into separate sections of the .o file, we need
- to ensure the jump table ends up in the correct section... */
-
- if (flag_reorder_blocks_and_partition
- && targetm.have_named_sections)
- {
- rtx tmp_table, tmp_label;
- if (LABEL_P (insn)
- && tablejump_p (NEXT_INSN (insn), &tmp_label, &tmp_table))
- {
- /* Do nothing; Do NOT change the current section. */
- }
- else if (scan_ahead_for_unlikely_executed_note (insn))
- unlikely_text_section ();
- else if (in_unlikely_text_section ())
- function_section (current_function_decl);
- }
-
if (app_on)
{
fputs (ASM_APP_OFF, file);
app_on = 0;
}
- if (NEXT_INSN (insn) != 0
- && JUMP_P (NEXT_INSN (insn)))
+
+ next = next_nonnote_insn (insn);
+ if (next != 0 && JUMP_P (next))
{
- rtx nextbody = PATTERN (NEXT_INSN (insn));
+ rtx nextbody = PATTERN (next);
/* If this label is followed by a jump-table,
make sure we put the label in the read-only section. Also
{
int log_align;
- targetm.asm_out.function_rodata_section (current_function_decl);
+ switch_to_section (targetm.asm_out.function_rodata_section
+ (current_function_decl));
#ifdef ADDR_VEC_ALIGN
- log_align = ADDR_VEC_ALIGN (NEXT_INSN (insn));
+ log_align = ADDR_VEC_ALIGN (next);
#else
log_align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
#endif
ASM_OUTPUT_ALIGN (file, log_align);
}
else
- function_section (current_function_decl);
+ switch_to_section (current_function_section ());
#ifdef ASM_OUTPUT_CASE_LABEL
ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn),
- NEXT_INSN (insn));
+ next);
#else
targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (insn));
#endif
int vlen, idx;
#endif
- if (prescan > 0)
- break;
+ if (! JUMP_TABLES_IN_TEXT_SECTION)
+ switch_to_section (targetm.asm_out.function_rodata_section
+ (current_function_decl));
+ else
+ switch_to_section (current_function_section ());
if (app_on)
{
#ifdef ASM_OUTPUT_ADDR_VEC
ASM_OUTPUT_ADDR_VEC (PREV_INSN (insn), body);
#else
- abort ();
+ gcc_unreachable ();
#endif
}
else
#ifdef ASM_OUTPUT_ADDR_DIFF_VEC
ASM_OUTPUT_ADDR_DIFF_VEC (PREV_INSN (insn), body);
#else
- abort ();
+ gcc_unreachable ();
#endif
}
#else
ASM_OUTPUT_ADDR_VEC_ELT
(file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0)));
#else
- abort ();
+ gcc_unreachable ();
#endif
}
else
CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)),
CODE_LABEL_NUMBER (XEXP (XEXP (body, 0), 0)));
#else
- abort ();
+ gcc_unreachable ();
#endif
}
}
#endif
#endif
- function_section (current_function_decl);
+ switch_to_section (current_function_section ());
break;
}
/* There's no telling what that did to the condition codes. */
CC_STATUS_INIT;
- if (prescan > 0)
- break;
if (string[0])
{
/* There's no telling what that did to the condition codes. */
CC_STATUS_INIT;
- if (prescan > 0)
- break;
/* Get out the operand values. */
string = decode_asm_operands (body, ops, NULL, NULL, NULL);
- /* Inhibit aborts on what would otherwise be compiler bugs. */
+ /* Inhibit dieing on what would otherwise be compiler bugs. */
insn_noperands = noperands;
this_is_asm_operands = insn;
break;
}
- if (prescan <= 0 && app_on)
+ if (app_on)
{
fputs (ASM_APP_OFF, file);
app_on = 0;
{
/* A delayed-branch sequence */
int i;
- rtx next;
- if (prescan > 0)
- break;
final_sequence = body;
/* Record the delay slots' frame information before the branch.
#if defined (DWARF2_UNWIND_INFO)
if (dwarf2out_do_frame ())
for (i = 1; i < XVECLEN (body, 0); i++)
- dwarf2out_frame_debug (XVECEXP (body, 0, i));
+ dwarf2out_frame_debug (XVECEXP (body, 0, i), false);
#endif
/* The first insn in this SEQUENCE might be a JUMP_INSN that will
thought unnecessary. If that happens, cancel this sequence
and cause that insn to be restored. */
- next = final_scan_insn (XVECEXP (body, 0, 0), file, 0, prescan, 1, seen);
+ next = final_scan_insn (XVECEXP (body, 0, 0), file, 0, 1, seen);
if (next != XVECEXP (body, 0, 1))
{
final_sequence = 0;
/* We loop in case any instruction in a delay slot gets
split. */
do
- insn = final_scan_insn (insn, file, 0, prescan, 1, seen);
+ insn = final_scan_insn (insn, file, 0, 1, seen);
while (insn != next);
}
#ifdef DBR_OUTPUT_SEQEND
}
#endif
-#ifndef STACK_REGS
- /* Don't bother outputting obvious no-ops, even without -O.
- This optimization is fast and doesn't interfere with debugging.
- Don't do this if the insn is in a delay slot, since this
- will cause an improper number of delay insns to be written. */
- if (final_sequence == 0
- && prescan >= 0
- && NONJUMP_INSN_P (insn) && GET_CODE (body) == SET
- && REG_P (SET_SRC (body))
- && REG_P (SET_DEST (body))
- && REGNO (SET_SRC (body)) == REGNO (SET_DEST (body)))
- break;
-#endif
-
#ifdef HAVE_cc0
/* If this is a conditional branch, maybe modify it
if the cc's are in a nonstandard state
&& SET_DEST (body) == pc_rtx
&& GET_CODE (SET_SRC (body)) == IF_THEN_ELSE
&& COMPARISON_P (XEXP (SET_SRC (body), 0))
- && XEXP (XEXP (SET_SRC (body), 0), 0) == cc0_rtx
- /* This is done during prescan; it is not done again
- in final scan when prescan has been done. */
- && prescan >= 0)
+ && XEXP (XEXP (SET_SRC (body), 0), 0) == cc0_rtx)
{
/* This function may alter the contents of its argument
and clear some of the cc_status.flags bits.
for (note = NEXT_INSN (insn); note != next;
note = NEXT_INSN (note))
- final_scan_insn (note, file, optimize, prescan, nopeepholes, seen);
+ final_scan_insn (note, file, optimize, nopeepholes, seen);
- /* In case this is prescan, put the notes
- in proper position for later rescan. */
+ /* Put the notes in the proper position for a later
+ rescan. For example, the SH target can do this
+ when generating a far jump in a delayed branch
+ sequence. */
note = NEXT_INSN (insn);
PREV_INSN (note) = prev;
NEXT_INSN (prev) = note;
#if defined (DWARF2_UNWIND_INFO)
if (CALL_P (insn) && dwarf2out_do_frame ())
- dwarf2out_frame_debug (insn);
+ dwarf2out_frame_debug (insn, false);
#endif
/* Find the proper template for this insn. */
{
rtx prev;
- if (prev_nonnote_insn (insn) != last_ignored_compare)
- abort ();
+ gcc_assert (prev_nonnote_insn (insn) == last_ignored_compare);
/* We have already processed the notes between the setter and
the user. Make sure we don't process them again, this is
/* This instruction should have been split in shorten_branches,
to ensure that we would have valid length info for the
splitees. */
- abort ();
+ gcc_unreachable ();
#endif
return new;
}
- if (prescan > 0)
- break;
-
#ifdef TARGET_UNWIND_INFO
/* ??? This will put the directives in the wrong place if
get_insn_template outputs assembly directly. However calling it
the unwind info. We've already done this for delay slots
and call instructions. */
#if defined (DWARF2_UNWIND_INFO)
- if (NONJUMP_INSN_P (insn)
+ if (final_sequence == 0
#if !defined (HAVE_prologue)
&& !ACCUMULATE_OUTGOING_ARGS
#endif
- && final_sequence == 0
&& dwarf2out_do_frame ())
- dwarf2out_frame_debug (insn);
+ dwarf2out_frame_debug (insn, true);
#endif
current_output_insn = debug_insn = 0;
return NEXT_INSN (insn);
}
\f
-/* Output debugging info to the assembler file FILE
- based on the NOTE-insn INSN, assumed to be a line number. */
+/* Return whether a source line note needs to be emitted before INSN. */
static bool
notice_source_line (rtx insn)
const char *filename = insn_file (insn);
int linenum = insn_line (insn);
- if (filename && (filename != last_filename || last_linenum != linenum))
+ if (filename
+ && (force_source_line
+ || filename != last_filename
+ || last_linenum != linenum))
{
+ force_source_line = false;
last_filename = filename;
last_linenum = linenum;
high_block_linenum = MAX (last_linenum, high_block_linenum);
/* simplify_subreg does not remove subreg from volatile references.
We are required to. */
if (MEM_P (y))
- *xp = adjust_address (y, GET_MODE (x), SUBREG_BYTE (x));
+ {
+ int offset = SUBREG_BYTE (x);
+
+ /* For paradoxical subregs on big-endian machines, SUBREG_BYTE
+ contains 0 instead of the proper offset. See simplify_subreg. */
+ if (offset == 0
+ && GET_MODE_SIZE (GET_MODE (y)) < GET_MODE_SIZE (GET_MODE (x)))
+ {
+ int difference = GET_MODE_SIZE (GET_MODE (y))
+ - GET_MODE_SIZE (GET_MODE (x));
+ if (WORDS_BIG_ENDIAN)
+ offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
+ if (BYTES_BIG_ENDIAN)
+ offset += difference % UNITS_PER_WORD;
+ }
+
+ *xp = adjust_address (y, GET_MODE (x), offset);
+ }
else
{
rtx new = simplify_subreg (GET_MODE (x), y, GET_MODE (y),
if (new != 0)
*xp = new;
- /* Simplify_subreg can't handle some REG cases, but we have to. */
else if (REG_P (y))
{
- unsigned int regno = subreg_hard_regno (x, 1);
+ /* 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));
}
- else
- abort ();
}
return *xp;
switch (GET_CODE (cond))
{
default:
- abort ();
+ gcc_unreachable ();
case NE:
PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? GE : LT);
In an `asm', it's the user's fault; otherwise, the compiler's fault. */
void
-output_operand_lossage (const char *msgid, ...)
+output_operand_lossage (const char *cmsgid, ...)
{
char *fmt_string;
char *new_message;
const char *pfx_str;
va_list ap;
- va_start (ap, msgid);
+ va_start (ap, cmsgid);
- pfx_str = this_is_asm_operands ? _("invalid `asm': ") : "output_operand: ";
- asprintf (&fmt_string, "%s%s", pfx_str, _(msgid));
+ pfx_str = this_is_asm_operands ? _("invalid 'asm': ") : "output_operand: ";
+ asprintf (&fmt_string, "%s%s", pfx_str, _(cmsgid));
vasprintf (&new_message, fmt_string, ap);
if (this_is_asm_operands)
else if (ISALPHA (*p))
{
int letter = *p++;
- c = atoi (p);
-
- if (! ISDIGIT (*p))
- output_operand_lossage ("operand number missing after %%-letter");
- else if (this_is_asm_operands
- && (c < 0 || (unsigned int) c >= insn_noperands))
+ unsigned long opnum;
+ char *endptr;
+
+ opnum = strtoul (p, &endptr, 10);
+
+ if (endptr == p)
+ output_operand_lossage ("operand number missing "
+ "after %%-letter");
+ else if (this_is_asm_operands && opnum >= insn_noperands)
output_operand_lossage ("operand number out of range");
else if (letter == 'l')
- output_asm_label (operands[c]);
+ output_asm_label (operands[opnum]);
else if (letter == 'a')
- output_address (operands[c]);
+ output_address (operands[opnum]);
else if (letter == 'c')
{
- if (CONSTANT_ADDRESS_P (operands[c]))
- output_addr_const (asm_out_file, operands[c]);
+ if (CONSTANT_ADDRESS_P (operands[opnum]))
+ output_addr_const (asm_out_file, operands[opnum]);
else
- output_operand (operands[c], 'c');
+ output_operand (operands[opnum], 'c');
}
else if (letter == 'n')
{
- if (GET_CODE (operands[c]) == CONST_INT)
+ if (GET_CODE (operands[opnum]) == CONST_INT)
fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC,
- - INTVAL (operands[c]));
+ - INTVAL (operands[opnum]));
else
{
putc ('-', asm_out_file);
- output_addr_const (asm_out_file, operands[c]);
+ output_addr_const (asm_out_file, operands[opnum]);
}
}
else
- output_operand (operands[c], letter);
+ output_operand (operands[opnum], letter);
- if (!opoutput[c])
- oporder[ops++] = c;
- opoutput[c] = 1;
+ if (!opoutput[opnum])
+ oporder[ops++] = opnum;
+ opoutput[opnum] = 1;
- while (ISDIGIT (c = *p))
- p++;
+ p = endptr;
+ c = *p;
}
/* % followed by a digit outputs an operand the default way. */
else if (ISDIGIT (*p))
{
- c = atoi (p);
- if (this_is_asm_operands
- && (c < 0 || (unsigned int) c >= insn_noperands))
+ 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");
else
- output_operand (operands[c], 0);
+ output_operand (operands[opnum], 0);
- if (!opoutput[c])
- oporder[ops++] = c;
- opoutput[c] = 1;
+ if (!opoutput[opnum])
+ oporder[ops++] = opnum;
+ opoutput[opnum] = 1;
- while (ISDIGIT (c = *p))
- p++;
+ p = endptr;
+ c = *p;
}
/* % followed by punctuation: output something for that
punctuation character alone, with no operand.
&& NOTE_LINE_NUMBER (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");
+ output_operand_lossage ("'%%l' operand isn't a label");
assemble_name (asm_out_file, buf);
}
if (x && GET_CODE (x) == SUBREG)
x = alter_subreg (&x);
- /* If X is a pseudo-register, abort now rather than writing trash to the
- assembler file. */
-
- if (x && REG_P (x) && REGNO (x) >= FIRST_PSEUDO_REGISTER)
- abort ();
+ /* X must not be a pseudo reg. */
+ gcc_assert (!x || !REG_P (x) || REGNO (x) < FIRST_PSEUDO_REGISTER);
PRINT_OPERAND (asm_out_file, x, code);
}
ASM_FPRINTF_EXTENSIONS (file, argptr, p)
#endif
default:
- abort ();
+ gcc_unreachable ();
}
break;
final_forward_branch_p (rtx insn)
{
int insn_id, label_id;
- if (!uid_shuid)
- abort ();
+
+ gcc_assert (uid_shuid);
insn_id = INSN_SHUID (insn);
label_id = INSN_SHUID (JUMP_LABEL (insn));
/* We've hit some insns that does not have id information available. */
- if (!insn_id || !label_id)
- abort ();
+ gcc_assert (insn_id && label_id);
return insn_id < label_id;
}
return;
}
newreg = LEAF_REG_REMAP (newreg);
- if (newreg < 0)
- abort ();
+ gcc_assert (newreg >= 0);
regs_ever_live[REGNO (in_rtx)] = 0;
regs_ever_live[newreg] = 1;
REGNO (in_rtx) = newreg;
break;
default:
- abort ();
+ gcc_unreachable ();
}
}
#endif
symbol_queue_size = 0;
}
}
+\f
+/* Turn the RTL into assembly. */
+static void
+rest_of_handle_final (void)
+{
+ rtx x;
+ const char *fnname;
+
+ /* Get the function's name, as described by its RTL. This may be
+ different from the DECL_NAME name used in the source file. */
+
+ x = DECL_RTL (current_function_decl);
+ gcc_assert (MEM_P (x));
+ x = XEXP (x, 0);
+ gcc_assert (GET_CODE (x) == SYMBOL_REF);
+ fnname = XSTR (x, 0);
+
+ assemble_start_function (current_function_decl, fnname);
+ final_start_function (get_insns (), asm_out_file, optimize);
+ final (get_insns (), asm_out_file, optimize);
+ final_end_function ();
+
+#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 ();
+#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 ();
+#endif
+
+ user_defined_section_attribute = false;
+
+ 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
+ know for certain that we will be generating an out-of-line copy,
+ the first invocation of this routine (rest_of_compilation) will
+ skip over this code by doing a `goto exit_rest_of_compilation;'.
+ Later on, wrapup_global_declarations will (indirectly) call
+ rest_of_compilation again for those inline functions that need
+ to have out-of-line copies generated. During that call, we
+ *will* be routed past here. */
+
+ timevar_push (TV_SYMOUT);
+ (*debug_hooks->function_decl) (current_function_decl);
+ timevar_pop (TV_SYMOUT);
+}
+
+struct tree_opt_pass pass_final =
+{
+ NULL, /* name */
+ NULL, /* gate */
+ rest_of_handle_final, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_FINAL, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_ggc_collect, /* todo_flags_finish */
+ 0 /* letter */
+};
+
+
+static void
+rest_of_handle_shorten_branches (void)
+{
+ /* Shorten branches. */
+ shorten_branches (get_insns ());
+}
+
+struct tree_opt_pass pass_shorten_branches =
+{
+ "shorten", /* name */
+ NULL, /* gate */
+ rest_of_handle_shorten_branches, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_FINAL, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_dump_func, /* todo_flags_finish */
+ 0 /* letter */
+};
+
+
+static void
+rest_of_clean_state (void)
+{
+ rtx insn, next;
+
+ /* It is very important to decompose the RTL instruction chain here:
+ debug information keeps pointing into CODE_LABEL insns inside the function
+ body. If these remain pointing to the other insns, we end up preserving
+ whole RTL chain and attached detailed debug info in memory. */
+ for (insn = get_insns (); insn; insn = next)
+ {
+ next = NEXT_INSN (insn);
+ NEXT_INSN (insn) = NULL;
+ PREV_INSN (insn) = NULL;
+ }
+
+ /* In case the function was not output,
+ don't leave any temporary anonymous types
+ queued up for sdb output. */
+#ifdef SDB_DEBUGGING_INFO
+ if (write_symbols == SDB_DEBUG)
+ sdbout_types (NULL_TREE);
+#endif
+
+ reload_completed = 0;
+ epilogue_completed = 0;
+ flow2_completed = 0;
+ no_new_pseudos = 0;
+
+ /* Clear out the insn_length contents now that they are no
+ longer valid. */
+ init_insn_lengths ();
+
+ /* 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;
+ cgraph_rtl_info (current_function_decl)->preferred_incoming_stack_boundary
+ = pref;
+ }
+
+ /* Make sure volatile mem refs aren't considered valid operands for
+ arithmetic insns. We must call this here if this is a nested inline
+ function, since the above code leaves us in the init_recog state,
+ and the function context push/pop code does not save/restore volatile_ok.
+
+ ??? Maybe it isn't necessary for expand_start_function to call this
+ anymore if we do it here? */
+
+ init_recog_no_volatile ();
+
+ /* We're done with this function. Free up memory if we can. */
+ free_after_parsing (cfun);
+ free_after_compilation (cfun);
+}
+
+struct tree_opt_pass pass_clean_state =
+{
+ NULL, /* name */
+ NULL, /* gate */
+ rest_of_clean_state, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_FINAL, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ PROP_rtl, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
+ 0 /* letter */
+};
+