/* 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 Free Software Foundation, Inc.
+ 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
This file is part of GCC.
#define HAVE_READONLY_DATA_SECTION 0
#endif
+/* Bitflags used by final_scan_insn. */
+#define SEEN_BB 1
+#define SEEN_NOTE 2
+#define SEEN_EMITTED 4
+
/* Last insn processed by final_scan_insn. */
static rtx debug_insn;
rtx current_output_insn;
char regs_ever_live[FIRST_PSEUDO_REGISTER];
+/* Like regs_ever_live, but 1 if a reg is set or clobbered from an asm.
+ Unlike regs_ever_live, elements of this array corresponding to
+ eliminable regs like the frame pointer are set if an asm sets them. */
+
+char regs_asm_clobbered[FIRST_PSEUDO_REGISTER];
+
/* Nonzero means current function must be given a frame pointer.
- Set in stmt.c if anything is allocated on the stack there.
- Set in reload1.c if anything is allocated on the stack there. */
+ Initialized in function.c to 0. Set only in reload1.c as per
+ the needs of the function. */
int frame_pointer_needed;
static int dialect_number;
#endif
-/* Indexed by line number, nonzero if there is a note for that line. */
-
-static char *line_note_exists;
-
#ifdef HAVE_conditional_execution
/* Nonnull if the insn currently being emitted was a COND_EXEC pattern. */
rtx current_insn_predicate;
FOR_EACH_BB (bb)
{
- rtx label = bb->head;
+ rtx label = BB_HEAD (bb);
int fallthru_frequency = 0, branch_frequency = 0, has_fallthru = 0;
edge e;
/* Make a pass over all insns and compute their actual lengths by shortening
any branches of variable length if possible. */
-/* Give a default value for the lowest address in a function. */
-
-#ifndef FIRST_INSN_ADDRESS
-#define FIRST_INSN_ADDRESS 0
-#endif
-
/* shorten_branches might be called multiple times: for example, the SH
port splits out-of-range conditional branches in MACHINE_DEPENDENT_REORG.
In order to do this, it needs proper length information, which it obtains
/* Compute maximum UID and allocate label_align / uid_shuid. */
max_uid = get_max_uid ();
+ /* Free uid_shuid before reallocating it. */
+ free (uid_shuid);
+
uid_shuid = xmalloc (max_uid * sizeof *uid_shuid);
if (max_labelno != max_label_num ())
#endif /* CASE_VECTOR_SHORTEN_MODE */
/* Compute initial lengths, addresses, and varying flags for each insn. */
- for (insn_current_address = FIRST_INSN_ADDRESS, insn = first;
+ for (insn_current_address = 0, insn = first;
insn != 0;
insn_current_address += insn_lengths[uid], insn = NEXT_INSN (insn))
{
{
something_changed = 0;
insn_current_align = MAX_CODE_ALIGN - 1;
- for (insn_current_address = FIRST_INSN_ADDRESS, insn = first;
+ for (insn_current_address = 0, insn = first;
insn != 0;
insn = NEXT_INSN (insn))
{
this_is_asm_operands = 0;
-#ifdef NON_SAVING_SETJMP
- /* A function that calls setjmp should save and restore all the
- call-saved registers on a system where longjmp clobbers them. */
- if (NON_SAVING_SETJMP && current_function_calls_setjmp)
- {
- int i;
-
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (!call_used_regs[i])
- regs_ever_live[i] = 1;
- }
-#endif
-
last_filename = locator_file (prologue_locator);
last_linenum = locator_line (prologue_locator);
}
/* First output the function prologue: code to set up the stack frame. */
- (*targetm.asm_out.function_prologue) (file, get_frame_size ());
+ targetm.asm_out.function_prologue (file, get_frame_size ());
/* If the machine represents the prologue as RTL, the profiling code must
be emitted when NOTE_INSN_PROLOGUE_END is scanned. */
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 = current_function_needs_context;
+ int cxt = cfun->static_chain_decl != NULL;
#endif
#endif /* ASM_OUTPUT_REG_PUSH */
int align = MIN (BIGGEST_ALIGNMENT, LONG_TYPE_SIZE);
data_section ();
ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
- (*targetm.asm_out.internal_label) (file, "LP", current_function_funcdef_no);
+ targetm.asm_out.internal_label (file, "LP", current_function_funcdef_no);
assemble_integer (const0_rtx, LONG_TYPE_SIZE / BITS_PER_UNIT, align, 1);
}
function_section (current_function_decl);
#if defined(ASM_OUTPUT_REG_PUSH)
- if (sval && GET_CODE (svrtx) == REG)
+ if (sval && svrtx != NULL_RTX && REG_P (svrtx))
ASM_OUTPUT_REG_PUSH (file, REGNO (svrtx));
#endif
#endif
#if defined(ASM_OUTPUT_REG_PUSH)
- if (sval && GET_CODE (svrtx) == REG)
+ if (sval && svrtx != NULL_RTX && REG_P (svrtx))
ASM_OUTPUT_REG_POP (file, REGNO (svrtx));
#endif
}
/* Finally, output the function epilogue:
code to restore the stack frame and return to the caller. */
- (*targetm.asm_out.function_epilogue) (asm_out_file, get_frame_size ());
+ targetm.asm_out.function_epilogue (asm_out_file, get_frame_size ());
/* And debug output. */
(*debug_hooks->end_epilogue) (last_linenum, last_filename);
final (rtx first, FILE *file, int optimize, int prescan)
{
rtx insn;
- int max_line = 0;
int max_uid = 0;
+ int seen = 0;
last_ignored_compare = 0;
- /* Make a map indicating which line numbers appear in this function.
- When producing SDB debugging info, delete troublesome line number
+#ifdef SDB_DEBUGGING_INFO
+ /* When producing SDB debugging info, delete troublesome line number
notes from inlined functions in other files as well as duplicate
line number notes. */
-#ifdef SDB_DEBUGGING_INFO
if (write_symbols == SDB_DEBUG)
{
rtx last = 0;
for (insn = first; insn; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
{
- if ((RTX_INTEGRATED_P (insn)
- && strcmp (NOTE_SOURCE_FILE (insn), main_input_filename) != 0)
- || (last != 0
- && NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last)
- && NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last)))
+ if (last != 0
+#ifdef USE_MAPPED_LOCATION
+ && NOTE_SOURCE_LOCATION (insn) == NOTE_SOURCE_LOCATION (last)
+#else
+ && NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last)
+ && NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last)
+#endif
+ )
{
delete_insn (insn); /* Use delete_note. */
continue;
}
last = insn;
- if (NOTE_LINE_NUMBER (insn) > max_line)
- max_line = NOTE_LINE_NUMBER (insn);
}
}
- else
#endif
- {
- for (insn = first; insn; insn = NEXT_INSN (insn))
- if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > max_line)
- max_line = NOTE_LINE_NUMBER (insn);
- }
-
- line_note_exists = xcalloc (max_line + 1, sizeof (char));
for (insn = first; insn; insn = NEXT_INSN (insn))
{
if (INSN_UID (insn) > max_uid) /* Find largest UID. */
max_uid = INSN_UID (insn);
- if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
- line_note_exists[NOTE_LINE_NUMBER (insn)] = 1;
#ifdef HAVE_cc0
/* If CC tracking across branches is enabled, record the insn which
jumps to each branch only reached from one place. */
insn_current_address = INSN_ADDRESSES (INSN_UID (insn));
#endif /* HAVE_ATTR_length */
- insn = final_scan_insn (insn, file, optimize, prescan, 0);
+ insn = final_scan_insn (insn, file, optimize, prescan, 0, &seen);
}
-
- free (line_note_exists);
- line_note_exists = NULL;
}
\f
const char *
get_insn_template (int code, rtx insn)
{
- const void *output = insn_data[code].output;
switch (insn_data[code].output_format)
{
case INSN_OUTPUT_FORMAT_SINGLE:
- return (const char *) output;
+ return insn_data[code].output.single;
case INSN_OUTPUT_FORMAT_MULTI:
- return ((const char *const *) output)[which_alternative];
+ return insn_data[code].output.multi[which_alternative];
case INSN_OUTPUT_FORMAT_FUNCTION:
if (insn == NULL)
abort ();
- return (*(insn_output_fn) output) (recog_data.operand, insn);
+ return (*insn_data[code].output.function) (recog_data.operand, insn);
default:
abort ();
ASM_WEAKEN_LABEL (file, name);
#endif
case LABEL_GLOBAL_ENTRY:
- (*targetm.asm_out.globalize_label) (file, name);
+ targetm.asm_out.globalize_label (file, name);
case LABEL_STATIC_ENTRY:
#ifdef ASM_OUTPUT_TYPE_DIRECTIVE
ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
}
}
+/* Return boolean indicating if there is a NOTE_INSN_UNLIKELY_EXECUTED_CODE
+ note in the instruction chain (going forward) between the current
+ instruction, and the next 'executable' instruction. */
+
+bool
+scan_ahead_for_unlikely_executed_note (rtx insn)
+{
+ rtx temp;
+ int bb_note_count = 0;
+
+ for (temp = insn; temp; temp = NEXT_INSN (temp))
+ {
+ if (GET_CODE (temp) == NOTE
+ && NOTE_LINE_NUMBER (temp) == NOTE_INSN_UNLIKELY_EXECUTED_CODE)
+ return true;
+ if (GET_CODE (temp) == NOTE
+ && NOTE_LINE_NUMBER (temp) == NOTE_INSN_BASIC_BLOCK)
+ {
+ bb_note_count++;
+ if (bb_note_count > 1)
+ return false;
+ }
+ if (INSN_P (temp))
+ return false;
+ }
+
+ return false;
+}
+
/* The final scan for one insn, INSN.
Args are same as in `final', except that INSN
is the insn being scanned.
Value returned is the next insn to be scanned.
NOPEEPHOLES is the flag to disallow peephole processing (currently
- used for within delayed branch sequence output). */
+ used for within delayed branch sequence output).
+
+ SEEN is used to track the end of the prologue, for emitting
+ debug information. We force the emission of a line note after
+ both NOTE_INSN_PROLOGUE_END and NOTE_INSN_FUNCTION_BEG, or
+ at the beginning of the second basic block, whichever comes
+ first. */
rtx
final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
- int prescan, int nopeepholes ATTRIBUTE_UNUSED)
+ int prescan, int nopeepholes ATTRIBUTE_UNUSED,
+ int *seen)
{
#ifdef HAVE_cc0
rtx set;
case NOTE_INSN_EXPECTED_VALUE:
break;
+ case NOTE_INSN_UNLIKELY_EXECUTED_CODE:
+
+ /* The presence of this note indicates that this basic block
+ belongs in the "cold" section of the .o file. If we are
+ not already writing to the cold section we need to change
+ to it. */
+
+ unlikely_text_section ();
+ break;
+
case NOTE_INSN_BASIC_BLOCK:
+
+ /* If we are performing the optimization that partitions
+ basic blocks into hot & cold sections of the .o file,
+ then at the start of each new basic block, before
+ beginning to write code for the basic block, we need to
+ check to see whether the basic block belongs in the hot
+ or cold section of the .o file, and change the section we
+ are writing to appropriately. */
+
+ if (flag_reorder_blocks_and_partition
+ && in_unlikely_text_section()
+ && !scan_ahead_for_unlikely_executed_note (insn))
+ text_section ();
+
#ifdef IA64_UNWIND_INFO
IA64_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 ((*seen & (SEEN_EMITTED | SEEN_BB)) == SEEN_BB)
+ {
+ *seen |= SEEN_EMITTED;
+ last_filename = NULL;
+ }
+ else
+ *seen |= SEEN_BB;
+
break;
case NOTE_INSN_EH_REGION_BEG:
break;
case NOTE_INSN_PROLOGUE_END:
- (*targetm.asm_out.function_end_prologue) (file);
+ targetm.asm_out.function_end_prologue (file);
profile_after_prologue (file);
+
+ if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE)
+ {
+ *seen |= SEEN_EMITTED;
+ last_filename = NULL;
+ }
+ else
+ *seen |= SEEN_NOTE;
+
break;
case NOTE_INSN_EPILOGUE_BEG:
- (*targetm.asm_out.function_begin_epilogue) (file);
+ targetm.asm_out.function_begin_epilogue (file);
break;
case NOTE_INSN_FUNCTION_BEG:
app_disable ();
(*debug_hooks->end_prologue) (last_linenum, last_filename);
+
+ if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE)
+ {
+ *seen |= SEEN_EMITTED;
+ last_filename = NULL;
+ }
+ else
+ *seen |= SEEN_NOTE;
+
break;
case NOTE_INSN_BLOCK_BEG:
ASM_OUTPUT_DEBUG_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
break;
+ case NOTE_INSN_VAR_LOCATION:
+ (*debug_hooks->var_location) (insn);
+ break;
+
case 0:
break;
if (prescan > 0)
break;
-#ifdef FINAL_PRESCAN_LABEL
- FINAL_PRESCAN_INSN (insn, NULL, 0);
-#endif
-
if (LABEL_NAME (insn))
(*debug_hooks->label) (insn);
+ /* If we are doing the optimization that partitions hot & cold
+ basic blocks into separate sections of the .o file, we need
+ to ensure the jump table ends up in the correct section... */
+
+ if (flag_reorder_blocks_and_partition)
+ {
+ rtx tmp_table, tmp_label;
+ if (GET_CODE (insn) == CODE_LABEL
+ && tablejump_p (NEXT_INSN (insn), &tmp_label, &tmp_table))
+ {
+ /* Do nothing; Do NOT change the current section. */
+ }
+ else if (scan_ahead_for_unlikely_executed_note (insn))
+ unlikely_text_section ();
+ else
+ {
+ if (in_unlikely_text_section ())
+ text_section ();
+ }
+ }
+
if (app_on)
{
fputs (ASM_APP_OFF, file);
ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn),
NEXT_INSN (insn));
#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;
if (LABEL_ALT_ENTRY_P (insn))
output_alternate_entry_point (file, insn);
else
- (*targetm.asm_out.internal_label) (file, "L", CODE_LABEL_NUMBER (insn));
+ targetm.asm_out.internal_label (file, "L", CODE_LABEL_NUMBER (insn));
break;
default:
/* An INSN, JUMP_INSN or CALL_INSN.
First check for special kinds that recog doesn't recognize. */
- if (GET_CODE (body) == USE /* These are just declarations */
+ if (GET_CODE (body) == USE /* These are just declarations. */
|| GET_CODE (body) == CLOBBER)
break;
insn_noperands = noperands;
this_is_asm_operands = insn;
+#ifdef FINAL_PRESCAN_INSN
+ FINAL_PRESCAN_INSN (insn, ops, insn_noperands);
+#endif
+
/* Output the insn using them. */
if (string[0])
{
thought unnecessary. If that happens, cancel this sequence
and cause that insn to be restored. */
- next = final_scan_insn (XVECEXP (body, 0, 0), file, 0, prescan, 1);
+ next = final_scan_insn (XVECEXP (body, 0, 0), file, 0, prescan, 1, seen);
if (next != XVECEXP (body, 0, 1))
{
final_sequence = 0;
/* We loop in case any instruction in a delay slot gets
split. */
do
- insn = final_scan_insn (insn, file, 0, prescan, 1);
+ insn = final_scan_insn (insn, file, 0, prescan, 1, seen);
while (insn != next);
}
#ifdef DBR_OUTPUT_SEQEND
if (optimize)
{
-#if 0
- rtx set = single_set (insn);
-#endif
-
if (set
&& GET_CODE (SET_DEST (set)) == CC0
&& insn != last_ignored_compare)
if (final_sequence == 0
&& prescan >= 0
&& GET_CODE (insn) == INSN && GET_CODE (body) == SET
- && GET_CODE (SET_SRC (body)) == REG
- && GET_CODE (SET_DEST (body)) == REG
+ && REG_P (SET_SRC (body))
+ && REG_P (SET_DEST (body))
&& REGNO (SET_SRC (body)) == REGNO (SET_DEST (body)))
break;
#endif
&& GET_CODE (body) == SET
&& SET_DEST (body) == pc_rtx
&& GET_CODE (SET_SRC (body)) == IF_THEN_ELSE
- && GET_RTX_CLASS (GET_CODE (XEXP (SET_SRC (body), 0))) == '<'
+ && COMPARISON_P (XEXP (SET_SRC (body), 0))
&& XEXP (XEXP (SET_SRC (body), 0), 0) == cc0_rtx
/* This is done during prescan; it is not done again
in final scan when prescan has been done. */
for (note = NEXT_INSN (insn); note != next;
note = NEXT_INSN (note))
- final_scan_insn (note, file, optimize, prescan, nopeepholes);
+ final_scan_insn (note, file, optimize, prescan, nopeepholes, seen);
/* In case this is prescan, put the notes
in proper position for later rescan. */
extract_insn_cached (insn);
for (i = 0; i < recog_data.n_operands; i++)
{
- /* The following test cannot use recog_data.operand when tesing
+ /* The following test cannot use recog_data.operand when testing
for a SUBREG: the underlying object might have been changed
already if we are inside a match_operator expression that
matches the else clause. Instead we test the underlying
recog_data.operand[i] = alter_subreg (recog_data.operand_loc[i]);
else if (GET_CODE (recog_data.operand[i]) == PLUS
|| GET_CODE (recog_data.operand[i]) == MULT
- || GET_CODE (recog_data.operand[i]) == MEM)
+ || MEM_P (recog_data.operand[i]))
recog_data.operand[i] = walk_alter_subreg (recog_data.operand_loc[i]);
}
*recog_data.dup_loc[i] = alter_subreg (recog_data.dup_loc[i]);
else if (GET_CODE (*recog_data.dup_loc[i]) == PLUS
|| GET_CODE (*recog_data.dup_loc[i]) == MULT
- || GET_CODE (*recog_data.dup_loc[i]) == MEM)
+ || MEM_P (*recog_data.dup_loc[i]))
*recog_data.dup_loc[i] = walk_alter_subreg (recog_data.dup_loc[i]);
}
}
/* simplify_subreg does not remove subreg from volatile references.
We are required to. */
- if (GET_CODE (y) == MEM)
+ if (MEM_P (y))
*xp = adjust_address (y, GET_MODE (x), SUBREG_BYTE (x));
else
{
if (new != 0)
*xp = new;
/* Simplify_subreg can't handle some REG cases, but we have to. */
- else if (GET_CODE (y) == REG)
+ else if (REG_P (y))
{
unsigned int regno = subreg_hard_regno (x, 1);
*xp = gen_rtx_REG_offset (y, GET_MODE (x), regno, SUBREG_BYTE (x));
*paddressp = 0;
- if (GET_CODE (op) == REG)
+ if (REG_P (op))
return REG_EXPR (op);
- else if (GET_CODE (op) != MEM)
+ else if (!MEM_P (op))
return 0;
if (MEM_EXPR (op) != 0)
&& (expr = get_mem_expr_from_op (XEXP (op, 1), &inner_addressp)))
return expr;
- while (GET_RTX_CLASS (GET_CODE (op)) == '1'
- || GET_RTX_CLASS (GET_CODE (op)) == '2')
+ while (GET_RTX_CLASS (GET_CODE (op)) == RTX_UNARY
+ || GET_RTX_CLASS (GET_CODE (op)) == RTX_BIN_ARITH)
op = XEXP (op, 0);
expr = get_mem_expr_from_op (op, &inner_addressp);
/* If X is a pseudo-register, abort now rather than writing trash to the
assembler file. */
- if (x && GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER)
+ if (x && REG_P (x) && REGNO (x) >= FIRST_PSEUDO_REGISTER)
abort ();
PRINT_OPERAND (asm_out_file, x, code);
break;
case SYMBOL_REF:
+ if (SYMBOL_REF_DECL (x))
+ mark_decl_referenced (SYMBOL_REF_DECL (x));
#ifdef ASM_OUTPUT_SYMBOL_REF
ASM_OUTPUT_SYMBOL_REF (file, x);
#else
break;
#ifdef ASM_FPRINTF_EXTENSIONS
- /* Upper case letters are reserved for general use by asm_fprintf
+ /* Uppercase letters are reserved for general use by asm_fprintf
and so are not available to target specific code. In order to
prevent the ASM_FPRINTF_EXTENSIONS macro from using them then,
they are defined here. As they get turned into real extensions
if (current_function_uses_pic_offset_table
&& pic_offset_table_rtx != 0
- && GET_CODE (pic_offset_table_rtx) == REG
+ && REG_P (pic_offset_table_rtx)
&& ! permitted_reg_in_leaf_functions[REGNO (pic_offset_table_rtx)])
return 0;
renumbered_regs would be 1 for an output-register;
they */
- if (GET_CODE (in_rtx) == REG)
+ if (REG_P (in_rtx))
{
int newreg;
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 a intercept nesting counter (debug_nesting). We only save the
+ we maintain an intercept nesting counter (debug_nesting). We only save the
intercepted arguments if the nesting is 1. */
int debug_nesting = 0;