/* 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 Free Software Foundation, Inc.
+ 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
This file is part of GNU CC.
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-
/* This is the final pass of the compiler.
It looks at the rtl code for a function and outputs assembler code.
#include "tm_p.h"
#include "regs.h"
#include "insn-config.h"
-#include "insn-flags.h"
#include "insn-attr.h"
-#include "insn-codes.h"
#include "recog.h"
#include "conditions.h"
#include "flags.h"
#include "real.h"
#include "hard-reg-set.h"
-#include "defaults.h"
#include "output.h"
#include "except.h"
#include "function.h"
#include "intl.h"
#include "basic-block.h"
-/* Get N_SLINE and N_SOL from stab.h if we can expect the file to exist. */
#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
#include "dbxout.h"
-#if defined (USG) || !defined (HAVE_STAB_H)
-#include "gstab.h" /* If doing DBX on sysV, use our own stab.h. */
-#else
-#include <stab.h>
-#endif
-
#endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */
-#ifndef ACCUMULATE_OUTGOING_ARGS
-#define ACCUMULATE_OUTGOING_ARGS 0
-#endif
-
#ifdef XCOFF_DEBUGGING_INFO
#include "xcoffout.h"
#endif
#include "sdbout.h"
#endif
-/* .stabd code for line number. */
-#ifndef N_SLINE
-#define N_SLINE 0x44
-#endif
-
-/* .stabs code for included file name. */
-#ifndef N_SOL
-#define N_SOL 0x84
-#endif
-
-#ifndef INT_TYPE_SIZE
-#define INT_TYPE_SIZE BITS_PER_WORD
-#endif
-
-#ifndef LONG_TYPE_SIZE
-#define LONG_TYPE_SIZE BITS_PER_WORD
-#endif
-
/* If we aren't using cc0, CC_STATUS_INIT shouldn't exist. So define a
null default for it to save conditionalization later. */
#ifndef CC_STATUS_INIT
#endif
/* Last insn processed by final_scan_insn. */
-static rtx debug_insn = 0;
+static rtx debug_insn;
+rtx current_output_insn;
/* Line number of last NOTE. */
static int last_linenum;
/* Linked list to hold line numbers for each basic block. */
-struct bb_list {
+struct bb_list
+{
struct bb_list *next; /* pointer to next basic block */
int line_num; /* line number */
int file_label_num; /* LPBC<n> label # for stored filename */
/* Linked list to hold the strings for each file and function name output. */
-struct bb_str {
+struct bb_str
+{
struct bb_str *next; /* pointer to next string */
const char *string; /* string */
int label_num; /* label number */
void
end_final (filename)
- const char *filename;
+ const char *filename;
{
int i;
else
#endif
#ifdef ASM_OUTPUT_ALIGNED_DECL_LOCAL
- ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, NULL_TREE, name, size,
- BIGGEST_ALIGNMENT);
+ ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, NULL_TREE, name,
+ size, BIGGEST_ALIGNMENT);
#else
#ifdef ASM_OUTPUT_ALIGNED_LOCAL
ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size,
assemble_integer (const0_rtx, pointer_bytes, 1);
}
- for ( ; i < count_basic_blocks; i++)
+ for (; i < count_basic_blocks; i++)
assemble_integer (const0_rtx, pointer_bytes, 1);
}
for ((ptr = bb_head), (i = 0); ptr != 0; (ptr = ptr->next), i++)
assemble_integer (GEN_INT (ptr->line_num), long_bytes, 1);
- for ( ; i < count_basic_blocks; i++)
+ for (; i < count_basic_blocks; i++)
assemble_integer (const0_rtx, long_bytes, 1);
/* Output the table of file names. */
assemble_integer (const0_rtx, pointer_bytes, 1);
}
- for ( ; i < count_basic_blocks; i++)
+ for (; i < count_basic_blocks; i++)
assemble_integer (const0_rtx, pointer_bytes, 1);
}
}
}
\f
-/* Return the number of slots filled in the current
+/* Return the number of slots filled in the current
delayed branch sequence (we don't count the insn needing the
delay slot). Zero if not in a delayed branch sequence. */
`insn_current_length'. */
static short *insn_lengths;
-int *insn_addresses;
+
+#ifdef HAVE_ATTR_length
+varray_type insn_addresses_;
+#endif
/* Max uid for which the above arrays are valid. */
static int insn_lengths_max_uid;
for each insn we'll call the alignment chain of this insn in the following
comments. */
-struct label_alignment {
+struct label_alignment
+{
short alignment;
short max_skip;
};
insn_lengths = 0;
insn_lengths_max_uid = 0;
}
- if (insn_addresses)
- {
- free (insn_addresses);
- insn_addresses = 0;
- }
+#ifdef HAVE_ATTR_length
+ INSN_ADDRESSES_FREE ();
+#endif
if (uid_align)
{
free (uid_align);
Call a sequence of instructions beginning with alignment point X
and continuing until the next alignment point `block X'. When `X'
- is used in an expression, it means the alignment value of the
+ is used in an expression, it means the alignment value of the
alignment point.
-
+
Call the distance between the start of the first insn of block X, and
the end of the last insn of block X `IX', for the `inner size of X'.
This is clearly the sum of the instruction lengths.
-
+
Likewise with the next alignment-delimited block following X, which we
shall call block Y.
-
+
Call the distance between the start of the first insn of block X, and
the start of the first insn of block Y `OX', for the `outer size of X'.
-
+
The estimated padding is then OX - IX.
-
+
OX can be safely estimated as
-
+
if (X >= Y)
OX = round_up(IX, Y)
else
OX = round_up(IX, X) + Y - X
-
+
Clearly est(IX) >= real(IX), because that only depends on the
instruction lengths, and those being overestimated is a given.
-
+
Clearly round_up(foo, Z) >= round_up(bar, Z) if foo >= bar, so
we needn't worry about that when thinking about OX.
-
+
When X >= Y, the alignment provided by Y adds no uncertainty factor
for branch ranges starting before X, so we can just round what we have.
But when X < Y, we don't know anything about the, so to speak,
final_addr_vec_align (addr_vec)
rtx addr_vec;
{
- int align = exact_log2 (GET_MODE_SIZE (GET_MODE (PATTERN (addr_vec))));
+ int align = GET_MODE_SIZE (GET_MODE (PATTERN (addr_vec)));
if (align > BIGGEST_ALIGNMENT / BITS_PER_UNIT)
align = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
- return align;
+ return exact_log2 (align);
}
+
#define ADDR_VEC_ALIGN(ADDR_VEC) final_addr_vec_align (ADDR_VEC)
#endif
(label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno].max_skip)
/* For the benefit of port specific code do this also as a function. */
+
int
label_to_alignment (label)
rtx label;
For this purpose, align_fuzz with a growth argument of 0 comuptes the
appropriate adjustment. */
-
/* Compute the maximum delta by which the difference of the addresses of
START and END might grow / shrink due to a different address for start
which changes the size of alignment insns between START and END.
GROWTH should be ~0 if the objective is to compute potential code size
increase, and 0 if the objective is to compute potential shrink.
The return value is undefined for any other value of GROWTH. */
+
static int
align_fuzz (start, end, known_align_log, growth)
rtx start, end;
int align_addr, new_align;
uid = INSN_UID (align_label);
- align_addr = insn_addresses[uid] - insn_lengths[uid];
+ align_addr = INSN_ADDRESSES (uid) - insn_lengths[uid];
if (uid_shuid[uid] > end_shuid)
break;
known_align_log = LABEL_TO_ALIGNMENT (align_label);
to account for possible size increase due to alignment.
NB.: Therefore, the maximum offset allowed for backward branches needs
to exclude the branch size. */
+
int
insn_current_reference_address (branch)
rtx branch;
{
- rtx dest;
- rtx seq = NEXT_INSN (PREV_INSN (branch));
- int seq_uid = INSN_UID (seq);
+ rtx dest, seq;
+ int seq_uid;
+
+ if (! INSN_ADDRESSES_SET_P ())
+ return 0;
+
+ seq = NEXT_INSN (PREV_INSN (branch));
+ seq_uid = INSN_UID (seq);
if (GET_CODE (branch) != JUMP_INSN)
/* This can happen for example on the PA; the objective is to know the
offset to address something in front of the start of the function.
any alignment we'd encounter, so we skip the call to align_fuzz. */
return insn_current_address;
dest = JUMP_LABEL (branch);
- /* BRANCH has no proper alignment chain set, so use SEQ. */
- if (INSN_SHUID (branch) < INSN_SHUID (dest))
+
+ /* BRANCH has no proper alignment chain set, so use SEQ.
+ BRANCH also has no INSN_SHUID. */
+ if (INSN_SHUID (seq) < INSN_SHUID (dest))
{
- /* Forward branch. */
+ /* Forward branch. */
return (insn_last_address + insn_lengths[seq_uid]
- align_fuzz (seq, dest, length_unit_log, ~0));
}
else
{
- /* Backward branch. */
+ /* Backward branch. */
return (insn_current_address
+ align_fuzz (dest, seq, length_unit_log, ~0));
}
int uid;
rtx align_tab[MAX_CODE_ALIGN];
- /* In order to make sure that all instructions have valid length info,
- we must split them before we compute the address/length info. */
-
- for (insn = NEXT_INSN (first); insn; insn = NEXT_INSN (insn))
- if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
- {
- rtx old = insn;
- /* Don't split the insn if it has been deleted. */
- if (! INSN_DELETED_P (old))
- insn = try_split (PATTERN (old), old, 1);
- /* When not optimizing, the old insn will be still left around
- with only the 'deleted' bit set. Transform it into a note
- to avoid confusion of subsequent processing. */
- if (INSN_DELETED_P (old))
- {
- PUT_CODE (old , NOTE);
- NOTE_LINE_NUMBER (old) = NOTE_INSN_DELETED;
- NOTE_SOURCE_FILE (old) = 0;
- }
- }
#endif
/* We must do some computations even when not actually shortening, in
/* We use max_log here to keep track of the maximum alignment we want to
impose on the next CODE_LABEL (or the current one if we are processing
the CODE_LABEL itself). */
-
+
max_log = 0;
max_skip = 0;
int log;
INSN_SHUID (insn) = i++;
- if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+ if (INSN_P (insn))
{
/* reorg might make the first insn of a loop being run once only,
and delete the label in front of it. Then we want to apply
{
rtx label;
- for (label = insn; label && GET_RTX_CLASS (GET_CODE (label)) != 'i';
+ for (label = insn; label && ! INSN_P (label);
label = NEXT_INSN (label))
if (GET_CODE (label) == CODE_LABEL)
{
insn_lengths_max_uid = max_uid;
/* Syntax errors can lead to labels being outside of the main insn stream.
Initialize insn_addresses, so that we get reproducible results. */
- insn_addresses = (int *) xcalloc (max_uid, sizeof (int));
+ INSN_ADDRESSES_ALLOC (max_uid);
varying_length = (char *) xcalloc (max_uid, sizeof (char));
alignment of n. */
uid_align = (rtx *) xcalloc (max_uid, sizeof *uid_align);
- for (i = MAX_CODE_ALIGN; --i >= 0; )
+ for (i = MAX_CODE_ALIGN; --i >= 0;)
align_tab[i] = NULL_RTX;
seq = get_last_insn ();
for (; seq; seq = PREV_INSN (seq))
}
#endif /* CASE_VECTOR_SHORTEN_MODE */
-
/* Compute initial lengths, addresses, and varying flags for each insn. */
for (insn_current_address = FIRST_INSN_ADDRESS, insn = first;
insn != 0;
int align = 1 << log;
int new_address = (insn_current_address + align - 1) & -align;
insn_lengths[uid] = new_address - insn_current_address;
- insn_current_address = new_address;
}
}
- insn_addresses[uid] = insn_current_address;
-
+ INSN_ADDRESSES (uid) = insn_current_address;
+
if (GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER
|| GET_CODE (insn) == CODE_LABEL)
continue;
* insn_default_length (inner_insn));
else
inner_length = insn_default_length (inner_insn);
-
+
insn_lengths[inner_uid] = inner_length;
if (const_delay_slots)
{
if ((varying_length[inner_uid]
= insn_variable_length_p (inner_insn)) != 0)
varying_length[uid] = 1;
- insn_addresses[inner_uid] = (insn_current_address +
- insn_lengths[uid]);
+ INSN_ADDRESSES (inner_uid) = (insn_current_address
+ + insn_lengths[uid]);
}
else
varying_length[inner_uid] = 0;
}
else
insn_lengths[uid] = 0;
- insn_addresses[uid] = insn_current_address;
+ INSN_ADDRESSES (uid) = insn_current_address;
continue;
}
if (length_align < insn_current_align)
insn_current_align = length_align;
- insn_last_address = insn_addresses[uid];
- insn_addresses[uid] = insn_current_address;
+ insn_last_address = INSN_ADDRESSES (uid);
+ INSN_ADDRESSES (uid) = insn_current_address;
#ifdef CASE_VECTOR_SHORTEN_MODE
if (optimize && GET_CODE (insn) == JUMP_INSN
rtx min_lab = XEXP (XEXP (body, 2), 0);
rtx max_lab = XEXP (XEXP (body, 3), 0);
addr_diff_vec_flags flags = ADDR_DIFF_VEC_FLAGS (body);
- int rel_addr = insn_addresses[INSN_UID (rel_lab)];
- int min_addr = insn_addresses[INSN_UID (min_lab)];
- int max_addr = insn_addresses[INSN_UID (max_lab)];
+ int rel_addr = INSN_ADDRESSES (INSN_UID (rel_lab));
+ int min_addr = INSN_ADDRESSES (INSN_UID (min_lab));
+ int max_addr = INSN_ADDRESSES (INSN_UID (max_lab));
rtx prev;
int rel_align = 0;
if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE)
{
int i;
-
+
body = PATTERN (insn);
new_length = 0;
for (i = 0; i < XVECLEN (body, 0); i++)
int inner_uid = INSN_UID (inner_insn);
int inner_length;
- insn_addresses[inner_uid] = insn_current_address;
+ INSN_ADDRESSES (inner_uid) = insn_current_address;
/* insn_current_length returns 0 for insns with a
non-varying length. */
if (GET_CODE (body) == ASM_INPUT)
template = XSTR (body, 0);
else
- template = decode_asm_operands (body, NULL_PTR, NULL_PTR,
- NULL_PTR, NULL_PTR);
+ template = decode_asm_operands (body, NULL, NULL, NULL, NULL);
- for ( ; *template; template++)
- if (IS_ASM_LOGICAL_LINE_SEPARATOR(*template) || *template == '\n')
+ for (; *template; template++)
+ if (IS_ASM_LOGICAL_LINE_SEPARATOR (*template) || *template == '\n')
count++;
return count;
regs_ever_live[i] = 1;
}
#endif
-
+
/* Initial line number is supposed to be output
before the function's prologue and label
so that the function's address will not appear to be
last_linenum = high_block_linenum = high_function_linenum
= NOTE_LINE_NUMBER (first);
-#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
- /* Output DWARF definition of the function. */
- if (dwarf2out_do_frame ())
- dwarf2out_begin_prologue ();
- else
- current_function_func_begin_label = 0;
+#if defined (DWARF2_UNWIND_INFO) || defined (IA64_UNWIND_INFO) \
+ || defined (DWARF2_DEBUGGING_INFO)
+ dwarf2out_begin_prologue ();
#endif
/* For SDB and XCOFF, the function beginning must be marked between
if (write_symbols == XCOFF_DEBUG)
xcoffout_begin_function (file, last_linenum);
else
-#endif
+#endif
/* But only output line number for other debug info types if -g2
or better. */
if (NOTE_LINE_NUMBER (first) != NOTE_INSN_DELETED)
of the function name. */
if (profile_block_flag)
{
- bb_func_label_num
- = add_bb_string ((*decl_printable_name) (current_function_decl, 2), FALSE);
+ bb_func_label_num =
+ add_bb_string ((*decl_printable_name) (current_function_decl, 2),
+ FALSE);
}
}
profile_function (file)
FILE *file;
{
+#ifndef NO_PROFILE_COUNTERS
int align = MIN (BIGGEST_ALIGNMENT, LONG_TYPE_SIZE);
+#endif
#if defined(ASM_OUTPUT_REG_PUSH)
#if defined(STRUCT_VALUE_INCOMING_REGNUM) || defined(STRUCT_VALUE_REGNUM)
int sval = current_function_returns_struct;
#endif
#endif /* ASM_OUTPUT_REG_PUSH */
+#ifndef NO_PROFILE_COUNTERS
data_section ();
ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
ASM_OUTPUT_INTERNAL_LABEL (file, "LP", profile_label_no);
assemble_integer (const0_rtx, LONG_TYPE_SIZE / BITS_PER_UNIT, 1);
+#endif
function_section (current_function_decl);
add_bb (file)
FILE *file;
{
- struct bb_list *ptr = (struct bb_list *) permalloc (sizeof (struct bb_list));
+ struct bb_list *ptr =
+ (struct bb_list *) permalloc (sizeof (struct bb_list));
/* Add basic block to linked list. */
ptr->next = 0;
if (!perm_p)
{
char *p = (char *) permalloc (len);
- bcopy (string, p, len);
+ memcpy (p, string, len);
string = p;
}
else
return ptr->label_num;
}
-
\f
/* Output assembler code for some insns: all or part of a function.
For description of args, see `final_start_function', above.
last_ignored_compare = 0;
new_block = 1;
- check_exception_handler_labels ();
-
/* Make a map indicating which line numbers appear in this function.
When producing SDB debugging info, delete troublesome line number
notes from inlined functions in other files as well as duplicate
for (insn = first; insn; insn = NEXT_INSN (insn))
{
if (INSN_UID (insn) > max_uid) /* find largest UID */
- max_uid = INSN_UID (insn);
+ max_uid = INSN_UID (insn);
if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
- line_note_exists[NOTE_LINE_NUMBER (insn)] = 1;
+ 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. */
#endif
}
- /* Initialize insn_eh_region table if eh is being used. */
-
- init_insn_eh_region (first, max_uid);
-
init_recog ();
CC_STATUS_INIT;
for (insn = NEXT_INSN (first); insn;)
{
#ifdef HAVE_ATTR_length
- insn_current_address = insn_addresses[INSN_UID (insn)];
+ if (INSN_UID (insn) >= INSN_ADDRESSES_SIZE ())
+ {
+#ifdef STACK_REGS
+ /* Irritatingly, the reg-stack pass is creating new instructions
+ and because of REG_DEAD note abuse it has to run after
+ shorten_branches. Fake address of -1 then. */
+ insn_current_address = -1;
+#else
+ /* This can be triggered by bugs elsewhere in the compiler if
+ new insns are created after init_insn_lengths is called. */
+ abort ();
#endif
+ }
+ else
+ insn_current_address = INSN_ADDRESSES (INSN_UID (insn));
+#endif /* HAVE_ATTR_length */
+
insn = final_scan_insn (insn, file, optimize, prescan, 0);
}
if (profile_block_flag && new_block)
add_bb (file);
- free_insn_eh_region ();
free (line_note_exists);
line_note_exists = NULL;
}
case INSN_OUTPUT_FORMAT_SINGLE:
return (const char *) output;
case INSN_OUTPUT_FORMAT_MULTI:
- return ((const char * const *) output)[which_alternative];
+ return ((const char *const *) output)[which_alternative];
case INSN_OUTPUT_FORMAT_FUNCTION:
if (insn == NULL)
abort ();
- return (* (insn_output_fn) output) (recog_data.operand, insn);
+ return (*(insn_output_fn) output) (recog_data.operand, insn);
default:
abort ();
}
}
+
/* The final scan for one insn, INSN.
Args are same as in `final', except that INSN
is the insn being scanned.
break;
case NOTE_INSN_BASIC_BLOCK:
+#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);
break;
case NOTE_INSN_EH_REGION_BEG:
- if (! exceptions_via_longjmp)
- {
- ASM_OUTPUT_INTERNAL_LABEL (file, "LEHB", NOTE_EH_HANDLER (insn));
- if (! flag_new_exceptions)
- add_eh_table_entry (NOTE_EH_HANDLER (insn));
-#ifdef ASM_OUTPUT_EH_REGION_BEG
- ASM_OUTPUT_EH_REGION_BEG (file, NOTE_EH_HANDLER (insn));
-#endif
- }
+ ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LEHB",
+ NOTE_EH_HANDLER (insn));
break;
case NOTE_INSN_EH_REGION_END:
- if (! exceptions_via_longjmp)
- {
- ASM_OUTPUT_INTERNAL_LABEL (file, "LEHE", NOTE_EH_HANDLER (insn));
- if (flag_new_exceptions)
- add_eh_table_entry (NOTE_EH_HANDLER (insn));
-#ifdef ASM_OUTPUT_EH_REGION_END
- ASM_OUTPUT_EH_REGION_END (file, NOTE_EH_HANDLER (insn));
-#endif
- }
+ ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LEHE",
+ NOTE_EH_HANDLER (insn));
break;
case NOTE_INSN_PROLOGUE_END:
break;
case NOTE_INSN_FUNCTION_BEG:
- if (write_symbols == NO_DEBUG)
- break;
#if defined(SDB_DEBUGGING_INFO) && defined(MIPS_DEBUGGING_INFO)
/* MIPS stabs require the parameter descriptions to be after the
function entry point rather than before. */
app_disable ();
sdbout_begin_function (last_linenum);
}
- else
#endif
#ifdef DWARF_DEBUGGING_INFO
/* This outputs a marker where the function body starts, so it
/* Emit the label. We may have deleted the CODE_LABEL because
the label could be proved to be unreachable, though still
referenced (in the form of having its address taken. */
- /* ??? Figure out how not to do this unconditionally. This
- interferes with bundling on LIW targets. */
- ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
-
- if (debug_info_level == DINFO_LEVEL_NORMAL
- || debug_info_level == DINFO_LEVEL_VERBOSE)
- {
-#ifdef DWARF_DEBUGGING_INFO
- if (write_symbols == DWARF_DEBUG)
- dwarfout_label (insn);
-#endif
-#ifdef DWARF2_DEBUGGING_INFO
- if (write_symbols == DWARF2_DEBUG)
- dwarf2out_label (insn);
-#endif
- }
+ ASM_OUTPUT_DEBUG_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
break;
case 0:
register rtx note;
int note_after = 0;
- /* If there is anything real after this note, output it.
+ /* If there is anything real after this note, output it.
If another line note follows, omit this one. */
for (note = NEXT_INSN (insn); note; note = NEXT_INSN (note))
{
if (!note_after)
output_source_line (file, insn);
}
- break;
+ break;
}
break;
case BARRIER:
#if defined (DWARF2_UNWIND_INFO)
- /* If we push arguments, we need to check all insns for stack
- adjustments. */
- if (!ACCUMULATE_OUTGOING_ARGS && dwarf2out_do_frame ())
+ if (dwarf2out_do_frame ())
dwarf2out_frame_debug (insn);
#endif
break;
new_block = 1;
#ifdef FINAL_PRESCAN_LABEL
- FINAL_PRESCAN_INSN (insn, NULL_PTR, 0);
+ FINAL_PRESCAN_INSN (insn, NULL, 0);
#endif
#ifdef SDB_DEBUGGING_INFO
if (write_symbols == SDB_DEBUG && LABEL_NAME (insn))
sdbout_label (insn);
#endif
-#ifdef DWARF_DEBUGGING_INFO
- if (write_symbols == DWARF_DEBUG && LABEL_NAME (insn))
- dwarfout_label (insn);
-#endif
-#ifdef DWARF2_DEBUGGING_INFO
- if (write_symbols == DWARF2_DEBUG && LABEL_NAME (insn))
- dwarf2out_label (insn);
-#endif
if (app_on)
{
fputs (ASM_APP_OFF, file);
ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn),
NEXT_INSN (insn));
#else
- if (LABEL_ALTERNATE_NAME (insn))
- ASM_OUTPUT_ALTERNATE_LABEL_NAME (file, insn);
- else
- ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
+ if (LABEL_ALTERNATE_NAME (insn))
+ ASM_OUTPUT_ALTERNATE_LABEL_NAME (file, insn);
+ else
+ ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
#endif
#endif
break;
}
}
if (LABEL_ALTERNATE_NAME (insn))
- ASM_OUTPUT_ALTERNATE_LABEL_NAME (file, insn);
+ ASM_OUTPUT_ALTERNATE_LABEL_NAME (file, insn);
else
- ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
+ ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
break;
default:
#ifdef ASM_OUTPUT_ADDR_VEC
ASM_OUTPUT_ADDR_VEC (PREV_INSN (insn), body);
#else
- abort();
+ abort ();
#endif
}
else
#ifdef ASM_OUTPUT_ADDR_DIFF_VEC
ASM_OUTPUT_ADDR_DIFF_VEC (PREV_INSN (insn), body);
#else
- abort();
+ abort ();
#endif
}
#else
}
/* Get out the operand values. */
- string = decode_asm_operands (body, ops, NULL_PTR,
- NULL_PTR, NULL_PTR);
+ string = decode_asm_operands (body, ops, NULL, NULL, NULL);
/* Inhibit aborts on what would otherwise be compiler bugs. */
insn_noperands = noperands;
this_is_asm_operands = insn;
body = PATTERN (insn);
#ifdef HAVE_cc0
- set = single_set(insn);
+ set = single_set (insn);
/* Check for redundant test and compare instructions
(when the condition codes are already set up as desired).
if (optimize)
{
#if 0
- rtx set = single_set(insn);
+ rtx set = single_set (insn);
#endif
if (set
&& set != 0)
{
rtx cond_rtx, then_rtx, else_rtx;
-
+
if (GET_CODE (insn) != JUMP_INSN
&& GET_CODE (SET_SRC (set)) == IF_THEN_ELSE)
{
then_rtx = const_true_rtx;
else_rtx = const0_rtx;
}
-
+
switch (GET_CODE (cond_rtx))
{
case GTU:
since `reload' should have changed them so that they do. */
insn_code_number = recog_memoized (insn);
- extract_insn (insn);
cleanup_subreg_operands (insn);
- if (! constrain_operands (1))
+ /* Dump the insn in the assembly for debugging. */
+ if (flag_dump_rtl_in_asm)
+ {
+ print_rtx_head = ASM_COMMENT_START;
+ print_rtl_single (asm_out_file, insn);
+ print_rtx_head = "";
+ }
+
+ if (! constrain_operands_cached (1))
fatal_insn_not_found (insn);
/* Some target machines need to prescan each insn before
NOTICE_UPDATE_CC (body, insn);
#endif
- debug_insn = insn;
+ current_output_insn = debug_insn = insn;
#if defined (DWARF2_UNWIND_INFO)
- /* If we push arguments, we want to know where the calls are. */
- if (!ACCUMULATE_OUTGOING_ARGS && GET_CODE (insn) == CALL_INSN
- && dwarf2out_do_frame ())
+ if (GET_CODE (insn) == CALL_INSN && dwarf2out_do_frame ())
dwarf2out_frame_debug (insn);
#endif
needs to be reinserted. */
if (template == 0)
{
+ rtx prev;
+
if (prev_nonnote_insn (insn) != last_ignored_compare)
abort ();
new_block = 0;
- return prev_nonnote_insn (insn);
+
+ /* We have already processed the notes between the setter and
+ the user. Make sure we don't process them again, this is
+ particularly important if one of the notes is a block
+ scope note or an EH note. */
+ for (prev = insn;
+ prev != last_ignored_compare;
+ prev = PREV_INSN (prev))
+ {
+ if (GET_CODE (prev) == NOTE)
+ {
+ NOTE_LINE_NUMBER (prev) = NOTE_INSN_DELETED;
+ NOTE_SOURCE_FILE (prev) = 0;
+ }
+ }
+
+ return prev;
}
/* If the template is the string "#", it means that this insn must
/* If we didn't split the insn, go away. */
if (new == insn && PATTERN (new) == body)
fatal_insn ("Could not split insn", insn);
-
+
#ifdef HAVE_ATTR_length
/* This instruction should have been split in shorten_branches,
to ensure that we would have valid length info for the
new_block = 0;
return new;
}
-
+
if (prescan > 0)
break;
+#ifdef IA64_UNWIND_INFO
+ IA64_UNWIND_EMIT (asm_out_file, insn);
+#endif
/* Output assembler code from the template. */
output_asm_insn (template, recog_data.operand);
#if defined (DWARF2_UNWIND_INFO)
- /* If we push arguments, we need to check all insns for stack
- adjustments. */
- if (!ACCUMULATE_OUTGOING_ARGS)
- {
- if (GET_CODE (insn) == INSN && dwarf2out_do_frame ())
- dwarf2out_frame_debug (insn);
- }
- else
- {
#if defined (HAVE_prologue)
- /* If this insn is part of the prologue, emit DWARF v2
- call frame info. */
- if (RTX_FRAME_RELATED_P (insn) && dwarf2out_do_frame ())
- dwarf2out_frame_debug (insn);
+ if (GET_CODE (insn) == INSN && dwarf2out_do_frame ())
+ dwarf2out_frame_debug (insn);
+#else
+ if (!ACCUMULATE_OUTGOING_ARGS
+ && GET_CODE (insn) == INSN
+ && dwarf2out_do_frame ())
+ dwarf2out_frame_debug (insn);
#endif
- }
#endif
#if 0
INSN_DELETED_P (insn) = 1;
#endif
- debug_insn = 0;
+ current_output_insn = debug_insn = 0;
}
}
return NEXT_INSN (insn);
}
}
\f
-
/* For each operand in INSN, simplify (subreg (reg)) so that it refers
directly to the desired hard register. */
+
void
cleanup_subreg_operands (insn)
rtx insn;
{
int i;
-
- extract_insn (insn);
+ extract_insn_cached (insn);
for (i = 0; i < recog_data.n_operands; i++)
{
if (GET_CODE (recog_data.operand[i]) == SUBREG)
- recog_data.operand[i] = alter_subreg (recog_data.operand[i]);
+ recog_data.operand[i] = alter_subreg (recog_data.operand[i]);
else if (GET_CODE (recog_data.operand[i]) == PLUS
- || GET_CODE (recog_data.operand[i]) == MULT)
- recog_data.operand[i] = walk_alter_subreg (recog_data.operand[i]);
+ || GET_CODE (recog_data.operand[i]) == MULT
+ || GET_CODE (recog_data.operand[i]) == MEM)
+ recog_data.operand[i] = walk_alter_subreg (recog_data.operand[i]);
}
for (i = 0; i < recog_data.n_dups; i++)
{
if (GET_CODE (*recog_data.dup_loc[i]) == SUBREG)
- *recog_data.dup_loc[i] = alter_subreg (*recog_data.dup_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)
- *recog_data.dup_loc[i] = walk_alter_subreg (*recog_data.dup_loc[i]);
+ || GET_CODE (*recog_data.dup_loc[i]) == MULT
+ || GET_CODE (*recog_data.dup_loc[i]) == MEM)
+ *recog_data.dup_loc[i] = walk_alter_subreg (*recog_data.dup_loc[i]);
}
}
if (GET_CODE (y) == REG)
{
- int regno;
- /* If the word size is larger than the size of this register,
- adjust the register number to compensate. */
- /* ??? Note that this just catches stragglers created by/for
- integrate. It would be better if we either caught these
- earlier, or kept _all_ subregs until now and eliminate
- gen_lowpart and friends. */
-
-#ifdef ALTER_HARD_SUBREG
- regno = ALTER_HARD_SUBREG(GET_MODE (x), SUBREG_WORD (x),
- GET_MODE (y), REGNO (y));
-#else
- regno = REGNO (y) + SUBREG_WORD (x);
-#endif
+ int regno = subreg_hard_regno (x, 1);
+
PUT_CODE (x, REG);
REGNO (x) = regno;
+ ORIGINAL_REGNO (x) = ORIGINAL_REGNO (y);
/* This field has a different meaning for REGs and SUBREGs. Make sure
to clear it! */
x->used = 0;
}
else if (GET_CODE (y) == MEM)
{
- register int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
+ register int offset = SUBREG_BYTE (x);
+
+ /* Catch these instead of generating incorrect code. */
+ if ((offset % GET_MODE_SIZE (GET_MODE (x))) != 0)
+ abort ();
- if (BYTES_BIG_ENDIAN)
- offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x)))
- - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (y))));
PUT_CODE (x, MEM);
MEM_COPY_ATTRIBUTES (x, y);
XEXP (x, 0) = plus_constant (XEXP (y, 0), offset);
case SUBREG:
return alter_subreg (x);
-
+
default:
break;
}
PUT_CODE (cond, NE);
value = 2;
break;
-
+
default:
break;
}
PUT_CODE (cond, NE);
value = 2;
break;
-
+
default:
break;
}
case LTU:
/* Jump becomes no-op. */
return -1;
-
+
default:
break;
}
if (this_is_asm_operands)
error_for_asm (this_is_asm_operands, "invalid `asm': %s", _(msgid));
else
- {
- error ("output_operand: %s", _(msgid));
- abort ();
- }
+ internal_error ("output_operand: %s", _(msgid));
}
\f
/* Output of assembler code from a template, and its subroutines. */
if (debug_insn)
{
register int num = INSN_CODE (debug_insn);
- fprintf (asm_out_file, "\t%s %d\t%s",
+ fprintf (asm_out_file, "\t%s %d\t%s",
ASM_COMMENT_START, INSN_UID (debug_insn),
insn_data[num].name);
if (insn_data[num].n_alternatives > 1)
case '{':
{
register int i;
-
+
/* If we want the first dialect, do nothing. Otherwise, skip
DIALECT_NUMBER of strings ending with '|'. */
for (i = 0; i < dialect_number; i++)
Letters `acln' are implemented directly.
Other letters are passed to `output_operand' so that
the PRINT_OPERAND macro can define them. */
- else if (ISLOWER(*p) || ISUPPER(*p))
+ else if (ISLOWER (*p) || ISUPPER (*p))
{
int letter = *p++;
c = atoi (p);
}
else
output_operand (operands[c], letter);
-
- while ((c = *p) >= '0' && c <= '9') p++;
+
+ while ((c = *p) >= '0' && c <= '9')
+ p++;
}
/* % followed by a digit outputs an operand the default way. */
else if (*p >= '0' && *p <= '9')
{
c = atoi (p);
- if (this_is_asm_operands && (c < 0 || (unsigned int) c >= insn_noperands))
+ if (this_is_asm_operands
+ && (c < 0 || (unsigned int) c >= insn_noperands))
output_operand_lossage ("operand number out of range");
else
output_operand (operands[c], 0);
- while ((c = *p) >= '0' && c <= '9') p++;
+ while ((c = *p) >= '0' && c <= '9')
+ 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))
+ else if (PRINT_OPERAND_PUNCT_VALID_P ((unsigned char) *p))
output_operand (NULL_RTX, *p++);
#endif
else
break;
case SYMBOL_REF:
+#ifdef ASM_OUTPUT_SYMBOL_REF
+ ASM_OUTPUT_SYMBOL_REF (file, x);
+#else
assemble_name (file, XSTR (x, 0));
+#endif
break;
case LABEL_REF:
- ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0)));
- assemble_name (file, buf);
- break;
-
+ x = XEXP (x, 0);
+ /* Fall through. */
case CODE_LABEL:
ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
assemble_name (file, buf);
if (CONST_DOUBLE_HIGH (x))
fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x));
- else if (CONST_DOUBLE_LOW (x) < 0)
+ else if (CONST_DOUBLE_LOW (x) < 0)
fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (x));
else
fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x));
else
{
output_addr_const (file, XEXP (x, 0));
- if (INTVAL (XEXP (x, 1)) >= 0)
+ if (GET_CODE (XEXP (x, 1)) != CONST_INT
+ || 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 ((GET_CODE (XEXP (x, 1)) == CONST_INT
+ && INTVAL (XEXP (x, 1)) < 0)
+ || GET_CODE (XEXP (x, 1)) != CONST_INT)
{
fprintf (file, "%s", ASM_OPEN_PAREN);
output_addr_const (file, XEXP (x, 1));
break;
default:
+#ifdef OUTPUT_ADDR_CONST_EXTRA
+ OUTPUT_ADDR_CONST_EXTRA (file, x, fail);
+ break;
+
+ fail:
+#endif
output_operand_lossage ("invalid expression as operand");
}
}
if (*p == '|')
p++;
- }
+ }
}
break;
case 'M': case 'N': case 'P': case 'Q': case 'S':
case 'T': case 'V': case 'W': case 'Y': case 'Z':
break;
-
+
ASM_FPRINTF_EXTENSIONS (file, argptr, p)
#endif
default:
/* In this case the CONST_INT holds both target words.
Extract the bits from it into two word-sized pieces.
Sign extend each half to HOST_WIDE_INT. */
- rtx low, high;
- /* On machines where HOST_BITS_PER_WIDE_INT == BITS_PER_WORD
- the shift below will cause a compiler warning, even though
- this code won't be executed. So put the shift amounts in
- variables to avoid the warning. */
- int rshift = HOST_BITS_PER_WIDE_INT - BITS_PER_WORD;
- int lshift = HOST_BITS_PER_WIDE_INT - 2 * BITS_PER_WORD;
-
- low = GEN_INT ((INTVAL (value) << rshift) >> rshift);
- high = GEN_INT ((INTVAL (value) << lshift) >> rshift);
+ unsigned HOST_WIDE_INT low, high;
+ unsigned HOST_WIDE_INT mask, sign_bit, sign_extend;
+
+ /* Set sign_bit to the most significant bit of a word. */
+ sign_bit = 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
+ calculation on sign_bit. However, on machines where
+ HOST_BITS_PER_WIDE_INT == BITS_PER_WORD, it could cause a
+ compiler warning, even though the code would never be
+ executed. */
+ mask = sign_bit << 1;
+ mask--;
+
+ /* Set sign_extend as any remaining bits. */
+ sign_extend = ~mask;
+
+ /* Pick the lower word and sign-extend it. */
+ low = INTVAL (value);
+ low &= mask;
+ if (low & sign_bit)
+ low |= sign_extend;
+
+ /* Pick the higher word, shifted to the least significant
+ bits, and sign-extend it. */
+ high = INTVAL (value);
+ high >>= BITS_PER_WORD - 1;
+ high >>= 1;
+ high &= mask;
+ if (high & sign_bit)
+ high |= sign_extend;
+
+ /* Store the words in the target machine order. */
if (WORDS_BIG_ENDIAN)
{
- *first = high;
- *second = low;
+ *first = GEN_INT (high);
+ *second = GEN_INT (low);
}
else
{
- *first = low;
- *second = high;
+ *first = GEN_INT (low);
+ *second = GEN_INT (high);
}
}
else
else
{
#ifdef REAL_ARITHMETIC
- REAL_VALUE_TYPE r; long l[2];
+ REAL_VALUE_TYPE r;
+ long l[2];
REAL_VALUE_FROM_CONST_DOUBLE (r, value);
/* Note, this converts the REAL_VALUE_TYPE to the target's
if ((HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
|| HOST_BITS_PER_WIDE_INT != BITS_PER_WORD)
&& ! flag_pretend_float)
- abort ();
+ abort ();
if (
#ifdef HOST_WORDS_BIG_ENDIAN
leaf_function_p ()
{
rtx insn;
+ rtx link;
if (profile_flag || profile_block_flag || profile_arc_flag)
return 0;
&& ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0)))
return 0;
}
- for (insn = current_function_epilogue_delay_list; insn; insn = XEXP (insn, 1))
+ for (link = current_function_epilogue_delay_list;
+ link;
+ link = XEXP (link, 1))
{
- if (GET_CODE (XEXP (insn, 0)) == CALL_INSN
+ insn = XEXP (link, 0);
+
+ if (GET_CODE (insn) == CALL_INSN
&& ! SIBLING_CALL_P (insn))
return 0;
- if (GET_CODE (XEXP (insn, 0)) == INSN
- && GET_CODE (PATTERN (XEXP (insn, 0))) == SEQUENCE
- && GET_CODE (XVECEXP (PATTERN (XEXP (insn, 0)), 0, 0)) == CALL_INSN
- && ! SIBLING_CALL_P (XVECEXP (PATTERN (XEXP (insn, 0)), 0, 0)))
+ if (GET_CODE (insn) == INSN
+ && GET_CODE (PATTERN (insn)) == SEQUENCE
+ && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN
+ && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0)))
return 0;
}
return 1;
}
+/* Return 1 if branch is an forward branch.
+ Uses insn_shuid array, so it works only in the final pass. May be used by
+ output templates to customary add branch prediction hints.
+ */
+int
+final_forward_branch_p (insn)
+ rtx insn;
+{
+ int insn_id, label_id;
+ if (!uid_shuid)
+ abort ();
+ insn_id = INSN_SHUID (insn);
+ label_id = INSN_SHUID (JUMP_LABEL (insn));
+ /* We've hit some insns that does not have id information available. */
+ if (!insn_id || !label_id)
+ abort ();
+ return insn_id < label_id;
+}
+
/* On some machines, a function with no call insns
can run faster if it doesn't create its own register window.
When output, the leaf function should use only the "output"
The reg-notes can contain frame pointer refs,
and renumbering them could crash, and should not be needed. */
for (insn = first; insn; insn = NEXT_INSN (insn))
- if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+ if (INSN_P (insn))
leaf_renumber_regs_insn (PATTERN (insn));
- for (insn = current_function_epilogue_delay_list; insn; insn = XEXP (insn, 1))
- if (GET_RTX_CLASS (GET_CODE (XEXP (insn, 0))) == 'i')
+ for (insn = current_function_epilogue_delay_list;
+ insn;
+ insn = XEXP (insn, 1))
+ if (INSN_P (XEXP (insn, 0)))
leaf_renumber_regs_insn (PATTERN (XEXP (insn, 0)));
}
in_rtx->used = 1;
}
- if (GET_RTX_CLASS (GET_CODE (in_rtx)) == 'i')
+ if (INSN_P (in_rtx))
{
/* Inside a SEQUENCE, we find insns.
Renumber just the patterns of these insns,