/* 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, 2006, 2007
+ 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"
+#include "vecprim.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;
-extern int length_unit_log; /* This is defined in insn-attrtab.c. */
+/* Whether to force emission of a line note before the next insn. */
+static bool force_source_line = false;
+
+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 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;
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, get its maximum length. */
-
-int
-get_attr_length (rtx insn ATTRIBUTE_UNUSED)
+ get its actual length. Otherwise, use FALLBACK_FN to calculate 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. */
seq = NEXT_INSN (PREV_INSN (branch));
seq_uid = INSN_UID (seq);
- if (GET_CODE (branch) != JUMP_INSN)
+ if (!JUMP_P (branch))
/* This can happen for example on the PA; the objective is to know the
offset to address something in front of the start of the function.
Thus, we can treat it like a backward branch.
}
#endif /* HAVE_ATTR_length */
\f
-void
+/* Compute branch alignments based on frequency information in the
+ CFG. */
+
+static unsigned int
compute_alignments (void)
{
int log, max_skip, max_log;
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;
FOR_EACH_BB (bb)
{
rtx label = BB_HEAD (bb);
int fallthru_frequency = 0, branch_frequency = 0, has_fallthru = 0;
edge e;
+ edge_iterator ei;
- if (GET_CODE (label) != CODE_LABEL
+ if (!LABEL_P (label)
|| probably_never_executed_bb_p (bb))
continue;
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_ALIGNMENT (label) = max_log;
LABEL_TO_MAX_SKIP (label) = max_skip;
}
+ return 0;
}
+
+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 ();
- uid_shuid = xmalloc (max_uid * sizeof *uid_shuid);
+ /* Free uid_shuid before reallocating it. */
+ free (uid_shuid);
+
+ uid_shuid = XNEWVEC (int, max_uid);
if (max_labelno != max_label_num ())
{
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));
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 (GET_CODE (insn) == CODE_LABEL)
+ continue;
+
+ if (LABEL_P (insn))
{
rtx next;
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 (next && GET_CODE (next) == JUMP_INSN)
+ if (JUMP_TABLES_IN_TEXT_SECTION
+ || readonly_data_section == text_section)
+ if (next && JUMP_P (next))
{
rtx nextbody = PATTERN (next);
if (GET_CODE (nextbody) == ADDR_VEC
max_log = 0;
max_skip = 0;
}
- else if (GET_CODE (insn) == BARRIER)
+ else if (BARRIER_P (insn))
{
rtx label;
for (label = insn; label && ! INSN_P (label);
label = NEXT_INSN (label))
- if (GET_CODE (label) == CODE_LABEL)
+ if (LABEL_P (label))
{
log = LABEL_ALIGN_AFTER_BARRIER (insn);
if (max_log < log)
#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;
{
int uid = INSN_UID (seq);
int log;
- log = (GET_CODE (seq) == CODE_LABEL ? LABEL_TO_ALIGNMENT (seq) : 0);
+ log = (LABEL_P (seq) ? LABEL_TO_ALIGNMENT (seq) : 0);
uid_align[uid] = align_tab[0];
if (log)
{
int min_align;
addr_diff_vec_flags flags;
- if (GET_CODE (insn) != JUMP_INSN
+ if (!JUMP_P (insn)
|| GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC)
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;
insn_lengths[uid] = 0;
- if (GET_CODE (insn) == CODE_LABEL)
+ if (LABEL_P (insn))
{
int log = LABEL_TO_ALIGNMENT (insn);
if (log)
INSN_ADDRESSES (uid) = insn_current_address + insn_lengths[uid];
- if (GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER
- || GET_CODE (insn) == CODE_LABEL)
+ if (NOTE_P (insn) || BARRIER_P (insn)
+ || LABEL_P (insn))
continue;
if (INSN_DELETED_P (insn))
continue;
{
/* 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)));
uid = INSN_UID (insn);
- if (GET_CODE (insn) == CODE_LABEL)
+ if (LABEL_P (insn))
{
int log = LABEL_TO_ALIGNMENT (insn);
if (log > insn_current_align)
INSN_ADDRESSES (uid) = insn_current_address;
#ifdef CASE_VECTOR_SHORTEN_MODE
- if (optimize && GET_CODE (insn) == JUMP_INSN
+ if (optimize && JUMP_P (insn)
&& GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
{
rtx body = PATTERN (insn);
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 (! (varying_length[uid]))
{
- if (GET_CODE (insn) == INSN
+ if (NONJUMP_INSN_P (insn)
&& GET_CODE (PATTERN (insn)) == SEQUENCE)
{
int i;
continue;
}
- if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE)
+ if (NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE)
{
int i;
if (GET_CODE (body) == ASM_INPUT)
template = XSTR (body, 0);
else
- template = decode_asm_operands (body, NULL, NULL, NULL, NULL);
+ template = decode_asm_operands (body, NULL, NULL, NULL, NULL, NULL);
for (; *template; template++)
if (IS_ASM_LOGICAL_LINE_SEPARATOR (*template) || *template == '\n')
(*debug_hooks->begin_prologue) (last_linenum, last_filename);
-#if defined (DWARF2_UNWIND_INFO) || defined (IA64_UNWIND_INFO)
+#if defined (DWARF2_UNWIND_INFO) || defined (TARGET_UNWIND_INFO)
if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG)
dwarf2out_begin_prologue (0, NULL);
#endif
#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
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
int sval = current_function_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 = current_function_needs_context;
+ int cxt = cfun->static_chain_decl != NULL;
#endif
#endif /* ASM_OUTPUT_REG_PUSH */
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 && GET_CODE (svrtx) == REG)
+ if (sval && svrtx != NULL_RTX && REG_P (svrtx))
ASM_OUTPUT_REG_PUSH (file, REGNO (svrtx));
#endif
#endif
#if defined(ASM_OUTPUT_REG_PUSH)
- if (sval && svrtx != NULL_RTX && GET_CODE (svrtx) == REG)
+ if (sval && svrtx != NULL_RTX && REG_P (svrtx))
ASM_OUTPUT_REG_POP (file, REGNO (svrtx));
#endif
}
}
\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;
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 (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
- {
- if ((RTX_INTEGRATED_P (insn)
- && strcmp (NOTE_SOURCE_FILE (insn), main_input_filename) != 0)
- || (last != 0
- && NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last)
- && NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last)))
- {
- 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. */
#ifdef HAVE_cc0
/* If CC tracking across branches is enabled, record the insn which
jumps to each branch only reached from one place. */
- if (optimize && GET_CODE (insn) == JUMP_INSN)
+ if (optimize && JUMP_P (insn))
{
rtx lab = JUMP_LABEL (insn);
if (lab && LABEL_NUSES (lab) == 1)
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 ())
{
/* This can be triggered by bugs elsewhere in the compiler if
new insns are created after init_insn_lengths is called. */
- if (GET_CODE (insn) == NOTE)
- 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 ();
+ gcc_unreachable ();
}
}
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))
+ switch (NOTE_KIND (insn))
{
case NOTE_INSN_DELETED:
- case NOTE_INSN_LOOP_BEG:
- case NOTE_INSN_LOOP_END:
- case NOTE_INSN_LOOP_END_TOP_COND:
- case NOTE_INSN_LOOP_CONT:
- case NOTE_INSN_LOOP_VTOP:
- 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) ();
+ switch_to_section (current_function_section ());
break;
case NOTE_INSN_BASIC_BLOCK:
-#ifdef IA64_UNWIND_INFO
- IA64_UNWIND_EMIT (asm_out_file, insn);
+#ifdef TARGET_UNWIND_INFO
+ targetm.asm_out.unwind_emit (asm_out_file, insn);
#endif
+
if (flag_debug_asm)
fprintf (asm_out_file, "\t%s basic block %d\n",
ASM_COMMENT_START, NOTE_BASIC_BLOCK (insn)->index);
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;
case NOTE_INSN_BLOCK_BEG:
if (debug_info_level == DINFO_LEVEL_NORMAL
|| debug_info_level == DINFO_LEVEL_VERBOSE
- || write_symbols == DWARF_DEBUG
|| write_symbols == DWARF2_DEBUG
|| write_symbols == VMS_AND_DWARF2_DEBUG
|| write_symbols == VMS_DEBUG)
case NOTE_INSN_BLOCK_END:
if (debug_info_level == DINFO_LEVEL_NORMAL
|| debug_info_level == DINFO_LEVEL_VERBOSE
- || write_symbols == DWARF_DEBUG
|| write_symbols == DWARF2_DEBUG
|| write_symbols == VMS_AND_DWARF2_DEBUG
|| write_symbols == VMS_DEBUG)
/* 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);
}
(*debug_hooks->var_location) (insn);
break;
- case 0:
- break;
-
default:
- if (NOTE_LINE_NUMBER (insn) <= 0)
- abort ();
+ gcc_unreachable ();
break;
}
break;
case BARRIER:
#if defined (DWARF2_UNWIND_INFO)
if (dwarf2out_do_frame ())
- dwarf2out_frame_debug (insn);
+ dwarf2out_frame_debug (insn, false);
#endif
break;
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 && GET_CODE (barrier) == BARRIER
- && jump && GET_CODE (jump) == JUMP_INSN
+ if (barrier && BARRIER_P (barrier)
+ && jump && JUMP_P (jump)
&& (prev = prev_nonnote_insn (jump))
- && GET_CODE (prev) == INSN)
+ && NONJUMP_INSN_P (prev))
{
NOTICE_UPDATE_CC (PATTERN (prev), prev);
NOTICE_UPDATE_CC (PATTERN (jump), jump);
}
}
#endif
- if (prescan > 0)
- break;
if (LABEL_NAME (insn))
(*debug_hooks->label) (insn);
fputs (ASM_APP_OFF, file);
app_on = 0;
}
- if (NEXT_INSN (insn) != 0
- && GET_CODE (NEXT_INSN (insn)) == JUMP_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;
- readonly_data_section ();
+ 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
rtx body = PATTERN (insn);
int insn_code_number;
const char *template;
- rtx note;
+#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. */
break;
#ifdef HAVE_cc0
- /* If there is a REG_CC_SETTER note on this insn, it means that
- the setting of the condition code was done in the delay slot
- of the insn that branched here. So recover the cc status
- from the insn that set it. */
+ {
+ /* If there is a REG_CC_SETTER note on this insn, it means that
+ the setting of the condition code was done in the delay slot
+ of the insn that branched here. So recover the cc status
+ from the insn that set it. */
- note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX);
- if (note)
- {
- NOTICE_UPDATE_CC (PATTERN (XEXP (note, 0)), XEXP (note, 0));
- cc_prev_status = cc_status;
- }
+ rtx note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX);
+ if (note)
+ {
+ NOTICE_UPDATE_CC (PATTERN (XEXP (note, 0)), XEXP (note, 0));
+ cc_prev_status = cc_status;
+ }
+ }
#endif
/* Detect insns that are really jump-tables
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])
{
+ location_t loc;
+
if (! app_on)
{
fputs (ASM_APP_ON, file);
app_on = 1;
}
+#ifdef USE_MAPPED_LOCATION
+ loc = ASM_INPUT_SOURCE_LOCATION (body);
+#else
+ loc.file = ASM_INPUT_SOURCE_FILE (body);
+ loc.line = ASM_INPUT_SOURCE_LINE (body);
+#endif
+ 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;
}
unsigned int noperands = asm_noperands (body);
rtx *ops = alloca (noperands * sizeof (rtx));
const char *string;
+ location_t loc;
/* 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. */
+ string = decode_asm_operands (body, ops, NULL, NULL, NULL, &loc);
+ /* Inhibit dieing on what would otherwise be compiler bugs. */
insn_noperands = noperands;
this_is_asm_operands = insn;
fputs (ASM_APP_ON, file);
app_on = 1;
}
+ if (loc.file && loc.line)
+ fprintf (asm_out_file, "%s %i \"%s\" 1\n",
+ ASM_COMMENT_START, loc.line, loc.file);
output_asm_insn (string, ops);
+#if HAVE_AS_LINE_ZERO
+ if (loc.file && loc.line)
+ fprintf (asm_out_file, "%s 0 \"\" 2\n", ASM_COMMENT_START);
+#endif
}
this_is_asm_operands = 0;
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
called function. Hence we don't preserve any CC-setting
actions in these insns and the CC must be marked as being
clobbered by the function. */
- if (GET_CODE (XVECEXP (body, 0, 0)) == CALL_INSN)
+ if (CALL_P (XVECEXP (body, 0, 0)))
{
CC_STATUS_INIT;
}
}
#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
- && GET_CODE (insn) == INSN && GET_CODE (body) == SET
- && GET_CODE (SET_SRC (body)) == REG
- && GET_CODE (SET_DEST (body)) == REG
- && 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
do straightforwardly if the cc's were set up normally. */
if (cc_status.flags != 0
- && GET_CODE (insn) == JUMP_INSN
+ && JUMP_P (insn)
&& GET_CODE (body) == SET
&& 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.
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;
+ }
+
+ /* 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). */
{
rtx cond_rtx, then_rtx, else_rtx;
- if (GET_CODE (insn) != JUMP_INSN
+ if (!JUMP_P (insn)
&& GET_CODE (SET_SRC (set)) == IF_THEN_ELSE)
{
cond_rtx = XEXP (SET_SRC (set), 0);
emit them before the peephole. */
if (next != 0 && next != NEXT_INSN (insn))
{
- rtx prev = PREV_INSN (insn);
+ rtx note, prev = PREV_INSN (insn);
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;
#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
current_output_insn = debug_insn = insn;
#if defined (DWARF2_UNWIND_INFO)
- if (GET_CODE (insn) == CALL_INSN && dwarf2out_do_frame ())
- dwarf2out_frame_debug (insn);
+ if (CALL_P (insn) && dwarf2out_do_frame ())
+ 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
prev != last_ignored_compare;
prev = PREV_INSN (prev))
{
- if (GET_CODE (prev) == NOTE)
+ if (NOTE_P (prev))
delete_insn (prev); /* Use delete_note. */
}
/* 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 IA64_UNWIND_INFO
- IA64_UNWIND_EMIT (asm_out_file, insn);
+#ifdef TARGET_UNWIND_INFO
+ /* ??? This will put the directives in the wrong place if
+ get_insn_template outputs assembly directly. However calling it
+ before get_insn_template breaks if the insns is split. */
+ targetm.asm_out.unwind_emit (asm_out_file, insn);
#endif
- /* Output assembler code from the template. */
+ /* Output assembler code from the template. */
output_asm_insn (template, recog_data.operand);
/* If necessary, report the effect that the instruction has on
the unwind info. We've already done this for delay slots
and call instructions. */
#if defined (DWARF2_UNWIND_INFO)
- if (GET_CODE (insn) == INSN
+ if (final_sequence == 0
#if !defined (HAVE_prologue)
&& !ACCUMULATE_OUTGOING_ARGS
#endif
- && final_sequence == 0
&& dwarf2out_do_frame ())
- dwarf2out_frame_debug (insn);
-#endif
-
-#if 0
- /* It's not at all clear why we did this and doing so used to
- interfere with tests that used REG_WAS_0 notes, which are
- now gone, so let's try with this out. */
-
- /* Mark this insn as having been output. */
- INSN_DELETED_P (insn) = 1;
+ dwarf2out_frame_debug (insn, true);
#endif
- /* Emit information for vtable gc. */
- note = find_reg_note (insn, REG_VTABLE_REF, NULL_RTX);
-
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);
recog_data.operand[i] = alter_subreg (recog_data.operand_loc[i]);
else if (GET_CODE (recog_data.operand[i]) == PLUS
|| GET_CODE (recog_data.operand[i]) == MULT
- || GET_CODE (recog_data.operand[i]) == MEM)
+ || MEM_P (recog_data.operand[i]))
recog_data.operand[i] = walk_alter_subreg (recog_data.operand_loc[i]);
}
*recog_data.dup_loc[i] = alter_subreg (recog_data.dup_loc[i]);
else if (GET_CODE (*recog_data.dup_loc[i]) == PLUS
|| GET_CODE (*recog_data.dup_loc[i]) == MULT
- || GET_CODE (*recog_data.dup_loc[i]) == MEM)
+ || MEM_P (*recog_data.dup_loc[i]))
*recog_data.dup_loc[i] = walk_alter_subreg (recog_data.dup_loc[i]);
}
}
/* simplify_subreg does not remove subreg from volatile references.
We are required to. */
- if (GET_CODE (y) == MEM)
- *xp = adjust_address (y, GET_MODE (x), SUBREG_BYTE (x));
+ if (MEM_P (y))
+ {
+ 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 (GET_CODE (y) == REG)
+ 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;
{
case PLUS:
case MULT:
+ case AND:
XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0));
XEXP (x, 1) = walk_alter_subreg (&XEXP (x, 1));
break;
case MEM:
+ case ZERO_EXTEND:
XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0));
break;
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)
*paddressp = 0;
- if (GET_CODE (op) == REG)
+ if (REG_P (op))
return REG_EXPR (op);
- else if (GET_CODE (op) != MEM)
+ else if (!MEM_P (op))
return 0;
if (MEM_EXPR (op) != 0)
else if (ISALPHA (*p))
{
int letter = *p++;
- c = atoi (p);
+ unsigned long opnum;
+ char *endptr;
+
+ opnum = strtoul (p, &endptr, 10);
- if (! ISDIGIT (*p))
- output_operand_lossage ("operand number missing after %%-letter");
- else if (this_is_asm_operands
- && (c < 0 || (unsigned int) c >= insn_noperands))
+ 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.
if (GET_CODE (x) == LABEL_REF)
x = XEXP (x, 0);
- if (GET_CODE (x) == CODE_LABEL
- || (GET_CODE (x) == NOTE
- && NOTE_LINE_NUMBER (x) == NOTE_INSN_DELETED_LABEL))
+ if (LABEL_P (x)
+ || (NOTE_P (x)
+ && 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");
+ 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 && GET_CODE (x) == REG && 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);
}
break;
case SYMBOL_REF:
+ if (SYMBOL_REF_DECL (x))
+ mark_decl_referenced (SYMBOL_REF_DECL (x));
#ifdef ASM_OUTPUT_SYMBOL_REF
ASM_OUTPUT_SYMBOL_REF (file, x);
#else
ASM_FPRINTF_EXTENSIONS (file, argptr, p)
#endif
default:
- abort ();
+ gcc_unreachable ();
}
break;
}
#endif
- *first = GEN_INT ((HOST_WIDE_INT) l[0]);
- *second = GEN_INT ((HOST_WIDE_INT) l[1]);
+ *first = GEN_INT (l[0]);
+ *second = GEN_INT (l[1]);
}
}
\f
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
- if (GET_CODE (insn) == CALL_INSN
+ if (CALL_P (insn)
&& ! SIBLING_CALL_P (insn))
return 0;
- if (GET_CODE (insn) == INSN
+ if (NONJUMP_INSN_P (insn)
&& GET_CODE (PATTERN (insn)) == SEQUENCE
- && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN
+ && CALL_P (XVECEXP (PATTERN (insn), 0, 0))
&& ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0)))
return 0;
}
{
insn = XEXP (link, 0);
- if (GET_CODE (insn) == CALL_INSN
+ if (CALL_P (insn)
&& ! SIBLING_CALL_P (insn))
return 0;
- if (GET_CODE (insn) == INSN
+ if (NONJUMP_INSN_P (insn)
&& GET_CODE (PATTERN (insn)) == SEQUENCE
- && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN
+ && CALL_P (XVECEXP (PATTERN (insn), 0, 0))
&& ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0)))
return 0;
}
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;
}
if (current_function_uses_pic_offset_table
&& pic_offset_table_rtx != 0
- && GET_CODE (pic_offset_table_rtx) == REG
+ && REG_P (pic_offset_table_rtx)
&& ! permitted_reg_in_leaf_functions[REGNO (pic_offset_table_rtx)])
return 0;
renumbered_regs would be 1 for an output-register;
they */
- if (GET_CODE (in_rtx) == REG)
+ if (REG_P (in_rtx))
{
int newreg;
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
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
symbol_queue_size = 0;
}
}
+\f
+/* Turn the RTL into assembly. */
+static unsigned int
+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 (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 (fnname);
+#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);
+ 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 =
+{
+ 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 unsigned int
+rest_of_handle_shorten_branches (void)
+{
+ /* Shorten branches. */
+ shorten_branches (get_insns ());
+ return 0;
+}
+
+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 unsigned int
+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;
+#ifdef STACK_REGS
+ regstack_completed = 0;
+#endif
+
+ /* 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);
+ return 0;
+}
+
+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 */
+};
+