/* Convert RTL to assembler code and output it, for GNU compiler.
- Copyright (C) 1987-2015 Free Software Foundation, Inc.
+ Copyright (C) 1987-2017 Free Software Foundation, Inc.
This file is part of GCC.
function_epilogue. Those instructions never exist as rtl. */
#include "config.h"
+#define INCLUDE_ALGORITHM /* reverse */
#include "system.h"
#include "coretypes.h"
#include "backend.h"
-#include "cfghooks.h"
-#include "tree.h"
+#include "target.h"
#include "rtl.h"
+#include "tree.h"
+#include "cfghooks.h"
#include "df.h"
-#include "alias.h"
-#include "varasm.h"
+#include "memmodel.h"
#include "tm_p.h"
-#include "regs.h"
#include "insn-config.h"
-#include "insn-attr.h"
+#include "regs.h"
+#include "emit-rtl.h"
#include "recog.h"
+#include "cgraph.h"
+#include "tree-pretty-print.h" /* for dump_function_header */
+#include "varasm.h"
+#include "insn-attr.h"
#include "conditions.h"
#include "flags.h"
#include "output.h"
#include "reload.h"
#include "intl.h"
#include "cfgrtl.h"
-#include "target.h"
-#include "targhooks.h"
#include "debug.h"
-#include "expmed.h"
-#include "dojump.h"
-#include "explow.h"
-#include "calls.h"
-#include "emit-rtl.h"
-#include "stmt.h"
-#include "expr.h"
#include "tree-pass.h"
-#include "cgraph.h"
#include "tree-ssa.h"
-#include "coverage.h"
#include "cfgloop.h"
#include "params.h"
-#include "tree-pretty-print.h" /* for dump_function_header */
+#include "stringpool.h"
+#include "attribs.h"
#include "asan.h"
-#include "wide-int-print.h"
#include "rtl-iter.h"
#include "print-rtl.h"
#ifdef XCOFF_DEBUGGING_INFO
-#include "xcoffout.h" /* Needed for external data
- declarations for e.g. AIX 4.x. */
+#include "xcoffout.h" /* Needed for external data declarations. */
#endif
#include "dwarf2out.h"
#include "dbxout.h"
#endif
-#ifdef SDB_DEBUGGING_INFO
-#include "sdbout.h"
-#endif
-
/* Most ports that aren't using cc0 don't need to define CC_STATUS_INIT.
So define a null default for it to save conditionalization later. */
#ifndef CC_STATUS_INIT
/* Line number of last NOTE. */
static int last_linenum;
+/* Column number of last NOTE. */
+static int last_columnnum;
+
/* Last discriminator written to assembly. */
static int last_discriminator;
/* Filename of last NOTE. */
static const char *last_filename;
-/* Override filename and line number. */
+/* Override filename, line and column number. */
static const char *override_filename;
static int override_linenum;
+static int override_columnnum;
/* Whether to force emission of a line note before the next insn. */
static bool force_source_line = false;
#if HAVE_cc0
static int alter_cond (rtx);
#endif
-#ifndef ADDR_VEC_ALIGN
-static int final_addr_vec_align (rtx);
-#endif
static int align_fuzz (rtx, rtx, int, unsigned);
static void collect_fn_hard_reg_usage (void);
static tree get_call_fndecl (rtx_insn *);
If not overridden for epilogue code, then the function body itself
contains return instructions wherever needed. */
void
-default_function_pro_epilogue (FILE *file ATTRIBUTE_UNUSED,
- HOST_WIDE_INT size ATTRIBUTE_UNUSED)
+default_function_pro_epilogue (FILE *)
{
}
delayed branch sequence (we don't count the insn needing the
delay slot). Zero if not in a delayed branch sequence. */
-#ifdef DELAY_SLOTS
int
dbr_sequence_length (void)
{
else
return 0;
}
-#endif
\f
/* The next two pages contain routines used to compute the length of an insn
and to shorten branches. */
#ifndef ADDR_VEC_ALIGN
static int
-final_addr_vec_align (rtx addr_vec)
+final_addr_vec_align (rtx_jump_table_data *addr_vec)
{
- int align = GET_MODE_SIZE (GET_MODE (PATTERN (addr_vec)));
+ int align = GET_MODE_SIZE (addr_vec->get_data_mode ());
if (align > BIGGEST_ALIGNMENT / BITS_PER_UNIT)
align = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
if (INSN_P (insn))
continue;
- if (LABEL_P (insn))
+ if (rtx_code_label *label = dyn_cast <rtx_code_label *> (insn))
{
- rtx_insn *next;
- bool next_is_jumptable;
-
/* Merge in alignments computed by compute_alignments. */
- log = LABEL_TO_ALIGNMENT (insn);
+ log = LABEL_TO_ALIGNMENT (label);
if (max_log < log)
{
max_log = log;
- max_skip = LABEL_TO_MAX_SKIP (insn);
+ max_skip = LABEL_TO_MAX_SKIP (label);
}
- next = next_nonnote_insn (insn);
- next_is_jumptable = next && JUMP_TABLE_DATA_P (next);
- if (!next_is_jumptable)
+ rtx_jump_table_data *table = jump_table_for_label (label);
+ if (!table)
{
- log = LABEL_ALIGN (insn);
+ log = LABEL_ALIGN (label);
if (max_log < log)
{
max_log = log;
- max_skip = targetm.asm_out.label_align_max_skip (insn);
+ max_skip = targetm.asm_out.label_align_max_skip (label);
}
}
/* 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)
- && next_is_jumptable)
+ && table)
{
- log = ADDR_VEC_ALIGN (next);
+ log = ADDR_VEC_ALIGN (table);
if (max_log < log)
{
max_log = log;
- max_skip = targetm.asm_out.label_align_max_skip (insn);
+ max_skip = targetm.asm_out.label_align_max_skip (label);
}
}
- LABEL_TO_ALIGNMENT (insn) = max_log;
- LABEL_TO_MAX_SKIP (insn) = max_skip;
+ LABEL_TO_ALIGNMENT (label) = max_log;
+ LABEL_TO_MAX_SKIP (label) = max_skip;
max_log = 0;
max_skip = 0;
}
continue;
body = PATTERN (insn);
- if (JUMP_TABLE_DATA_P (insn))
+ if (rtx_jump_table_data *table = dyn_cast <rtx_jump_table_data *> (insn))
{
/* This only takes room if read-only data goes into the text
section. */
|| readonly_data_section == text_section)
insn_lengths[uid] = (XVECLEN (body,
GET_CODE (body) == ADDR_DIFF_VEC)
- * GET_MODE_SIZE (GET_MODE (body)));
+ * GET_MODE_SIZE (table->get_data_mode ()));
/* Alignment is handled by ADDR_VEC_ALIGN. */
}
else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0)
{
int i;
int const_delay_slots;
-#ifdef DELAY_SLOTS
- const_delay_slots = const_num_delay_slots (body_seq->insn (0));
-#else
- const_delay_slots = 0;
-#endif
+ if (DELAY_SLOTS)
+ const_delay_slots = const_num_delay_slots (body_seq->insn (0));
+ else
+ const_delay_slots = 0;
+
int (*inner_length_fun) (rtx_insn *)
= const_delay_slots ? length_fun : insn_default_length;
/* Inside a delay slot sequence, we do not do any branch shortening
int inner_uid = INSN_UID (inner_insn);
int inner_length;
- if (GET_CODE (body) == ASM_INPUT
+ if (GET_CODE (PATTERN (inner_insn)) == ASM_INPUT
|| asm_noperands (PATTERN (inner_insn)) >= 0)
inner_length = (asm_insn_count (PATTERN (inner_insn))
* insn_default_length (inner_insn));
uid = INSN_UID (insn);
- if (LABEL_P (insn))
+ if (rtx_code_label *label = dyn_cast <rtx_code_label *> (insn))
{
- int log = LABEL_TO_ALIGNMENT (insn);
+ int log = LABEL_TO_ALIGNMENT (label);
#ifdef CASE_VECTOR_SHORTEN_MODE
/* If the mode of a following jump table was changed, we
may need to update the alignment of this label. */
- rtx_insn *next;
- bool next_is_jumptable;
-
- next = next_nonnote_insn (insn);
- next_is_jumptable = next && JUMP_TABLE_DATA_P (next);
- if ((JUMP_TABLES_IN_TEXT_SECTION
- || readonly_data_section == text_section)
- && next_is_jumptable)
+
+ if (JUMP_TABLES_IN_TEXT_SECTION
+ || readonly_data_section == text_section)
{
- int newlog = ADDR_VEC_ALIGN (next);
- if (newlog != log)
+ rtx_jump_table_data *table = jump_table_for_label (label);
+ if (table)
{
- log = newlog;
- LABEL_TO_ALIGNMENT (insn) = log;
- something_changed = 1;
+ int newlog = ADDR_VEC_ALIGN (table);
+ if (newlog != log)
+ {
+ log = newlog;
+ LABEL_TO_ALIGNMENT (insn) = log;
+ something_changed = 1;
+ }
}
}
#endif
&& JUMP_TABLE_DATA_P (insn)
&& GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
{
+ rtx_jump_table_data *table = as_a <rtx_jump_table_data *> (insn);
rtx body = PATTERN (insn);
int old_length = insn_lengths[uid];
rtx_insn *rel_lab =
rtx_insn *prev;
int rel_align = 0;
addr_diff_vec_flags flags;
- machine_mode vec_mode;
+ scalar_int_mode vec_mode;
/* Avoid automatic aggregate initialization. */
flags = ADDR_DIFF_VEC_FLAGS (body);
max_addr - rel_addr, body);
if (!increasing
|| (GET_MODE_SIZE (vec_mode)
- >= GET_MODE_SIZE (GET_MODE (body))))
+ >= GET_MODE_SIZE (table->get_data_mode ())))
PUT_MODE (body, vec_mode);
if (JUMP_TABLES_IN_TEXT_SECTION
|| readonly_data_section == text_section)
{
insn_lengths[uid]
- = (XVECLEN (body, 1) * GET_MODE_SIZE (GET_MODE (body)));
+ = (XVECLEN (body, 1)
+ * GET_MODE_SIZE (table->get_data_mode ()));
insn_current_address += insn_lengths[uid];
if (insn_lengths[uid] != old_length)
something_changed = 1;
if (!increasing)
break;
}
-
+ crtl->max_insn_address = insn_current_address;
free (varying_length);
}
last_filename = LOCATION_FILE (prologue_location);
last_linenum = LOCATION_LINE (prologue_location);
+ last_columnnum = LOCATION_COLUMN (prologue_location);
last_discriminator = discriminator = 0;
high_block_linenum = high_function_linenum = last_linenum;
asan_function_start ();
if (!DECL_IGNORED_P (current_function_decl))
- debug_hooks->begin_prologue (last_linenum, last_filename);
+ debug_hooks->begin_prologue (last_linenum, last_columnnum, last_filename);
if (!dwarf2_debug_info_emitted_p (current_function_decl))
- dwarf2out_begin_prologue (0, NULL);
+ dwarf2out_begin_prologue (0, 0, NULL);
#ifdef LEAF_REG_REMAP
if (crtl->uses_only_leaf_regs)
}
/* First output the function prologue: code to set up the stack frame. */
- targetm.asm_out.function_prologue (file, get_frame_size ());
+ targetm.asm_out.function_prologue (file);
/* If the machine represents the prologue as RTL, the profiling code must
be emitted when NOTE_INSN_PROLOGUE_END is scanned. */
/* 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 ());
+ targetm.asm_out.function_epilogue (asm_out_file);
/* And debug output. */
if (!DECL_IGNORED_P (current_function_decl))
fprintf (file, "%s BLOCK %d", ASM_COMMENT_START, bb->index);
if (bb->frequency)
fprintf (file, " freq:%d", bb->frequency);
- if (bb->count)
- fprintf (file, " count:%" PRId64,
- bb->count);
+ if (bb->count.initialized_p ())
+ {
+ fprintf (file, ", count:");
+ bb->count.dump (file);
+ }
fprintf (file, " seq:%d", (*bb_seqn)++);
fprintf (file, "\n%s PRED:", ASM_COMMENT_START);
FOR_EACH_EDGE (e, ei, bb->preds)
case LABEL_WEAK_ENTRY:
#ifdef ASM_WEAKEN_LABEL
ASM_WEAKEN_LABEL (file, name);
+ gcc_fallthrough ();
#endif
case LABEL_GLOBAL_ENTRY:
targetm.asm_out.globalize_label (file, name);
+ gcc_fallthrough ();
case LABEL_STATIC_ENTRY:
#ifdef ASM_OUTPUT_TYPE_DIRECTIVE
ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
return x;
}
+/* Print a comment into the asm showing FILENAME, LINENUM, and the
+ corresponding source line, if available. */
+
+static void
+asm_show_source (const char *filename, int linenum)
+{
+ if (!filename)
+ return;
+
+ int line_size;
+ const char *line = location_get_source_line (filename, linenum, &line_size);
+ if (!line)
+ return;
+
+ fprintf (asm_out_file, "%s %s:%i: ", ASM_COMMENT_START, filename, linenum);
+ /* "line" is not 0-terminated, so we must use line_size. */
+ fwrite (line, 1, line_size, asm_out_file);
+ fputc ('\n', asm_out_file);
+}
+
/* The final scan for one insn, INSN.
Args are same as in `final', except that INSN
is the insn being scanned.
rtx set;
#endif
rtx_insn *next;
+ rtx_jump_table_data *table;
insn_counter++;
/* Mark this block as output. */
TREE_ASM_WRITTEN (NOTE_BLOCK (insn)) = 1;
+ BLOCK_IN_COLD_SECTION_P (NOTE_BLOCK (insn)) = in_cold_section_p;
}
- if (write_symbols == DBX_DEBUG
- || write_symbols == SDB_DEBUG)
+ if (write_symbols == DBX_DEBUG)
{
location_t *locus_ptr
= block_nonartificial_location (NOTE_BLOCK (insn));
{
override_filename = LOCATION_FILE (*locus_ptr);
override_linenum = LOCATION_LINE (*locus_ptr);
+ override_columnnum = LOCATION_COLUMN (*locus_ptr);
}
}
break;
if (!DECL_IGNORED_P (current_function_decl))
debug_hooks->end_block (high_block_linenum, n);
+ gcc_assert (BLOCK_IN_COLD_SECTION_P (NOTE_BLOCK (insn))
+ == in_cold_section_p);
}
- if (write_symbols == DBX_DEBUG
- || write_symbols == SDB_DEBUG)
+ if (write_symbols == DBX_DEBUG)
{
tree outer_block = BLOCK_SUPERCONTEXT (NOTE_BLOCK (insn));
location_t *locus_ptr
{
override_filename = LOCATION_FILE (*locus_ptr);
override_linenum = LOCATION_LINE (*locus_ptr);
+ override_columnnum = LOCATION_COLUMN (*locus_ptr);
}
else
{
override_filename = NULL;
override_linenum = 0;
+ override_columnnum = 0;
}
}
break;
app_disable ();
- next = next_nonnote_insn (insn);
/* 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))
+ table = jump_table_for_label (as_a <rtx_code_label *> (insn));
+ if (table)
{
#if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)
/* In this case, the case vector is being moved by the
(current_function_decl));
#ifdef ADDR_VEC_ALIGN
- log_align = ADDR_VEC_ALIGN (next);
+ log_align = ADDR_VEC_ALIGN (table);
#else
log_align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
#endif
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), table);
#else
targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (insn));
#endif
note in a row. */
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 (flag_verbose_asm)
+ asm_show_source (last_filename, last_linenum);
+ (*debug_hooks->source_line) (last_linenum, last_columnnum,
+ last_filename, last_discriminator,
+ is_stmt);
+ }
+
+ if (GET_CODE (body) == PARALLEL
+ && GET_CODE (XVECEXP (body, 0, 0)) == ASM_INPUT)
+ body = XVECEXP (body, 0, 0);
if (GET_CODE (body) == ASM_INPUT)
{
&& targetm.asm_out.unwind_emit)
targetm.asm_out.unwind_emit (asm_out_file, insn);
- if (rtx_call_insn *call_insn = dyn_cast <rtx_call_insn *> (insn))
+ rtx_call_insn *call_insn = dyn_cast <rtx_call_insn *> (insn);
+ if (call_insn != NULL)
{
rtx x = call_from_call_insn (call_insn);
x = XEXP (x, 0);
if (t)
assemble_external (t);
}
- if (!DECL_IGNORED_P (current_function_decl))
- debug_hooks->var_location (insn);
}
/* Output assembler code from the template. */
&& targetm.asm_out.unwind_emit)
targetm.asm_out.unwind_emit (asm_out_file, insn);
+ /* Let the debug info back-end know about this call. We do this only
+ after the instruction has been emitted because labels that may be
+ created to reference the call instruction must appear after it. */
+ if (call_insn != NULL && !DECL_IGNORED_P (current_function_decl))
+ debug_hooks->var_location (insn);
+
current_output_insn = debug_insn = 0;
}
}
notice_source_line (rtx_insn *insn, bool *is_stmt)
{
const char *filename;
- int linenum;
+ int linenum, columnnum;
if (override_filename)
{
filename = override_filename;
linenum = override_linenum;
+ columnnum = override_columnnum;
}
else if (INSN_HAS_LOCATION (insn))
{
expanded_location xloc = insn_location (insn);
filename = xloc.file;
linenum = xloc.line;
+ columnnum = xloc.column;
}
else
{
filename = NULL;
linenum = 0;
+ columnnum = 0;
}
if (filename == NULL)
if (force_source_line
|| filename != last_filename
- || last_linenum != linenum)
+ || last_linenum != linenum
+ || (debug_column_info && last_columnnum != columnnum))
{
force_source_line = false;
last_filename = filename;
last_linenum = linenum;
+ last_columnnum = columnnum;
last_discriminator = discriminator;
*is_stmt = true;
high_block_linenum = MAX (last_linenum, high_block_linenum);
/* 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;
- }
+ if (paradoxical_subreg_p (x))
+ offset = byte_lowpart_offset (GET_MODE (x), GET_MODE (y));
if (final_p)
*xp = adjust_address (y, GET_MODE (x), offset);
else if (letter == 'l')
output_asm_label (operands[opnum]);
else if (letter == 'a')
- output_address (operands[opnum]);
+ output_address (VOIDmode, operands[opnum]);
else if (letter == 'c')
{
if (CONSTANT_ADDRESS_P (operands[opnum]))
char buf[256];
if (GET_CODE (x) == LABEL_REF)
- x = LABEL_REF_LABEL (x);
+ x = label_ref_label (x);
if (LABEL_P (x)
|| (NOTE_P (x)
&& NOTE_KIND (x) == NOTE_INSN_DELETED_LABEL))
machine-dependent assembler syntax. */
void
-output_address (rtx x)
+output_address (machine_mode mode, rtx x)
{
bool changed = false;
walk_alter_subreg (&x, &changed);
- targetm.asm_out.print_operand_address (asm_out_file, x);
+ targetm.asm_out.print_operand_address (asm_out_file, mode, x);
}
\f
/* Print an integer constant expression in assembler syntax.
break;
case LABEL_REF:
- x = LABEL_REF_LABEL (x);
+ x = label_ref_label (x);
/* Fall through. */
case CODE_LABEL:
ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
{
rtx_insn *insn;
+ /* Ensure we walk the entire function body. */
+ gcc_assert (!in_sequence_p ());
+
/* Some back-ends (e.g. s390) want leaf functions to stay leaf
functions even if they call mcount. */
if (crtl->profile && !targetm.keep_leaf_when_profiled ())
assemble_start_function (current_function_decl, fnname);
final_start_function (get_insns (), asm_out_file, optimize);
final (get_insns (), asm_out_file, optimize);
- if (flag_ipa_ra)
+ if (flag_ipa_ra
+ && !lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl)))
collect_fn_hard_reg_usage ();
final_end_function ();
assemble_end_function (current_function_decl, fnname);
- user_defined_section_attribute = false;
-
/* Free up reg info memory. */
free_reg_info ();
}
}
- /* 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
-
flag_rerun_cse_after_global_opts = 0;
reload_completed = 0;
epilogue_completed = 0;
free_bb_for_insn ();
- delete_tree_ssa ();
+ if (cfun->gimple_df)
+ delete_tree_ssa (cfun);
/* We can reduce stack alignment on call site only when we are sure that
the function body just produced will be actually used in the final