/* Convert RTL to assembler code and output it, for GNU compiler.
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
- 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+ 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
Free Software Foundation, Inc.
This file is part of GCC.
#include "expr.h"
#include "cfglayout.h"
#include "tree-pass.h"
+#include "tree-flow.h"
#include "timevar.h"
#include "cgraph.h"
#include "coverage.h"
/* Line number of last NOTE. */
static int last_linenum;
+/* Last discriminator written to assembly. */
+static int last_discriminator;
+
+/* Discriminator of current block. */
+static int discriminator;
+
/* Highest line number in current block. */
static int high_block_linenum;
CC_STATUS cc_prev_status;
#endif
-/* Nonzero means current function must be given a frame pointer.
- Initialized in function.c to 0. Set only in reload1.c as per
- the needs of the function. */
-
-int frame_pointer_needed;
-
/* Number of unmatched NOTE_INSN_BLOCK_BEG notes we have seen. */
static int block_depth;
static int dialect_number;
#endif
-#ifdef HAVE_conditional_execution
/* Nonnull if the insn currently being emitted was a COND_EXEC pattern. */
rtx current_insn_predicate;
-#endif
#ifdef HAVE_ATTR_length
static int asm_insn_count (rtx);
#endif
static void profile_function (FILE *);
static void profile_after_prologue (FILE *);
-static bool notice_source_line (rtx);
+static bool notice_source_line (rtx, bool *);
static rtx walk_alter_subreg (rtx *, bool *);
static void output_asm_name (void);
static void output_alternate_entry_point (FILE *, rtx);
case NOTE:
case BARRIER:
case CODE_LABEL:
+ case DEBUG_INSN:
return 0;
case CALL_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));
+ length += get_attr_length_1 (XVECEXP (body, 0, i), fallback_fn);
else
length = fallback_fn (insn);
break;
int
label_to_alignment (rtx label)
{
- return LABEL_TO_ALIGNMENT (label);
+ if (CODE_LABEL_NUMBER (label) <= max_labelno)
+ return LABEL_TO_ALIGNMENT (label);
+ return 0;
+}
+
+int
+label_to_max_skip (rtx label)
+{
+ if (CODE_LABEL_NUMBER (label) <= max_labelno)
+ return LABEL_TO_MAX_SKIP (label);
+ return 0;
}
#ifdef HAVE_ATTR_length
/* Compute branch alignments based on frequency information in the
CFG. */
-static unsigned int
+unsigned int
compute_alignments (void)
{
int log, max_skip, max_log;
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)
+ if (! optimize || optimize_function_for_size_p (cfun))
return 0;
if (dump_file)
edge_iterator ei;
if (!LABEL_P (label)
- || probably_never_executed_bb_p (bb))
+ || optimize_bb_for_size_p (bb))
{
if (dump_file)
fprintf(dump_file, "BB %4i freq %4i loop %2i loop_depth %2i skipped.\n",
/* In case block is frequent and reached mostly by non-fallthru edge,
align it. It is most likely a first block of loop. */
if (has_fallthru
- && maybe_hot_bb_p (bb)
+ && optimize_bb_for_speed_p (bb)
&& branch_frequency + fallthru_frequency > freq_threshold
&& (branch_frequency
> fallthru_frequency * PARAM_VALUE (PARAM_ALIGN_LOOP_ITERATIONS)))
}
if (dump_file)
- loop_optimizer_finalize ();
+ {
+ loop_optimizer_finalize ();
+ free_dominance_info (CDI_DOMINATORS);
+ }
return 0;
}
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
- 0, /* tv_id */
+ TV_NONE, /* tv_id */
0, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
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. */
if (LABEL_P (insn))
{
rtx next;
+ bool next_is_jumptable;
/* Merge in alignments computed by compute_alignments. */
log = LABEL_TO_ALIGNMENT (insn);
max_skip = LABEL_TO_MAX_SKIP (insn);
}
- log = LABEL_ALIGN (insn);
- if (max_log < log)
+ next = next_nonnote_insn (insn);
+ next_is_jumptable = next && JUMP_TABLE_DATA_P (next);
+ if (!next_is_jumptable)
{
- max_log = log;
- max_skip = LABEL_ALIGN_MAX_SKIP;
+ log = LABEL_ALIGN (insn);
+ if (max_log < log)
+ {
+ max_log = log;
+ max_skip = LABEL_ALIGN_MAX_SKIP;
+ }
}
- 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
- || readonly_data_section == text_section)
- if (next && JUMP_P (next))
- {
- rtx nextbody = PATTERN (next);
- if (GET_CODE (nextbody) == ADDR_VEC
- || GET_CODE (nextbody) == ADDR_DIFF_VEC)
- {
- log = ADDR_VEC_ALIGN (next);
- if (max_log < log)
- {
- max_log = log;
- max_skip = LABEL_ALIGN_MAX_SKIP;
- }
- }
- }
+ if ((JUMP_TABLES_IN_TEXT_SECTION
+ || readonly_data_section == text_section)
+ && next_is_jumptable)
+ {
+ log = ADDR_VEC_ALIGN (next);
+ if (max_log < log)
+ {
+ max_log = log;
+ max_skip = LABEL_ALIGN_MAX_SKIP;
+ }
+ }
LABEL_TO_ALIGNMENT (insn) = max_log;
LABEL_TO_MAX_SKIP (insn) = max_skip;
max_log = 0;
INSN_ADDRESSES (uid) = insn_current_address + insn_lengths[uid];
if (NOTE_P (insn) || BARRIER_P (insn)
- || LABEL_P (insn))
+ || LABEL_P (insn) || DEBUG_INSN_P(insn))
continue;
if (INSN_DELETED_P (insn))
continue;
static int
asm_insn_count (rtx body)
{
- const char *template;
- int count = 1;
+ const char *templ;
if (GET_CODE (body) == ASM_INPUT)
- template = XSTR (body, 0);
+ templ = XSTR (body, 0);
else
- template = decode_asm_operands (body, NULL, NULL, NULL, NULL, NULL);
+ templ = decode_asm_operands (body, NULL, NULL, NULL, NULL, NULL);
+
+ return asm_str_count (templ);
+}
+#endif
- for (; *template; template++)
- if (IS_ASM_LOGICAL_LINE_SEPARATOR (*template, template)
- || *template == '\n')
+/* Return the number of machine instructions likely to be generated for the
+ inline-asm template. */
+int
+asm_str_count (const char *templ)
+{
+ int count = 1;
+
+ if (!*templ)
+ return 0;
+
+ for (; *templ; templ++)
+ if (IS_ASM_LOGICAL_LINE_SEPARATOR (*templ, templ)
+ || *templ == '\n')
count++;
return count;
}
-#endif
\f
/* ??? This is probably the wrong place for these. */
/* Structure recording the mapping from source file and directory
return;
}
map = XNEW (debug_prefix_map);
- map->old_prefix = ggc_alloc_string (arg, p - arg);
+ map->old_prefix = xstrndup (arg, p - arg);
map->old_len = p - arg;
p++;
- map->new_prefix = ggc_strdup (p);
+ map->new_prefix = xstrdup (p);
map->new_len = strlen (p);
map->next = debug_prefix_maps;
debug_prefix_maps = map;
return ggc_strdup (s);
}
\f
+/* Return true if DWARF2 debug info can be emitted for DECL. */
+
+static bool
+dwarf2_debug_info_emitted_p (tree decl)
+{
+ if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG)
+ return false;
+
+ if (DECL_IGNORED_P (decl))
+ return false;
+
+ return true;
+}
+
/* 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
last_filename = locator_file (prologue_locator);
last_linenum = locator_line (prologue_locator);
+ last_discriminator = discriminator = 0;
high_block_linenum = high_function_linenum = last_linenum;
- (*debug_hooks->begin_prologue) (last_linenum, last_filename);
+ if (!DECL_IGNORED_P (current_function_decl))
+ debug_hooks->begin_prologue (last_linenum, last_filename);
#if defined (DWARF2_UNWIND_INFO) || defined (TARGET_UNWIND_INFO)
- if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG)
+ if (!dwarf2_debug_info_emitted_p (current_function_decl))
dwarf2out_begin_prologue (0, NULL);
#endif
/* 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 */
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 */
}
#ifndef NO_PROFILE_COUNTERS
# define NO_PROFILE_COUNTERS 0
#endif
-#if defined(ASM_OUTPUT_REG_PUSH)
- 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 = cfun->static_chain_decl != NULL;
-#endif
+#ifdef ASM_OUTPUT_REG_PUSH
+ rtx sval = NULL, chain = NULL;
+
+ if (cfun->returns_struct)
+ sval = targetm.calls.struct_value_rtx (TREE_TYPE (current_function_decl),
+ true);
+ if (cfun->static_chain_decl)
+ chain = targetm.calls.static_chain (current_function_decl, true);
#endif /* ASM_OUTPUT_REG_PUSH */
if (! NO_PROFILE_COUNTERS)
switch_to_section (current_function_section ());
-#if defined(ASM_OUTPUT_REG_PUSH)
- if (sval && svrtx != NULL_RTX && REG_P (svrtx))
- {
- ASM_OUTPUT_REG_PUSH (file, REGNO (svrtx));
- }
-#endif
-
-#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
- if (cxt)
- ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_INCOMING_REGNUM);
-#else
-#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
- if (cxt)
- {
- ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_REGNUM);
- }
-#endif
+#ifdef ASM_OUTPUT_REG_PUSH
+ if (sval && REG_P (sval))
+ ASM_OUTPUT_REG_PUSH (file, REGNO (sval));
+ if (chain && REG_P (chain))
+ ASM_OUTPUT_REG_PUSH (file, REGNO (chain));
#endif
FUNCTION_PROFILER (file, current_function_funcdef_no);
-#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
- if (cxt)
- ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_INCOMING_REGNUM);
-#else
-#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
- if (cxt)
- {
- ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_REGNUM);
- }
-#endif
-#endif
-
-#if defined(ASM_OUTPUT_REG_PUSH)
- if (sval && svrtx != NULL_RTX && REG_P (svrtx))
- {
- ASM_OUTPUT_REG_POP (file, REGNO (svrtx));
- }
+#ifdef ASM_OUTPUT_REG_PUSH
+ if (chain && REG_P (chain))
+ ASM_OUTPUT_REG_POP (file, REGNO (chain));
+ if (sval && REG_P (sval))
+ ASM_OUTPUT_REG_POP (file, REGNO (sval));
#endif
}
{
app_disable ();
- (*debug_hooks->end_function) (high_function_linenum);
+ if (!DECL_IGNORED_P (current_function_decl))
+ debug_hooks->end_function (high_function_linenum);
/* Finally, output the function epilogue:
code to restore the stack frame and return to the caller. */
targetm.asm_out.function_epilogue (asm_out_file, get_frame_size ());
/* And debug output. */
- (*debug_hooks->end_epilogue) (last_linenum, last_filename);
+ if (!DECL_IGNORED_P (current_function_decl))
+ debug_hooks->end_epilogue (last_linenum, last_filename);
#if defined (DWARF2_UNWIND_INFO)
- if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG
+ if (!dwarf2_debug_info_emitted_p (current_function_decl)
&& dwarf2out_do_frame ())
dwarf2out_end_epilogue (last_linenum, last_filename);
#endif
}
}
+/* 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.
dwarf2out_switch_text_section ();
else
#endif
- (*debug_hooks->switch_text_section) ();
+ if (!DECL_IGNORED_P (current_function_decl))
+ debug_hooks->switch_text_section ();
switch_to_section (current_function_section ());
break;
else
*seen |= SEEN_BB;
+ discriminator = NOTE_BASIC_BLOCK (insn)->discriminator;
+
break;
case NOTE_INSN_EH_REGION_BEG:
break;
case NOTE_INSN_EPILOGUE_BEG:
+#if defined (DWARF2_UNWIND_INFO) && defined (HAVE_epilogue)
+ if (dwarf2out_do_frame ())
+ dwarf2out_begin_epilogue (insn);
+#endif
targetm.asm_out.function_begin_epilogue (file);
break;
+ case NOTE_INSN_CFA_RESTORE_STATE:
+#if defined (DWARF2_UNWIND_INFO)
+ dwarf2out_frame_debug_restore_state ();
+#endif
+ break;
+
case NOTE_INSN_FUNCTION_BEG:
app_disable ();
- (*debug_hooks->end_prologue) (last_linenum, last_filename);
+ if (!DECL_IGNORED_P (current_function_decl))
+ debug_hooks->end_prologue (last_linenum, last_filename);
if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE)
{
high_block_linenum = last_linenum;
/* Output debugging info about the symbol-block beginning. */
- (*debug_hooks->begin_block) (last_linenum, n);
+ if (!DECL_IGNORED_P (current_function_decl))
+ debug_hooks->begin_block (last_linenum, n);
/* Mark this block as output. */
TREE_ASM_WRITTEN (NOTE_BLOCK (insn)) = 1;
--block_depth;
gcc_assert (block_depth >= 0);
- (*debug_hooks->end_block) (high_block_linenum, n);
+ if (!DECL_IGNORED_P (current_function_decl))
+ debug_hooks->end_block (high_block_linenum, n);
}
if (write_symbols == DBX_DEBUG
|| write_symbols == SDB_DEBUG)
break;
case NOTE_INSN_VAR_LOCATION:
- (*debug_hooks->var_location) (insn);
+ if (!DECL_IGNORED_P (current_function_decl))
+ debug_hooks->var_location (insn);
break;
default:
}
#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))
- (*debug_hooks->label) (insn);
+ if (!DECL_IGNORED_P (current_function_decl) && LABEL_NAME (insn))
+ debug_hooks->label (insn);
- if (app_on)
- {
- fputs (ASM_APP_OFF, file);
- app_on = 0;
- }
+ app_disable ();
next = next_nonnote_insn (insn);
- if (next != 0 && JUMP_P (next))
+ /* If this label is followed by a jump-table, make sure we put
+ the label in the read-only section. Also possibly write the
+ label and jump table together. */
+ if (next != 0 && JUMP_TABLE_DATA_P (next))
{
- 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
- possibly write the label and jump table together. */
-
- if (GET_CODE (nextbody) == ADDR_VEC
- || GET_CODE (nextbody) == ADDR_DIFF_VEC)
- {
#if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)
- /* In this case, the case vector is being moved by the
- target, so don't output the label at all. Leave that
- to the back end macros. */
+ /* In this case, the case vector is being moved by the
+ target, so don't output the label at all. Leave that
+ to the back end macros. */
#else
- if (! JUMP_TABLES_IN_TEXT_SECTION)
- {
- int log_align;
+ if (! JUMP_TABLES_IN_TEXT_SECTION)
+ {
+ int log_align;
- switch_to_section (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);
+ log_align = ADDR_VEC_ALIGN (next);
#else
- log_align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
+ log_align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
#endif
- ASM_OUTPUT_ALIGN (file, log_align);
- }
- else
- switch_to_section (current_function_section ());
+ ASM_OUTPUT_ALIGN (file, log_align);
+ }
+ else
+ switch_to_section (current_function_section ());
#ifdef ASM_OUTPUT_CASE_LABEL
- ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn),
- next);
+ ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn),
+ next);
#else
- targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (insn));
+ targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (insn));
#endif
#endif
- break;
- }
+ break;
}
if (LABEL_ALT_ENTRY_P (insn))
output_alternate_entry_point (file, insn);
{
rtx body = PATTERN (insn);
int insn_code_number;
- const char *template;
+ const char *templ;
+ bool is_stmt;
-#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. */
else
switch_to_section (current_function_section ());
- if (app_on)
- {
- fputs (ASM_APP_OFF, file);
- app_on = 0;
- }
+ app_disable ();
#if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)
if (GET_CODE (body) == ADDR_VEC)
}
/* Output this line note if it is the first or the last line
note in a row. */
- if (notice_source_line (insn))
- {
- (*debug_hooks->source_line) (last_linenum, last_filename);
- }
+ if (!DECL_IGNORED_P (current_function_decl)
+ && notice_source_line (insn, &is_stmt))
+ (*debug_hooks->source_line) (last_linenum, last_filename,
+ last_discriminator, is_stmt);
if (GET_CODE (body) == ASM_INPUT)
{
{
expanded_location loc;
- if (! app_on)
- {
- fputs (ASM_APP_ON, file);
- app_on = 1;
- }
+ app_enable ();
loc = expand_location (ASM_INPUT_SOURCE_LOCATION (body));
if (*loc.file && loc.line)
fprintf (asm_out_file, "%s %i \"%s\" 1\n",
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;
/* Output the insn using them. */
if (string[0])
{
- if (! app_on)
- {
- fputs (ASM_APP_ON, file);
- app_on = 1;
- }
+ app_enable ();
if (expanded.file && expanded.line)
fprintf (asm_out_file, "%s %i \"%s\" 1\n",
ASM_COMMENT_START, expanded.line, expanded.file);
#endif
}
+ if (targetm.asm_out.final_postscan_insn)
+ targetm.asm_out.final_postscan_insn (file, insn, ops,
+ insn_noperands);
+
this_is_asm_operands = 0;
break;
}
- if (app_on)
- {
- fputs (ASM_APP_OFF, file);
- app_on = 0;
- }
+ app_disable ();
if (GET_CODE (body) == SEQUENCE)
{
&& GET_CODE (SET_DEST (set)) == CC0
&& insn != last_ignored_compare)
{
+ rtx src1, src2;
if (GET_CODE (SET_SRC (set)) == SUBREG)
SET_SRC (set) = alter_subreg (&SET_SRC (set));
- else if (GET_CODE (SET_SRC (set)) == COMPARE)
+
+ src1 = SET_SRC (set);
+ src2 = NULL_RTX;
+ if (GET_CODE (SET_SRC (set)) == COMPARE)
{
if (GET_CODE (XEXP (SET_SRC (set), 0)) == SUBREG)
XEXP (SET_SRC (set), 0)
if (GET_CODE (XEXP (SET_SRC (set), 1)) == SUBREG)
XEXP (SET_SRC (set), 1)
= alter_subreg (&XEXP (SET_SRC (set), 1));
+ if (XEXP (SET_SRC (set), 1)
+ == CONST0_RTX (GET_MODE (XEXP (SET_SRC (set), 0))))
+ src2 = XEXP (SET_SRC (set), 0);
}
if ((cc_status.value1 != 0
- && rtx_equal_p (SET_SRC (set), cc_status.value1))
+ && rtx_equal_p (src1, cc_status.value1))
|| (cc_status.value2 != 0
- && rtx_equal_p (SET_SRC (set), cc_status.value2)))
+ && rtx_equal_p (src1, cc_status.value2))
+ || (src2 != 0 && cc_status.value1 != 0
+ && rtx_equal_p (src2, cc_status.value1))
+ || (src2 != 0 && cc_status.value2 != 0
+ && rtx_equal_p (src2, cc_status.value2)))
{
/* Don't delete insn if it has an addressing side-effect. */
if (! FIND_REG_INC_NOTE (insn, NULL_RTX)
}
}
}
-#endif
-#ifdef HAVE_cc0
/* If this is a conditional branch, maybe modify it
if the cc's are in a nonstandard state
so that it accomplishes the same thing that it would
FINAL_PRESCAN_INSN (insn, recog_data.operand, recog_data.n_operands);
#endif
-#ifdef HAVE_conditional_execution
- if (GET_CODE (PATTERN (insn)) == COND_EXEC)
+ if (targetm.have_conditional_execution ()
+ && GET_CODE (PATTERN (insn)) == COND_EXEC)
current_insn_predicate = COND_EXEC_TEST (PATTERN (insn));
-#endif
#ifdef HAVE_cc0
cc_prev_status = cc_status;
#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);
+
+ /* Record point-of-call information for ICF debugging. */
+ if (flag_enable_icf_debug && CALL_P (insn))
+ {
+ rtx x = call_from_call_insn (insn);
+ x = XEXP (x, 0);
+ if (x && MEM_P (x))
+ {
+ if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF)
+ {
+ tree t;
+ x = XEXP (x, 0);
+ t = SYMBOL_REF_DECL (x);
+ if (t)
+ (*debug_hooks->direct_call) (t);
+ }
+ else
+ (*debug_hooks->virtual_call) (INSN_UID (insn));
+ }
+ }
+
+ /* Some target machines need to postscan each insn after
+ it is output. */
+ if (targetm.asm_out.final_postscan_insn)
+ targetm.asm_out.final_postscan_insn (file, insn, recog_data.operand,
+ recog_data.n_operands);
/* If necessary, report the effect that the instruction has on
the unwind info. We've already done this for delay slots
return NEXT_INSN (insn);
}
\f
-/* Return whether a source line note needs to be emitted before INSN. */
+/* Return whether a source line note needs to be emitted before INSN.
+ Sets IS_STMT to TRUE if the line should be marked as a possible
+ breakpoint location. */
static bool
-notice_source_line (rtx insn)
+notice_source_line (rtx insn, bool *is_stmt)
{
const char *filename;
int linenum;
linenum = insn_line (insn);
}
- if (filename
- && (force_source_line
- || filename != last_filename
- || last_linenum != linenum))
+ if (filename == NULL)
+ return false;
+
+ if (force_source_line
+ || filename != last_filename
+ || last_linenum != linenum)
{
force_source_line = false;
last_filename = filename;
last_linenum = linenum;
+ last_discriminator = discriminator;
+ *is_stmt = true;
high_block_linenum = MAX (last_linenum, high_block_linenum);
high_function_linenum = MAX (last_linenum, high_function_linenum);
return true;
}
+
+ if (SUPPORTS_DISCRIMINATOR && last_discriminator != discriminator)
+ {
+ /* If the discriminator changed, but the line number did not,
+ output the line table entry with is_stmt false so the
+ debugger does not treat this as a breakpoint location. */
+ last_discriminator = discriminator;
+ *is_stmt = false;
+ return true;
+ }
+
return false;
}
\f
}
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. */
&& (expr = get_mem_expr_from_op (XEXP (op, 1), &inner_addressp)))
return expr;
- while (GET_RTX_CLASS (GET_CODE (op)) == RTX_UNARY
+ while (UNARY_P (op)
|| GET_RTX_CLASS (GET_CODE (op)) == RTX_BIN_ARITH)
op = XEXP (op, 0);
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
}
else if (letter == 'n')
{
- if (GET_CODE (operands[opnum]) == CONST_INT)
+ if (CONST_INT_P (operands[opnum]))
fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC,
- INTVAL (operands[opnum]));
else
assemble_name (asm_out_file, buf);
}
+/* Helper rtx-iteration-function for mark_symbol_refs_as_used and
+ output_operand. Marks SYMBOL_REFs as referenced through use of
+ assemble_external. */
+
+static int
+mark_symbol_ref_as_used (rtx *xp, void *dummy ATTRIBUTE_UNUSED)
+{
+ rtx x = *xp;
+
+ /* If we have a used symbol, we may have to emit assembly
+ annotations corresponding to whether the symbol is external, weak
+ or has non-default visibility. */
+ if (GET_CODE (x) == SYMBOL_REF)
+ {
+ tree t;
+
+ t = SYMBOL_REF_DECL (x);
+ if (t)
+ assemble_external (t);
+
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Marks SYMBOL_REFs in x as referenced through use of assemble_external. */
+
+void
+mark_symbol_refs_as_used (rtx x)
+{
+ for_each_rtx (&x, mark_symbol_ref_as_used, NULL);
+}
+
/* Print operand X using machine-dependent assembler syntax.
The macro PRINT_OPERAND is defined just to control this function.
CODE is a non-digit that preceded the operand-number in the % spec,
gcc_assert (!x || !REG_P (x) || REGNO (x) < FIRST_PSEUDO_REGISTER);
PRINT_OPERAND (asm_out_file, x, code);
+
+ if (x == NULL_RTX)
+ return;
+
+ for_each_rtx (&x, mark_symbol_ref_as_used, NULL);
}
/* Print a memory reference operand for address X
case SYMBOL_REF:
if (SYMBOL_REF_DECL (x))
- mark_decl_referenced (SYMBOL_REF_DECL (x));
+ {
+ mark_decl_referenced (SYMBOL_REF_DECL (x));
+ assemble_external (SYMBOL_REF_DECL (x));
+ }
#ifdef ASM_OUTPUT_SYMBOL_REF
ASM_OUTPUT_SYMBOL_REF (file, x);
#else
/* 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));
}
break;
case CONST_FIXED:
- fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_FIXED_VALUE_LOW (x));
+ 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)
+ if (CONST_INT_P (XEXP (x, 0)))
{
output_addr_const (file, XEXP (x, 1));
if (INTVAL (XEXP (x, 0)) >= 0)
else
{
output_addr_const (file, XEXP (x, 0));
- if (GET_CODE (XEXP (x, 1)) != CONST_INT
+ if (!CONST_INT_P (XEXP (x, 1))
|| INTVAL (XEXP (x, 1)) >= 0)
fprintf (file, "+");
output_addr_const (file, XEXP (x, 1));
output_addr_const (file, XEXP (x, 0));
fprintf (file, "-");
- if ((GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) >= 0)
+ if ((CONST_INT_P (XEXP (x, 1)) && INTVAL (XEXP (x, 1)) >= 0)
|| GET_CODE (XEXP (x, 1)) == PC
|| GET_CODE (XEXP (x, 1)) == SYMBOL_REF)
output_addr_const (file, XEXP (x, 1));
void
split_double (rtx value, rtx *first, rtx *second)
{
- if (GET_CODE (value) == CONST_INT)
+ if (CONST_INT_P (value))
{
if (HOST_BITS_PER_WIDE_INT >= (2 * BITS_PER_WORD))
{
rtx insn;
rtx link;
- if (current_function_profile || profile_arc_flag)
+ if (crtl->profile || profile_arc_flag)
return 0;
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
&& ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0)))
return 0;
}
- for (link = current_function_epilogue_delay_list;
+ for (link = crtl->epilogue_delay_list;
link;
link = XEXP (link, 1))
{
&& ! permitted_reg_in_leaf_functions[i])
return 0;
- if (current_function_uses_pic_offset_table
+ if (crtl->uses_pic_offset_table
&& pic_offset_table_rtx != 0
&& REG_P (pic_offset_table_rtx)
&& ! permitted_reg_in_leaf_functions[REGNO (pic_offset_table_rtx)])
for (insn = first; insn; insn = NEXT_INSN (insn))
if (INSN_P (insn))
leaf_renumber_regs_insn (PATTERN (insn));
- for (insn = current_function_epilogue_delay_list;
+ for (insn = crtl->epilogue_delay_list;
insn;
insn = XEXP (insn, 1))
if (INSN_P (XEXP (insn, 0)))
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;
*will* be routed past here. */
timevar_push (TV_SYMOUT);
- (*debug_hooks->function_decl) (current_function_decl);
+ if (!DECL_IGNORED_P (current_function_decl))
+ debug_hooks->function_decl (current_function_decl);
timevar_pop (TV_SYMOUT);
+
+ /* Release the blocks that are linked to DECL_INITIAL() to free the memory. */
+ DECL_INITIAL (current_function_decl) = error_mark_node;
+
if (DECL_STATIC_CONSTRUCTOR (current_function_decl)
&& targetm.have_ctors_dtors)
targetm.asm_out.constructor (XEXP (DECL_RTL (current_function_decl), 0),
{
{
RTL_PASS,
- NULL, /* name */
+ "final", /* name */
NULL, /* gate */
rest_of_handle_final, /* execute */
NULL, /* sub */
rest_of_clean_state (void)
{
rtx insn, next;
+ FILE *final_output = NULL;
+ int save_unnumbered = flag_dump_unnumbered;
+ int save_noaddr = flag_dump_noaddr;
+
+ if (flag_dump_final_insns)
+ {
+ final_output = fopen (flag_dump_final_insns, "a");
+ if (!final_output)
+ {
+ error ("could not open final insn dump file %qs: %s",
+ flag_dump_final_insns, strerror (errno));
+ flag_dump_final_insns = NULL;
+ }
+ else
+ {
+ const char *aname;
+
+ aname = (IDENTIFIER_POINTER
+ (DECL_ASSEMBLER_NAME (current_function_decl)));
+ fprintf (final_output, "\n;; Function (%s) %s\n\n", aname,
+ cfun->function_frequency == FUNCTION_FREQUENCY_HOT
+ ? " (hot)"
+ : cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED
+ ? " (unlikely executed)"
+ : "");
+
+ flag_dump_noaddr = flag_dump_unnumbered = 1;
+ if (flag_compare_debug_opt || flag_compare_debug)
+ dump_flags |= TDF_NOUID;
+
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ if (LABEL_P (insn))
+ INSN_UID (insn) = CODE_LABEL_NUMBER (insn);
+ else
+ INSN_UID (insn) = 0;
+ }
+ }
/* It is very important to decompose the RTL instruction chain here:
debug information keeps pointing into CODE_LABEL insns inside the function
next = NEXT_INSN (insn);
NEXT_INSN (insn) = NULL;
PREV_INSN (insn) = NULL;
+
+ if (final_output
+ && (!NOTE_P (insn) ||
+ (NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION
+ && NOTE_KIND (insn) != NOTE_INSN_BLOCK_BEG
+ && NOTE_KIND (insn) != NOTE_INSN_BLOCK_END
+ && NOTE_KIND (insn) != NOTE_INSN_CFA_RESTORE_STATE)))
+ print_rtl_single (final_output, insn);
+
+ }
+
+ if (final_output)
+ {
+ flag_dump_noaddr = save_noaddr;
+ flag_dump_unnumbered = save_unnumbered;
+
+ if (fclose (final_output))
+ {
+ error ("could not close final insn dump file %qs: %s",
+ flag_dump_final_insns, strerror (errno));
+ flag_dump_final_insns = NULL;
+ }
}
/* In case the function was not output,
sdbout_types (NULL_TREE);
#endif
+ flag_rerun_cse_after_global_opts = 0;
reload_completed = 0;
epilogue_completed = 0;
#ifdef STACK_REGS
free_bb_for_insn ();
+ delete_tree_ssa ();
+
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;
}
{
{
RTL_PASS,
- NULL, /* name */
+ "*clean_state", /* name */
NULL, /* gate */
rest_of_clean_state, /* execute */
NULL, /* sub */
0 /* todo_flags_finish */
}
};
-