/* 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, 2009
+ 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
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 "expr.h"
#include "cfglayout.h"
#include "tree-pass.h"
+#include "tree-flow.h"
#include "timevar.h"
#include "cgraph.h"
#include "coverage.h"
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);
case NOTE:
case BARRIER:
case CODE_LABEL:
+ case DEBUG_INSN:
return 0;
case CALL_INSN:
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;
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
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
#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
dwarf2out_switch_text_section ();
else
#endif
- (*debug_hooks->switch_text_section) ();
+ if (!DECL_IGNORED_P (current_function_decl))
+ debug_hooks->switch_text_section ();
switch_to_section (current_function_section ());
break;
case NOTE_INSN_FUNCTION_BEG:
app_disable ();
- (*debug_hooks->end_prologue) (last_linenum, last_filename);
+ if (!DECL_IGNORED_P (current_function_decl))
+ debug_hooks->end_prologue (last_linenum, last_filename);
if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE)
{
high_block_linenum = last_linenum;
/* Output debugging info about the symbol-block beginning. */
- (*debug_hooks->begin_block) (last_linenum, n);
+ if (!DECL_IGNORED_P (current_function_decl))
+ debug_hooks->begin_block (last_linenum, n);
/* Mark this block as output. */
TREE_ASM_WRITTEN (NOTE_BLOCK (insn)) = 1;
--block_depth;
gcc_assert (block_depth >= 0);
- (*debug_hooks->end_block) (high_block_linenum, n);
+ if (!DECL_IGNORED_P (current_function_decl))
+ debug_hooks->end_block (high_block_linenum, n);
}
if (write_symbols == DBX_DEBUG
|| write_symbols == SDB_DEBUG)
break;
case NOTE_INSN_VAR_LOCATION:
- (*debug_hooks->var_location) (insn);
+ if (!DECL_IGNORED_P (current_function_decl))
+ debug_hooks->var_location (insn);
break;
default:
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 ();
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,
- last_discriminator);
- }
+ 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)
{
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;
/* Output assembler code from the template. */
output_asm_insn (templ, recog_data.operand);
+ /* Record point-of-call information for ICF debugging. */
+ if (flag_enable_icf_debug && CALL_P (insn))
+ {
+ rtx x = call_from_call_insn (insn);
+ x = XEXP (x, 0);
+ if (x && MEM_P (x))
+ {
+ if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF)
+ {
+ tree t;
+ x = XEXP (x, 0);
+ t = SYMBOL_REF_DECL (x);
+ if (t)
+ (*debug_hooks->direct_call) (t);
+ }
+ else
+ (*debug_hooks->virtual_call) (INSN_UID (insn));
+ }
+ }
+
/* Some target machines need to postscan each insn after
it is output. */
if (targetm.asm_out.final_postscan_insn)
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
- || last_discriminator != discriminator))
+ 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);
}
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
case SYMBOL_REF:
if (SYMBOL_REF_DECL (x))
- {
- mark_decl_referenced (SYMBOL_REF_DECL (x));
- assemble_external (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));
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))
{
*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. */
{
{
RTL_PASS,
- NULL, /* name */
+ "final", /* name */
NULL, /* gate */
rest_of_handle_final, /* execute */
NULL, /* sub */
rest_of_clean_state (void)
{
rtx insn, next;
+ FILE *final_output = NULL;
+ int save_unnumbered = flag_dump_unnumbered;
+ int save_noaddr = flag_dump_noaddr;
+
+ if (flag_dump_final_insns)
+ {
+ final_output = fopen (flag_dump_final_insns, "a");
+ if (!final_output)
+ {
+ error ("could not open final insn dump file %qs: %s",
+ flag_dump_final_insns, strerror (errno));
+ flag_dump_final_insns = NULL;
+ }
+ else
+ {
+ const char *aname;
+ struct cgraph_node *node = cgraph_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
+ INSN_UID (insn) = 0;
+ }
+ }
/* It is very important to decompose the RTL instruction chain here:
debug information keeps pointing into CODE_LABEL insns inside the function
next = NEXT_INSN (insn);
NEXT_INSN (insn) = NULL;
PREV_INSN (insn) = NULL;
+
+ if (final_output
+ && (!NOTE_P (insn) ||
+ (NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION
+ && NOTE_KIND (insn) != NOTE_INSN_BLOCK_BEG
+ && NOTE_KIND (insn) != NOTE_INSN_BLOCK_END
+ && NOTE_KIND (insn) != NOTE_INSN_CFA_RESTORE_STATE)))
+ print_rtl_single (final_output, insn);
+
+ }
+
+ if (final_output)
+ {
+ flag_dump_noaddr = save_noaddr;
+ flag_dump_unnumbered = save_unnumbered;
+ final_insns_dump_p = false;
+
+ if (fclose (final_output))
+ {
+ error ("could not close final insn dump file %qs: %s",
+ flag_dump_final_insns, strerror (errno));
+ flag_dump_final_insns = NULL;
+ }
}
/* In case the function was not output,
free_bb_for_insn ();
+ delete_tree_ssa ();
+
if (targetm.binds_local_p (current_function_decl))
{
unsigned int pref = crtl->preferred_stack_boundary;
{
{
RTL_PASS,
- NULL, /* name */
+ "*clean_state", /* name */
NULL, /* gate */
rest_of_clean_state, /* execute */
NULL, /* sub */