/* 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
+ 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
+ 2010, 2011
Free Software Foundation, Inc.
This file is part of GCC.
#include "recog.h"
#include "conditions.h"
#include "flags.h"
-#include "real.h"
#include "hard-reg-set.h"
#include "output.h"
#include "except.h"
#include "function.h"
-#include "toplev.h"
+#include "rtl-error.h"
+#include "toplev.h" /* exact_log2, floor_log2 */
#include "reload.h"
#include "intl.h"
#include "basic-block.h"
#include "target.h"
+#include "targhooks.h"
#include "debug.h"
#include "expr.h"
#include "cfglayout.h"
#include "tree-pass.h"
+#include "tree-flow.h"
#include "timevar.h"
#include "cgraph.h"
#include "coverage.h"
declarations for e.g. AIX 4.x. */
#endif
-#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
#include "dwarf2out.h"
-#endif
#ifdef DBX_DEBUGGING_INFO
#include "dbxout.h"
#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. */
+/* 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
#define CC_STATUS_INIT
#endif
/* 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
+
+/* True if printing into -fdump-final-insns= dump. */
+bool final_insns_dump_p;
#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);
static tree get_mem_expr_from_op (rtx, int *);
static void output_asm_operand_names (rtx *, int *, int);
-static void output_operand (rtx, int);
#ifdef LEAF_REGISTERS
static void leaf_renumber_regs (rtx);
#endif
{
}
+void
+default_function_switched_text_sections (FILE *file ATTRIBUTE_UNUSED,
+ tree decl ATTRIBUTE_UNUSED,
+ bool new_is_cold ATTRIBUTE_UNUSED)
+{
+}
+
/* Default target hook that outputs nothing to a stream. */
void
no_asm_to_stream (FILE *file ATTRIBUTE_UNUSED)
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;
#define LABEL_ALIGN(LABEL) align_labels_log
#endif
-#ifndef LABEL_ALIGN_MAX_SKIP
-#define LABEL_ALIGN_MAX_SKIP align_labels_max_skip
-#endif
-
#ifndef LOOP_ALIGN
#define LOOP_ALIGN(LABEL) align_loops_log
#endif
-#ifndef LOOP_ALIGN_MAX_SKIP
-#define LOOP_ALIGN_MAX_SKIP align_loops_max_skip
-#endif
-
#ifndef LABEL_ALIGN_AFTER_BARRIER
#define LABEL_ALIGN_AFTER_BARRIER(LABEL) 0
#endif
-#ifndef LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP
-#define LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP 0
-#endif
-
#ifndef JUMP_ALIGN
#define JUMP_ALIGN(LABEL) align_jumps_log
#endif
-#ifndef JUMP_ALIGN_MAX_SKIP
-#define JUMP_ALIGN_MAX_SKIP align_jumps_max_skip
-#endif
+int
+default_label_align_after_barrier_max_skip (rtx insn ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+int
+default_loop_align_max_skip (rtx insn ATTRIBUTE_UNUSED)
+{
+ return align_loops_max_skip;
+}
+
+int
+default_label_align_max_skip (rtx insn ATTRIBUTE_UNUSED)
+{
+ return align_labels_max_skip;
+}
+
+int
+default_jump_align_max_skip (rtx insn ATTRIBUTE_UNUSED)
+{
+ return align_jumps_max_skip;
+}
#ifndef ADDR_VEC_ALIGN
static int
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)
{
dump_flow_info (dump_file, TDF_DETAILS);
flow_loops_dump (dump_file, NULL, 1);
- loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
}
+ loop_optimizer_init (AVOID_CFG_MODIFICATIONS);
FOR_EACH_BB (bb)
if (bb->frequency > freq_max)
freq_max = bb->frequency;
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",
continue;
}
max_log = LABEL_ALIGN (label);
- max_skip = LABEL_ALIGN_MAX_SKIP;
+ max_skip = targetm.asm_out.label_align_max_skip (label);
FOR_EACH_EDGE (e, ei, bb->preds)
{
if (max_log < log)
{
max_log = log;
- max_skip = JUMP_ALIGN_MAX_SKIP;
+ max_skip = targetm.asm_out.jump_align_max_skip (label);
}
}
/* 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 (max_log < log)
{
max_log = log;
- max_skip = LOOP_ALIGN_MAX_SKIP;
+ max_skip = targetm.asm_out.loop_align_max_skip (label);
}
}
LABEL_TO_ALIGNMENT (label) = max_log;
LABEL_TO_MAX_SKIP (label) = max_skip;
}
- if (dump_file)
- loop_optimizer_finalize ();
+ loop_optimizer_finalize ();
+ free_dominance_info (CDI_DOMINATORS);
return 0;
}
-struct tree_opt_pass pass_compute_alignments =
+struct rtl_opt_pass pass_compute_alignments =
{
+ {
+ RTL_PASS,
"alignments", /* name */
NULL, /* gate */
compute_alignments, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
- 0, /* tv_id */
+ TV_NONE, /* tv_id */
0, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func | TODO_verify_rtl_sharing
- | TODO_ggc_collect, /* todo_flags_finish */
- 0 /* letter */
+ | TODO_ggc_collect /* todo_flags_finish */
+ }
};
\f
n_labels = max_labelno - min_labelno + 1;
n_old_labels = old - min_labelno + 1;
- label_align = xrealloc (label_align,
- n_labels * sizeof (struct label_alignment));
+ label_align = XRESIZEVEC (struct label_alignment, label_align, n_labels);
/* Range of labels grows monotonically in the function. Failing here
means that the initialization of array got lost. */
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 = targetm.asm_out.label_align_max_skip (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
- || 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 = targetm.asm_out.label_align_max_skip (insn);
+ }
+ }
LABEL_TO_ALIGNMENT (insn) = max_log;
LABEL_TO_MAX_SKIP (insn) = max_skip;
max_log = 0;
if (max_log < log)
{
max_log = log;
- max_skip = LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP;
+ max_skip = targetm.asm_out.label_align_after_barrier_max_skip (label);
}
break;
}
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);
- for (; *template; template++)
- if (IS_ASM_LOGICAL_LINE_SEPARATOR (*template, template)
- || *template == '\n')
+ return asm_str_count (templ);
+}
+#endif
+
+/* 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;
size_t name_len;
for (map = debug_prefix_maps; map; map = map->next)
- if (strncmp (filename, map->old_prefix, map->old_len) == 0)
+ if (filename_ncmp (filename, map->old_prefix, map->old_len) == 0)
break;
if (!map)
return filename;
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
FIRST is the first insn of the rtl for the function being compiled.
FILE is the file to write assembler code to.
- OPTIMIZE is nonzero if we should eliminate redundant
+ OPTIMIZE_P is nonzero if we should eliminate redundant
test and compare insns. */
void
final_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file,
- int optimize ATTRIBUTE_UNUSED)
+ int optimize_p ATTRIBUTE_UNUSED)
{
block_depth = 0;
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
#ifdef LEAF_REG_REMAP
if (current_function_uses_only_leaf_regs)
/* 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 (targetm.profile_before_prologue () && crtl->profile)
profile_function (file);
-#endif /* PROFILE_BEFORE_PROLOGUE */
-#if defined (DWARF2_UNWIND_INFO) && defined (HAVE_prologue)
+#if defined (HAVE_prologue)
if (dwarf2out_do_frame ())
- dwarf2out_frame_debug (NULL_RTX, false);
+ dwarf2out_frame_debug_init ();
#endif
/* If debugging, assign block numbers to all of the blocks in this
TREE_ASM_WRITTEN (DECL_INITIAL (current_function_decl)) = 1;
}
+ if (warn_frame_larger_than
+ && get_frame_size () > frame_larger_than_size)
+ {
+ /* Issue a warning */
+ warning (OPT_Wframe_larger_than_,
+ "the frame size of %wd bytes is larger than %wd bytes",
+ get_frame_size (), frame_larger_than_size);
+ }
+
/* First output the function prologue: code to set up the stack frame. */
targetm.asm_out.function_prologue (file, get_frame_size ());
static void
profile_after_prologue (FILE *file ATTRIBUTE_UNUSED)
{
-#ifndef PROFILE_BEFORE_PROLOGUE
- if (current_function_profile)
+ if (!targetm.profile_before_prologue () && crtl->profile)
profile_function (file);
-#endif /* not PROFILE_BEFORE_PROLOGUE */
}
static void
#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
}
\f
+
+/* Dumper helper for basic block information. FILE is the assembly
+ output file, and INSN is the instruction being emitted. */
+
+static void
+dump_basic_block_info (FILE *file, rtx insn, basic_block *start_to_bb,
+ basic_block *end_to_bb, int bb_map_size, int *bb_seqn)
+{
+ basic_block bb;
+
+ if (!flag_debug_asm)
+ return;
+
+ if (INSN_UID (insn) < bb_map_size
+ && (bb = start_to_bb[INSN_UID (insn)]) != NULL)
+ {
+ edge e;
+ edge_iterator ei;
+
+ 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:" HOST_WIDEST_INT_PRINT_DEC,
+ bb->count);
+ fprintf (file, " seq:%d", (*bb_seqn)++);
+ fprintf (file, "\n%s PRED:", ASM_COMMENT_START);
+ FOR_EACH_EDGE (e, ei, bb->preds)
+ {
+ dump_edge_info (file, e, 0);
+ }
+ fprintf (file, "\n");
+ }
+ if (INSN_UID (insn) < bb_map_size
+ && (bb = end_to_bb[INSN_UID (insn)]) != NULL)
+ {
+ edge e;
+ edge_iterator ei;
+
+ fprintf (asm_out_file, "%s SUCC:", ASM_COMMENT_START);
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ {
+ dump_edge_info (asm_out_file, e, 1);
+ }
+ fprintf (file, "\n");
+ }
+}
+
/* Output assembler code for some insns: all or part of a function.
For description of args, see `final_start_function', above. */
void
-final (rtx first, FILE *file, int optimize)
+final (rtx first, FILE *file, int optimize_p)
{
rtx insn;
int max_uid = 0;
int seen = 0;
+ /* Used for -dA dump. */
+ basic_block *start_to_bb = NULL;
+ basic_block *end_to_bb = NULL;
+ int bb_map_size = 0;
+ int bb_seqn = 0;
+
last_ignored_compare = 0;
for (insn = first; insn; insn = NEXT_INSN (insn))
#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 && JUMP_P (insn))
+ if (optimize_p && JUMP_P (insn))
{
rtx lab = JUMP_LABEL (insn);
if (lab && LABEL_NUSES (lab) == 1)
CC_STATUS_INIT;
+ if (flag_debug_asm)
+ {
+ basic_block bb;
+
+ bb_map_size = get_max_uid () + 1;
+ start_to_bb = XCNEWVEC (basic_block, bb_map_size);
+ end_to_bb = XCNEWVEC (basic_block, bb_map_size);
+
+ FOR_EACH_BB_REVERSE (bb)
+ {
+ start_to_bb[INSN_UID (BB_HEAD (bb))] = bb;
+ end_to_bb[INSN_UID (BB_END (bb))] = bb;
+ }
+ }
+
/* Output the insns. */
for (insn = first; insn;)
{
insn_current_address = INSN_ADDRESSES (INSN_UID (insn));
#endif /* HAVE_ATTR_length */
- insn = final_scan_insn (insn, file, optimize, 0, &seen);
+ dump_basic_block_info (file, insn, start_to_bb, end_to_bb,
+ bb_map_size, &bb_seqn);
+ insn = final_scan_insn (insn, file, optimize_p, 0, &seen);
+ }
+
+ if (flag_debug_asm)
+ {
+ free (start_to_bb);
+ free (end_to_bb);
}
}
\f
}
}
+/* 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.
first. */
rtx
-final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
+final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
int nopeepholes ATTRIBUTE_UNUSED, int *seen)
{
#ifdef HAVE_cc0
case NOTE_INSN_SWITCH_TEXT_SECTIONS:
in_cold_section_p = !in_cold_section_p;
-#ifdef DWARF2_UNWIND_INFO
+
if (dwarf2out_do_frame ())
dwarf2out_switch_text_section ();
- else
-#endif
- (*debug_hooks->switch_text_section) ();
+ else if (!DECL_IGNORED_P (current_function_decl))
+ debug_hooks->switch_text_section ();
switch_to_section (current_function_section ());
+ targetm.asm_out.function_switched_text_sections (asm_out_file,
+ current_function_decl,
+ in_cold_section_p);
break;
case NOTE_INSN_BASIC_BLOCK:
-#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 (targetm.asm_out.unwind_emit)
+ targetm.asm_out.unwind_emit (asm_out_file, insn);
if ((*seen & (SEEN_EMITTED | SEEN_BB)) == SEEN_BB)
{
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 (HAVE_epilogue)
+ if (dwarf2out_do_frame ())
+ dwarf2out_cfi_begin_epilogue (insn);
+#endif
+ (*debug_hooks->begin_epilogue) (last_linenum, last_filename);
targetm.asm_out.function_begin_epilogue (file);
break;
+ case NOTE_INSN_CFA_RESTORE_STATE:
+ dwarf2out_frame_debug_restore_state ();
+ 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);
+ case NOTE_INSN_CALL_ARG_LOCATION:
+ if (!DECL_IGNORED_P (current_function_decl))
+ debug_hooks->var_location (insn);
break;
default:
break;
case BARRIER:
-#if defined (DWARF2_UNWIND_INFO)
if (dwarf2out_do_frame ())
dwarf2out_frame_debug (insn, false);
-#endif
break;
case CODE_LABEL:
#endif
}
}
-#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 (!DECL_IGNORED_P (current_function_decl) && LABEL_NAME (insn))
+ debug_hooks->label (insn);
- if (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;
- }
-#ifdef USE_MAPPED_LOCATION
+ app_enable ();
loc = expand_location (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);
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;
+ /* Make sure we flush any queued register saves in case this
+ clobbers affected registers. */
+ if (dwarf2out_do_frame ())
+ dwarf2out_frame_debug (insn, false);
+
/* There's no telling what that did to the condition codes. */
CC_STATUS_INIT;
/* Get out the operand values. */
string = decode_asm_operands (body, ops, NULL, NULL, NULL, &loc);
- /* Inhibit dieing on what would otherwise be compiler bugs. */
+ /* Inhibit dying on what would otherwise be compiler bugs. */
insn_noperands = noperands;
this_is_asm_operands = insn;
expanded = expand_location (loc);
/* 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)
{
/* Record the delay slots' frame information before the branch.
This is needed for delayed calls: see execute_cfa_program(). */
-#if defined (DWARF2_UNWIND_INFO)
if (dwarf2out_do_frame ())
for (i = 1; i < XVECLEN (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
force the restoration of a comparison that was previously
and the next statement should reexamine the variable
to compute the condition codes. */
- if (optimize)
+ if (optimize_p)
{
if (set
&& 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
#ifdef HAVE_peephole
/* Do machine-specific peephole optimizations if desired. */
- if (optimize && !flag_no_peephole && !nopeepholes)
+ if (optimize_p && !flag_no_peephole && !nopeepholes)
{
rtx next = peephole (insn);
/* When peepholing, if there were notes within the peephole,
for (note = NEXT_INSN (insn); note != next;
note = NEXT_INSN (note))
- final_scan_insn (note, file, optimize, nopeepholes, seen);
+ final_scan_insn (note, file, optimize_p, nopeepholes, seen);
/* Put the notes in the proper position for a later
rescan. For example, the SH target can do this
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;
current_output_insn = debug_insn = insn;
-#if defined (DWARF2_UNWIND_INFO)
if (CALL_P (insn) && dwarf2out_do_frame ())
dwarf2out_frame_debug (insn, false);
-#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
/* ??? 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
+ if (targetm.asm_out.unwind_emit_before_insn
+ && targetm.asm_out.unwind_emit)
+ targetm.asm_out.unwind_emit (asm_out_file, insn);
+
+ 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);
+ }
+ if (!DECL_IGNORED_P (current_function_decl))
+ debug_hooks->var_location (insn);
+ }
/* Output assembler code from the template. */
- output_asm_insn (template, recog_data.operand);
+ output_asm_insn (templ, recog_data.operand);
+
+ /* 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
and call instructions. */
-#if defined (DWARF2_UNWIND_INFO)
if (final_sequence == 0
#if !defined (HAVE_prologue)
&& !ACCUMULATE_OUTGOING_ARGS
#endif
&& dwarf2out_do_frame ())
dwarf2out_frame_debug (insn, true);
-#endif
+
+ if (!targetm.asm_out.unwind_emit_before_insn
+ && targetm.asm_out.unwind_emit)
+ targetm.asm_out.unwind_emit (asm_out_file, insn);
current_output_insn = debug_insn = 0;
}
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
outputs an operand in a special way depending on the letter.
Letters `acln' are implemented directly.
Other letters are passed to `output_operand' so that
- the PRINT_OPERAND macro can define them. */
+ the TARGET_PRINT_OPERAND hook can define them. */
else if (ISALPHA (*p))
{
int letter = *p++;
}
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
c = *p;
}
/* % followed by punctuation: output something for that
- punctuation character alone, with no operand.
- The PRINT_OPERAND macro decides what is actually done. */
-#ifdef PRINT_OPERAND_PUNCT_VALID_P
- else if (PRINT_OPERAND_PUNCT_VALID_P ((unsigned char) *p))
+ punctuation character alone, with no operand. The
+ TARGET_PRINT_OPERAND hook decides what is actually done. */
+ else if (targetm.asm_out.print_operand_punct_valid_p ((unsigned char) *p))
output_operand (NULL_RTX, *p++);
-#endif
else
output_operand_lossage ("invalid %%-code");
break;
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,
such as 'z' if the spec was `%z3'. CODE is 0 if there was no char
between the % and the digits.
When CODE is a non-letter, X is 0.
The meanings of the letters are machine-dependent and controlled
- by PRINT_OPERAND. */
+ by TARGET_PRINT_OPERAND. */
-static void
+void
output_operand (rtx x, int code ATTRIBUTE_UNUSED)
{
if (x && GET_CODE (x) == SUBREG)
/* 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);
+ targetm.asm_out.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
- using machine-dependent assembler syntax.
- The macro PRINT_OPERAND_ADDRESS exists just to control this function. */
+/* Print a memory reference operand for address X using
+ machine-dependent assembler syntax. */
void
output_address (rtx x)
{
bool changed = false;
walk_alter_subreg (&x, &changed);
- PRINT_OPERAND_ADDRESS (asm_out_file, x);
+ targetm.asm_out.print_operand_address (asm_out_file, x);
}
\f
/* Print an integer constant expression in assembler syntax.
case SYMBOL_REF:
if (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));
case ZERO_EXTEND:
case SIGN_EXTEND:
case SUBREG:
+ case TRUNCATE:
output_addr_const (file, XEXP (x, 0));
break;
default:
-#ifdef OUTPUT_ADDR_CONST_EXTRA
- OUTPUT_ADDR_CONST_EXTRA (file, x, fail);
- break;
+ if (targetm.asm_out.output_addr_const_extra (file, x))
+ break;
- fail:
-#endif
output_operand_lossage ("invalid expression as operand");
}
}
\f
+/* Output a quoted string. */
+
+void
+output_quoted_string (FILE *asm_file, const char *string)
+{
+#ifdef OUTPUT_QUOTED_STRING
+ OUTPUT_QUOTED_STRING (asm_file, string);
+#else
+ char c;
+
+ putc ('\"', asm_file);
+ while ((c = *string++) != 0)
+ {
+ if (ISPRINT (c))
+ {
+ if (c == '\"' || c == '\\')
+ putc ('\\', asm_file);
+ putc (c, asm_file);
+ }
+ else
+ fprintf (asm_file, "\\%03o", (unsigned char) c);
+ }
+ putc ('\"', asm_file);
+#endif
+}
+\f
/* A poor man's fprintf, with the added features of %I, %R, %L, and %U.
%R prints the value of REGISTER_PREFIX.
%L prints the value of LOCAL_LABEL_PREFIX.
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))
{
Sign extend each half to HOST_WIDE_INT. */
unsigned HOST_WIDE_INT low, high;
unsigned HOST_WIDE_INT mask, sign_bit, sign_extend;
+ unsigned bits_per_word = BITS_PER_WORD;
/* Set sign_bit to the most significant bit of a word. */
sign_bit = 1;
- sign_bit <<= BITS_PER_WORD - 1;
+ sign_bit <<= bits_per_word - 1;
/* Set mask so that all bits of the word are set. We could
have used 1 << BITS_PER_WORD instead of basing the
/* Pick the higher word, shifted to the least significant
bits, and sign-extend it. */
high = INTVAL (value);
- high >>= BITS_PER_WORD - 1;
+ high >>= bits_per_word - 1;
high >>= 1;
high &= mask;
if (high & sign_bit)
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)))
}
}
#endif
-
-
-/* When -gused is used, emit debug info for only used symbols. But in
- addition to the standard intercepted debug_hooks there are some direct
- calls into this file, i.e., dbxout_symbol, dbxout_parms, and dbxout_reg_params.
- Those routines may also be called from a higher level intercepted routine. So
- to prevent recording data for an inner call to one of these for an intercept,
- we maintain an intercept nesting counter (debug_nesting). We only save the
- intercepted arguments if the nesting is 1. */
-int debug_nesting = 0;
-
-static tree *symbol_queue;
-int symbol_queue_index = 0;
-static int symbol_queue_size = 0;
-
-/* Generate the symbols for any queued up type symbols we encountered
- while generating the type info for some originally used symbol.
- This might generate additional entries in the queue. Only when
- the nesting depth goes to 0 is this routine called. */
-
-void
-debug_flush_symbol_queue (void)
-{
- int i;
-
- /* Make sure that additionally queued items are not flushed
- prematurely. */
-
- ++debug_nesting;
-
- for (i = 0; i < symbol_queue_index; ++i)
- {
- /* 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
- which may be set for outside reasons. */
- int saved_tree_used = TREE_USED (symbol_queue[i]);
- int saved_suppress_debug = TYPE_DECL_SUPPRESS_DEBUG (symbol_queue[i]);
- TREE_USED (symbol_queue[i]) = 1;
- TYPE_DECL_SUPPRESS_DEBUG (symbol_queue[i]) = 0;
-
-#ifdef DBX_DEBUGGING_INFO
- dbxout_symbol (symbol_queue[i], 0);
-#endif
-
- TREE_USED (symbol_queue[i]) = saved_tree_used;
- TYPE_DECL_SUPPRESS_DEBUG (symbol_queue[i]) = saved_suppress_debug;
- }
-
- symbol_queue_index = 0;
- --debug_nesting;
-}
-
-/* Queue a type symbol needed as part of the definition of a decl
- symbol. These symbols are generated when debug_flush_symbol_queue()
- is called. */
-
-void
-debug_queue_symbol (tree decl)
-{
- if (symbol_queue_index >= symbol_queue_size)
- {
- symbol_queue_size += 10;
- symbol_queue = xrealloc (symbol_queue,
- symbol_queue_size * sizeof (tree));
- }
-
- symbol_queue[symbol_queue_index++] = decl;
-}
-
-/* Free symbol queue. */
-void
-debug_free_queue (void)
-{
- if (symbol_queue)
- {
- free (symbol_queue);
- symbol_queue = NULL;
- symbol_queue_size = 0;
- }
-}
\f
/* Turn the RTL into assembly. */
static unsigned int
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. */
+ /* The IA-64 ".handlerdata" directive must be issued before the ".endp"
+ directive that closes the procedure descriptor. Similarly, for x64 SEH.
+ Otherwise it's not strictly necessary, but it doesn't hurt either. */
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;
/* Free up reg info memory. */
*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),
return 0;
}
-struct tree_opt_pass pass_final =
+struct rtl_opt_pass pass_final =
{
- NULL, /* name */
+ {
+ RTL_PASS,
+ "final", /* name */
NULL, /* gate */
rest_of_handle_final, /* execute */
NULL, /* sub */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_ggc_collect, /* todo_flags_finish */
- 0 /* letter */
+ TODO_ggc_collect /* todo_flags_finish */
+ }
};
return 0;
}
-struct tree_opt_pass pass_shorten_branches =
+struct rtl_opt_pass pass_shorten_branches =
{
+ {
+ RTL_PASS,
"shorten", /* name */
NULL, /* gate */
rest_of_handle_shorten_branches, /* execute */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_dump_func, /* todo_flags_finish */
- 0 /* letter */
+ TODO_dump_func /* todo_flags_finish */
+ }
};
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: %m",
+ flag_dump_final_insns);
+ flag_dump_final_insns = NULL;
+ }
+ else
+ {
+ const char *aname;
+ struct cgraph_node *node = cgraph_get_node (current_function_decl);
+
+ aname = (IDENTIFIER_POINTER
+ (DECL_ASSEMBLER_NAME (current_function_decl)));
+ fprintf (final_output, "\n;; Function (%s) %s\n\n", aname,
+ node->frequency == NODE_FREQUENCY_HOT
+ ? " (hot)"
+ : node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED
+ ? " (unlikely executed)"
+ : node->frequency == NODE_FREQUENCY_EXECUTED_ONCE
+ ? " (executed once)"
+ : "");
+
+ flag_dump_noaddr = flag_dump_unnumbered = 1;
+ if (flag_compare_debug_opt || flag_compare_debug)
+ dump_flags |= TDF_NOUID;
+ final_insns_dump_p = true;
+
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ if (LABEL_P (insn))
+ INSN_UID (insn) = CODE_LABEL_NUMBER (insn);
+ else
+ {
+ if (NOTE_P (insn))
+ set_block_for_insn (insn, NULL);
+ 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_CALL_ARG_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;
+ final_insns_dump_p = false;
+
+ if (fclose (final_output))
+ {
+ error ("could not close final insn dump file %qs: %m",
+ flag_dump_final_insns);
+ 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 ();
- if (targetm.binds_local_p (current_function_decl))
+ delete_tree_ssa ();
+
+ /* 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
+ executable. */
+ if (decl_binds_to_current_def_p (current_function_decl))
{
- int pref = cfun->preferred_stack_boundary;
- if (cfun->stack_alignment_needed > cfun->preferred_stack_boundary)
- pref = cfun->stack_alignment_needed;
+ unsigned int pref = crtl->preferred_stack_boundary;
+ if (crtl->stack_alignment_needed > crtl->preferred_stack_boundary)
+ pref = crtl->stack_alignment_needed;
cgraph_rtl_info (current_function_decl)->preferred_incoming_stack_boundary
= pref;
}
return 0;
}
-struct tree_opt_pass pass_clean_state =
+struct rtl_opt_pass pass_clean_state =
{
- NULL, /* name */
+ {
+ RTL_PASS,
+ "*clean_state", /* name */
NULL, /* gate */
rest_of_clean_state, /* execute */
NULL, /* sub */
0, /* properties_provided */
PROP_rtl, /* properties_destroyed */
0, /* todo_flags_start */
- 0, /* todo_flags_finish */
- 0 /* letter */
+ 0 /* todo_flags_finish */
+ }
};
-