/* 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,
+ 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;
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:
#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;
}
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
- 0, /* tv_id */
+ TV_NONE, /* tv_id */
0, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
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;
asm_insn_count (rtx body)
{
const char *templ;
- int count = 1;
if (GET_CODE (body) == ASM_INPUT)
templ = XSTR (body, 0);
else
templ = decode_asm_operands (body, NULL, NULL, NULL, NULL, NULL);
+ 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;
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 (crtl->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
static void
profile_after_prologue (FILE *file ATTRIBUTE_UNUSED)
{
-#ifndef PROFILE_BEFORE_PROLOGUE
- if (crtl->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 = cfun->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
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;
-#endif
- if (LABEL_NAME (insn))
- (*debug_hooks->label) (insn);
+ if (!DECL_IGNORED_P (current_function_decl) && LABEL_NAME (insn))
+ debug_hooks->label (insn);
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 *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. */
}
/* 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;
- app_enable (void);
+ app_enable ();
loc = expand_location (ASM_INPUT_SOURCE_LOCATION (body));
if (*loc.file && loc.line)
fprintf (asm_out_file, "%s %i \"%s\" 1\n",
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;
/* Output the insn using them. */
if (string[0])
{
- app_enable (void);
+ 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;
}
/* 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. */
templ = get_insn_template (insn_code_number, insn);
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))
{
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 (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
&& (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);
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);
- 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);
- }
+ 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
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));
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)
}
}
#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 = XRESIZEVEC (tree, symbol_queue, symbol_queue_size);
- }
-
- 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),
{
{
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: %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))
{
unsigned int pref = crtl->preferred_stack_boundary;
if (crtl->stack_alignment_needed > crtl->preferred_stack_boundary)
{
{
RTL_PASS,
- NULL, /* name */
+ "*clean_state", /* name */
NULL, /* gate */
rest_of_clean_state, /* execute */
NULL, /* sub */
0 /* todo_flags_finish */
}
};
-