final.c revision 132727
118334Speter/* Convert RTL to assembler code and output it, for GNU compiler.
290087Sobrien   Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
3132727Skan   1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
418334Speter
590087SobrienThis file is part of GCC.
618334Speter
790087SobrienGCC is free software; you can redistribute it and/or modify it under
890087Sobrienthe terms of the GNU General Public License as published by the Free
990087SobrienSoftware Foundation; either version 2, or (at your option) any later
1090087Sobrienversion.
1118334Speter
1290087SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY
1390087SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or
1490087SobrienFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1590087Sobrienfor more details.
1618334Speter
1718334SpeterYou should have received a copy of the GNU General Public License
1890087Sobrienalong with GCC; see the file COPYING.  If not, write to the Free
1990087SobrienSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA
2090087Sobrien02111-1307, USA.  */
2118334Speter
2218334Speter/* This is the final pass of the compiler.
2318334Speter   It looks at the rtl code for a function and outputs assembler code.
2418334Speter
2518334Speter   Call `final_start_function' to output the assembler code for function entry,
2618334Speter   `final' to output assembler code for some RTL code,
2718334Speter   `final_end_function' to output assembler code for function exit.
2818334Speter   If a function is compiled in several pieces, each piece is
2918334Speter   output separately with `final'.
3018334Speter
3118334Speter   Some optimizations are also done at this level.
3218334Speter   Move instructions that were made unnecessary by good register allocation
3318334Speter   are detected and omitted from the output.  (Though most of these
3418334Speter   are removed by the last jump pass.)
3518334Speter
3618334Speter   Instructions to set the condition codes are omitted when it can be
3718334Speter   seen that the condition codes already had the desired values.
3818334Speter
3918334Speter   In some cases it is sufficient if the inherited condition codes
4018334Speter   have related values, but this may require the following insn
4118334Speter   (the one that tests the condition codes) to be modified.
4218334Speter
4318334Speter   The code for the function prologue and epilogue are generated
4490087Sobrien   directly in assembler by the target functions function_prologue and
4590087Sobrien   function_epilogue.  Those instructions never exist as rtl.  */
4618334Speter
4718334Speter#include "config.h"
4850503Sobrien#include "system.h"
49132727Skan#include "coretypes.h"
50132727Skan#include "tm.h"
5118334Speter
5218334Speter#include "tree.h"
5318334Speter#include "rtl.h"
5490087Sobrien#include "tm_p.h"
5518334Speter#include "regs.h"
5618334Speter#include "insn-config.h"
5718334Speter#include "insn-attr.h"
5818334Speter#include "recog.h"
5918334Speter#include "conditions.h"
6018334Speter#include "flags.h"
6118334Speter#include "real.h"
6218334Speter#include "hard-reg-set.h"
6318334Speter#include "output.h"
6450503Sobrien#include "except.h"
6590087Sobrien#include "function.h"
6650503Sobrien#include "toplev.h"
6750503Sobrien#include "reload.h"
6852515Sobrien#include "intl.h"
6990087Sobrien#include "basic-block.h"
7090087Sobrien#include "target.h"
7190087Sobrien#include "debug.h"
7290087Sobrien#include "expr.h"
73117404Skan#include "cfglayout.h"
7418334Speter
7518334Speter#ifdef XCOFF_DEBUGGING_INFO
7690087Sobrien#include "xcoffout.h"		/* Needed for external data
7790087Sobrien				   declarations for e.g. AIX 4.x.  */
7818334Speter#endif
7918334Speter
8050503Sobrien#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
8150503Sobrien#include "dwarf2out.h"
8250503Sobrien#endif
8350503Sobrien
84132727Skan#ifdef DBX_DEBUGGING_INFO
85132727Skan#include "dbxout.h"
86132727Skan#endif
87132727Skan
8818334Speter/* If we aren't using cc0, CC_STATUS_INIT shouldn't exist.  So define a
8918334Speter   null default for it to save conditionalization later.  */
9018334Speter#ifndef CC_STATUS_INIT
9118334Speter#define CC_STATUS_INIT
9218334Speter#endif
9318334Speter
9418334Speter/* How to start an assembler comment.  */
9518334Speter#ifndef ASM_COMMENT_START
9618334Speter#define ASM_COMMENT_START ";#"
9718334Speter#endif
9818334Speter
9918334Speter/* Is the given character a logical line separator for the assembler?  */
10018334Speter#ifndef IS_ASM_LOGICAL_LINE_SEPARATOR
10118334Speter#define IS_ASM_LOGICAL_LINE_SEPARATOR(C) ((C) == ';')
10218334Speter#endif
10318334Speter
10450503Sobrien#ifndef JUMP_TABLES_IN_TEXT_SECTION
10550503Sobrien#define JUMP_TABLES_IN_TEXT_SECTION 0
10650503Sobrien#endif
10750503Sobrien
108117404Skan#if defined(READONLY_DATA_SECTION) || defined(READONLY_DATA_SECTION_ASM_OP)
109117404Skan#define HAVE_READONLY_DATA_SECTION 1
110117404Skan#else
111117404Skan#define HAVE_READONLY_DATA_SECTION 0
112117404Skan#endif
113117404Skan
114132727Skan/* Bitflags used by final_scan_insn.  */
115132727Skan#define SEEN_BB		1
116132727Skan#define SEEN_NOTE	2
117132727Skan#define SEEN_EMITTED	4
118132727Skan
11918334Speter/* Last insn processed by final_scan_insn.  */
12090087Sobrienstatic rtx debug_insn;
12190087Sobrienrtx current_output_insn;
12218334Speter
12318334Speter/* Line number of last NOTE.  */
12418334Speterstatic int last_linenum;
12518334Speter
12618334Speter/* Highest line number in current block.  */
12718334Speterstatic int high_block_linenum;
12818334Speter
12918334Speter/* Likewise for function.  */
13018334Speterstatic int high_function_linenum;
13118334Speter
13218334Speter/* Filename of last NOTE.  */
13390087Sobrienstatic const char *last_filename;
13418334Speter
13550503Sobrienextern int length_unit_log; /* This is defined in insn-attrtab.c.  */
13650503Sobrien
13718334Speter/* Nonzero while outputting an `asm' with operands.
13818334Speter   This means that inconsistencies are the user's fault, so don't abort.
13918334Speter   The precise value is the insn being output, to pass to error_for_asm.  */
140117404Skanrtx this_is_asm_operands;
14118334Speter
14218334Speter/* Number of operands of this insn, for an `asm' with operands.  */
14350503Sobrienstatic unsigned int insn_noperands;
14418334Speter
14518334Speter/* Compare optimization flag.  */
14618334Speter
14718334Speterstatic rtx last_ignored_compare = 0;
14818334Speter
14918334Speter/* Assign a unique number to each insn that is output.
15018334Speter   This can be used to generate unique local labels.  */
15118334Speter
15218334Speterstatic int insn_counter = 0;
15318334Speter
15418334Speter#ifdef HAVE_cc0
15518334Speter/* This variable contains machine-dependent flags (defined in tm.h)
15618334Speter   set and examined by output routines
15718334Speter   that describe how to interpret the condition codes properly.  */
15818334Speter
15918334SpeterCC_STATUS cc_status;
16018334Speter
16118334Speter/* During output of an insn, this contains a copy of cc_status
16218334Speter   from before the insn.  */
16318334Speter
16418334SpeterCC_STATUS cc_prev_status;
16518334Speter#endif
16618334Speter
16718334Speter/* Indexed by hardware reg number, is 1 if that register is ever
16818334Speter   used in the current function.
16918334Speter
17018334Speter   In life_analysis, or in stupid_life_analysis, this is set
17118334Speter   up to record the hard regs used explicitly.  Reload adds
17218334Speter   in the hard regs used for holding pseudo regs.  Final uses
17318334Speter   it to generate the code in the function prologue and epilogue
17418334Speter   to save and restore registers as needed.  */
17518334Speter
17618334Speterchar regs_ever_live[FIRST_PSEUDO_REGISTER];
17718334Speter
178132727Skan/* Like regs_ever_live, but 1 if a reg is set or clobbered from an asm.
179132727Skan   Unlike regs_ever_live, elements of this array corresponding to
180132727Skan   eliminable regs like the frame pointer are set if an asm sets them.  */
181132727Skan
182132727Skanchar regs_asm_clobbered[FIRST_PSEUDO_REGISTER];
183132727Skan
18418334Speter/* Nonzero means current function must be given a frame pointer.
185132727Skan   Initialized in function.c to 0.  Set only in reload1.c as per
186132727Skan   the needs of the function.  */
18718334Speter
18818334Speterint frame_pointer_needed;
18918334Speter
19090087Sobrien/* Number of unmatched NOTE_INSN_BLOCK_BEG notes we have seen.  */
19118334Speter
19218334Speterstatic int block_depth;
19318334Speter
19418334Speter/* Nonzero if have enabled APP processing of our assembler output.  */
19518334Speter
19618334Speterstatic int app_on;
19718334Speter
19818334Speter/* If we are outputting an insn sequence, this contains the sequence rtx.
19918334Speter   Zero otherwise.  */
20018334Speter
20118334Speterrtx final_sequence;
20218334Speter
20318334Speter#ifdef ASSEMBLER_DIALECT
20418334Speter
20518334Speter/* Number of the assembler dialect to use, starting at 0.  */
20618334Speterstatic int dialect_number;
20718334Speter#endif
20818334Speter
20990087Sobrien#ifdef HAVE_conditional_execution
21090087Sobrien/* Nonnull if the insn currently being emitted was a COND_EXEC pattern.  */
21190087Sobrienrtx current_insn_predicate;
21290087Sobrien#endif
21318334Speter
21450503Sobrien#ifdef HAVE_ATTR_length
215132727Skanstatic int asm_insn_count (rtx);
21650503Sobrien#endif
217132727Skanstatic void profile_function (FILE *);
218132727Skanstatic void profile_after_prologue (FILE *);
219132727Skanstatic bool notice_source_line (rtx);
220132727Skanstatic rtx walk_alter_subreg (rtx *);
221132727Skanstatic void output_asm_name (void);
222132727Skanstatic void output_alternate_entry_point (FILE *, rtx);
223132727Skanstatic tree get_mem_expr_from_op (rtx, int *);
224132727Skanstatic void output_asm_operand_names (rtx *, int *, int);
225132727Skanstatic void output_operand (rtx, int);
22650503Sobrien#ifdef LEAF_REGISTERS
227132727Skanstatic void leaf_renumber_regs (rtx);
22850503Sobrien#endif
22950503Sobrien#ifdef HAVE_cc0
230132727Skanstatic int alter_cond (rtx);
23150503Sobrien#endif
23290087Sobrien#ifndef ADDR_VEC_ALIGN
233132727Skanstatic int final_addr_vec_align (rtx);
23490087Sobrien#endif
23590087Sobrien#ifdef HAVE_ATTR_length
236132727Skanstatic int align_fuzz (rtx, rtx, int, unsigned);
23790087Sobrien#endif
23818334Speter
23918334Speter/* Initialize data in final at the beginning of a compilation.  */
24018334Speter
24118334Spetervoid
242132727Skaninit_final (const char *filename ATTRIBUTE_UNUSED)
24318334Speter{
24418334Speter  app_on = 0;
24518334Speter  final_sequence = 0;
24618334Speter
24718334Speter#ifdef ASSEMBLER_DIALECT
24818334Speter  dialect_number = ASSEMBLER_DIALECT;
24918334Speter#endif
25018334Speter}
25118334Speter
25290087Sobrien/* Default target function prologue and epilogue assembler output.
25318334Speter
25490087Sobrien   If not overridden for epilogue code, then the function body itself
25590087Sobrien   contains return instructions wherever needed.  */
25690087Sobrienvoid
257132727Skandefault_function_pro_epilogue (FILE *file ATTRIBUTE_UNUSED,
258132727Skan			       HOST_WIDE_INT size ATTRIBUTE_UNUSED)
25990087Sobrien{
26090087Sobrien}
26118334Speter
26290087Sobrien/* Default target hook that outputs nothing to a stream.  */
26390087Sobrienvoid
264132727Skanno_asm_to_stream (FILE *file ATTRIBUTE_UNUSED)
26590087Sobrien{
26618334Speter}
26718334Speter
26818334Speter/* Enable APP processing of subsequent output.
26918334Speter   Used before the output from an `asm' statement.  */
27018334Speter
27118334Spetervoid
272132727Skanapp_enable (void)
27318334Speter{
27418334Speter  if (! app_on)
27518334Speter    {
27650503Sobrien      fputs (ASM_APP_ON, asm_out_file);
27718334Speter      app_on = 1;
27818334Speter    }
27918334Speter}
28018334Speter
28118334Speter/* Disable APP processing of subsequent output.
28218334Speter   Called from varasm.c before most kinds of output.  */
28318334Speter
28418334Spetervoid
285132727Skanapp_disable (void)
28618334Speter{
28718334Speter  if (app_on)
28818334Speter    {
28950503Sobrien      fputs (ASM_APP_OFF, asm_out_file);
29018334Speter      app_on = 0;
29118334Speter    }
29218334Speter}
29318334Speter
29490087Sobrien/* Return the number of slots filled in the current
29518334Speter   delayed branch sequence (we don't count the insn needing the
29618334Speter   delay slot).   Zero if not in a delayed branch sequence.  */
29718334Speter
29818334Speter#ifdef DELAY_SLOTS
29918334Speterint
300132727Skandbr_sequence_length (void)
30118334Speter{
30218334Speter  if (final_sequence != 0)
30318334Speter    return XVECLEN (final_sequence, 0) - 1;
30418334Speter  else
30518334Speter    return 0;
30618334Speter}
30718334Speter#endif
30818334Speter
30918334Speter/* The next two pages contain routines used to compute the length of an insn
31018334Speter   and to shorten branches.  */
31118334Speter
31218334Speter/* Arrays for insn lengths, and addresses.  The latter is referenced by
31318334Speter   `insn_current_length'.  */
31418334Speter
31590087Sobrienstatic int *insn_lengths;
31618334Speter
31790087Sobrienvarray_type insn_addresses_;
31890087Sobrien
31952515Sobrien/* Max uid for which the above arrays are valid.  */
32052515Sobrienstatic int insn_lengths_max_uid;
32152515Sobrien
32218334Speter/* Address of insn being processed.  Used by `insn_current_length'.  */
32318334Speterint insn_current_address;
32418334Speter
32550503Sobrien/* Address of insn being processed in previous iteration.  */
32650503Sobrienint insn_last_address;
32750503Sobrien
32890087Sobrien/* known invariant alignment of insn being processed.  */
32950503Sobrienint insn_current_align;
33050503Sobrien
33150503Sobrien/* After shorten_branches, for any insn, uid_align[INSN_UID (insn)]
33250503Sobrien   gives the next following alignment insn that increases the known
33350503Sobrien   alignment, or NULL_RTX if there is no such insn.
33450503Sobrien   For any alignment obtained this way, we can again index uid_align with
33550503Sobrien   its uid to obtain the next following align that in turn increases the
33650503Sobrien   alignment, till we reach NULL_RTX; the sequence obtained this way
33750503Sobrien   for each insn we'll call the alignment chain of this insn in the following
33850503Sobrien   comments.  */
33950503Sobrien
34090087Sobrienstruct label_alignment
34190087Sobrien{
34250503Sobrien  short alignment;
34350503Sobrien  short max_skip;
34450503Sobrien};
34550503Sobrien
34650503Sobrienstatic rtx *uid_align;
34750503Sobrienstatic int *uid_shuid;
34850503Sobrienstatic struct label_alignment *label_align;
34950503Sobrien
35018334Speter/* Indicate that branch shortening hasn't yet been done.  */
35118334Speter
35218334Spetervoid
353132727Skaninit_insn_lengths (void)
35418334Speter{
35550503Sobrien  if (uid_shuid)
35650503Sobrien    {
35750503Sobrien      free (uid_shuid);
35850503Sobrien      uid_shuid = 0;
35950503Sobrien    }
36050503Sobrien  if (insn_lengths)
36150503Sobrien    {
36250503Sobrien      free (insn_lengths);
36350503Sobrien      insn_lengths = 0;
36452515Sobrien      insn_lengths_max_uid = 0;
36550503Sobrien    }
36690087Sobrien#ifdef HAVE_ATTR_length
36790087Sobrien  INSN_ADDRESSES_FREE ();
36890087Sobrien#endif
36950503Sobrien  if (uid_align)
37050503Sobrien    {
37150503Sobrien      free (uid_align);
37250503Sobrien      uid_align = 0;
37350503Sobrien    }
37418334Speter}
37518334Speter
37618334Speter/* Obtain the current length of an insn.  If branch shortening has been done,
37718334Speter   get its actual length.  Otherwise, get its maximum length.  */
37818334Speter
37918334Speterint
380132727Skanget_attr_length (rtx insn ATTRIBUTE_UNUSED)
38118334Speter{
38218334Speter#ifdef HAVE_ATTR_length
38318334Speter  rtx body;
38418334Speter  int i;
38518334Speter  int length = 0;
38618334Speter
38752515Sobrien  if (insn_lengths_max_uid > INSN_UID (insn))
38818334Speter    return insn_lengths[INSN_UID (insn)];
38918334Speter  else
39018334Speter    switch (GET_CODE (insn))
39118334Speter      {
39218334Speter      case NOTE:
39318334Speter      case BARRIER:
39418334Speter      case CODE_LABEL:
39518334Speter	return 0;
39618334Speter
39718334Speter      case CALL_INSN:
39818334Speter	length = insn_default_length (insn);
39918334Speter	break;
40018334Speter
40118334Speter      case JUMP_INSN:
40218334Speter	body = PATTERN (insn);
403117404Skan	if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
40418334Speter	  {
40550503Sobrien	    /* Alignment is machine-dependent and should be handled by
40650503Sobrien	       ADDR_VEC_ALIGN.  */
40718334Speter	  }
40818334Speter	else
40918334Speter	  length = insn_default_length (insn);
41018334Speter	break;
41118334Speter
41218334Speter      case INSN:
41318334Speter	body = PATTERN (insn);
41418334Speter	if (GET_CODE (body) == USE || GET_CODE (body) == CLOBBER)
41518334Speter	  return 0;
41618334Speter
41718334Speter	else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0)
41818334Speter	  length = asm_insn_count (body) * insn_default_length (insn);
41918334Speter	else if (GET_CODE (body) == SEQUENCE)
42018334Speter	  for (i = 0; i < XVECLEN (body, 0); i++)
42118334Speter	    length += get_attr_length (XVECEXP (body, 0, i));
42218334Speter	else
42318334Speter	  length = insn_default_length (insn);
42450503Sobrien	break;
42550503Sobrien
42650503Sobrien      default:
42750503Sobrien	break;
42818334Speter      }
42918334Speter
43018334Speter#ifdef ADJUST_INSN_LENGTH
43118334Speter  ADJUST_INSN_LENGTH (insn, length);
43218334Speter#endif
43318334Speter  return length;
43418334Speter#else /* not HAVE_ATTR_length */
43518334Speter  return 0;
43618334Speter#endif /* not HAVE_ATTR_length */
43718334Speter}
43818334Speter
43950503Sobrien/* Code to handle alignment inside shorten_branches.  */
44050503Sobrien
44150503Sobrien/* Here is an explanation how the algorithm in align_fuzz can give
44250503Sobrien   proper results:
44350503Sobrien
44450503Sobrien   Call a sequence of instructions beginning with alignment point X
44550503Sobrien   and continuing until the next alignment point `block X'.  When `X'
44690087Sobrien   is used in an expression, it means the alignment value of the
44750503Sobrien   alignment point.
44890087Sobrien
44950503Sobrien   Call the distance between the start of the first insn of block X, and
45050503Sobrien   the end of the last insn of block X `IX', for the `inner size of X'.
45150503Sobrien   This is clearly the sum of the instruction lengths.
45290087Sobrien
45350503Sobrien   Likewise with the next alignment-delimited block following X, which we
45450503Sobrien   shall call block Y.
45590087Sobrien
45650503Sobrien   Call the distance between the start of the first insn of block X, and
45750503Sobrien   the start of the first insn of block Y `OX', for the `outer size of X'.
45890087Sobrien
45950503Sobrien   The estimated padding is then OX - IX.
46090087Sobrien
46150503Sobrien   OX can be safely estimated as
46290087Sobrien
46350503Sobrien           if (X >= Y)
46450503Sobrien                   OX = round_up(IX, Y)
46550503Sobrien           else
46650503Sobrien                   OX = round_up(IX, X) + Y - X
46790087Sobrien
46850503Sobrien   Clearly est(IX) >= real(IX), because that only depends on the
46950503Sobrien   instruction lengths, and those being overestimated is a given.
47090087Sobrien
47150503Sobrien   Clearly round_up(foo, Z) >= round_up(bar, Z) if foo >= bar, so
47250503Sobrien   we needn't worry about that when thinking about OX.
47390087Sobrien
47450503Sobrien   When X >= Y, the alignment provided by Y adds no uncertainty factor
47550503Sobrien   for branch ranges starting before X, so we can just round what we have.
47650503Sobrien   But when X < Y, we don't know anything about the, so to speak,
47750503Sobrien   `middle bits', so we have to assume the worst when aligning up from an
47850503Sobrien   address mod X to one mod Y, which is Y - X.  */
47950503Sobrien
48050503Sobrien#ifndef LABEL_ALIGN
48190087Sobrien#define LABEL_ALIGN(LABEL) align_labels_log
48250503Sobrien#endif
48350503Sobrien
48450503Sobrien#ifndef LABEL_ALIGN_MAX_SKIP
48590087Sobrien#define LABEL_ALIGN_MAX_SKIP align_labels_max_skip
48650503Sobrien#endif
48750503Sobrien
48850503Sobrien#ifndef LOOP_ALIGN
48990087Sobrien#define LOOP_ALIGN(LABEL) align_loops_log
49050503Sobrien#endif
49150503Sobrien
49250503Sobrien#ifndef LOOP_ALIGN_MAX_SKIP
49390087Sobrien#define LOOP_ALIGN_MAX_SKIP align_loops_max_skip
49450503Sobrien#endif
49550503Sobrien
49650503Sobrien#ifndef LABEL_ALIGN_AFTER_BARRIER
49750503Sobrien#define LABEL_ALIGN_AFTER_BARRIER(LABEL) 0
49850503Sobrien#endif
49950503Sobrien
50050503Sobrien#ifndef LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP
50150503Sobrien#define LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP 0
50250503Sobrien#endif
50350503Sobrien
50490087Sobrien#ifndef JUMP_ALIGN
50590087Sobrien#define JUMP_ALIGN(LABEL) align_jumps_log
50690087Sobrien#endif
50790087Sobrien
50890087Sobrien#ifndef JUMP_ALIGN_MAX_SKIP
50990087Sobrien#define JUMP_ALIGN_MAX_SKIP align_jumps_max_skip
51090087Sobrien#endif
51190087Sobrien
51250503Sobrien#ifndef ADDR_VEC_ALIGN
51390087Sobrienstatic int
514132727Skanfinal_addr_vec_align (rtx addr_vec)
51550503Sobrien{
51690087Sobrien  int align = GET_MODE_SIZE (GET_MODE (PATTERN (addr_vec)));
51750503Sobrien
51850503Sobrien  if (align > BIGGEST_ALIGNMENT / BITS_PER_UNIT)
51950503Sobrien    align = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
52090087Sobrien  return exact_log2 (align);
52150503Sobrien
52250503Sobrien}
52390087Sobrien
52450503Sobrien#define ADDR_VEC_ALIGN(ADDR_VEC) final_addr_vec_align (ADDR_VEC)
52550503Sobrien#endif
52650503Sobrien
52750503Sobrien#ifndef INSN_LENGTH_ALIGNMENT
52850503Sobrien#define INSN_LENGTH_ALIGNMENT(INSN) length_unit_log
52950503Sobrien#endif
53050503Sobrien
53150503Sobrien#define INSN_SHUID(INSN) (uid_shuid[INSN_UID (INSN)])
53250503Sobrien
53350503Sobrienstatic int min_labelno, max_labelno;
53450503Sobrien
53550503Sobrien#define LABEL_TO_ALIGNMENT(LABEL) \
53650503Sobrien  (label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno].alignment)
53750503Sobrien
53850503Sobrien#define LABEL_TO_MAX_SKIP(LABEL) \
53950503Sobrien  (label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno].max_skip)
54050503Sobrien
54150503Sobrien/* For the benefit of port specific code do this also as a function.  */
54290087Sobrien
54350503Sobrienint
544132727Skanlabel_to_alignment (rtx label)
54550503Sobrien{
54650503Sobrien  return LABEL_TO_ALIGNMENT (label);
54750503Sobrien}
54850503Sobrien
54950503Sobrien#ifdef HAVE_ATTR_length
55050503Sobrien/* The differences in addresses
55150503Sobrien   between a branch and its target might grow or shrink depending on
55250503Sobrien   the alignment the start insn of the range (the branch for a forward
55350503Sobrien   branch or the label for a backward branch) starts out on; if these
55450503Sobrien   differences are used naively, they can even oscillate infinitely.
55550503Sobrien   We therefore want to compute a 'worst case' address difference that
55650503Sobrien   is independent of the alignment the start insn of the range end
55750503Sobrien   up on, and that is at least as large as the actual difference.
55850503Sobrien   The function align_fuzz calculates the amount we have to add to the
55950503Sobrien   naively computed difference, by traversing the part of the alignment
56050503Sobrien   chain of the start insn of the range that is in front of the end insn
56150503Sobrien   of the range, and considering for each alignment the maximum amount
56250503Sobrien   that it might contribute to a size increase.
56350503Sobrien
56450503Sobrien   For casesi tables, we also want to know worst case minimum amounts of
56550503Sobrien   address difference, in case a machine description wants to introduce
56650503Sobrien   some common offset that is added to all offsets in a table.
56790087Sobrien   For this purpose, align_fuzz with a growth argument of 0 computes the
56850503Sobrien   appropriate adjustment.  */
56950503Sobrien
57050503Sobrien/* Compute the maximum delta by which the difference of the addresses of
57150503Sobrien   START and END might grow / shrink due to a different address for start
57250503Sobrien   which changes the size of alignment insns between START and END.
57350503Sobrien   KNOWN_ALIGN_LOG is the alignment known for START.
57450503Sobrien   GROWTH should be ~0 if the objective is to compute potential code size
57550503Sobrien   increase, and 0 if the objective is to compute potential shrink.
57650503Sobrien   The return value is undefined for any other value of GROWTH.  */
57790087Sobrien
57890087Sobrienstatic int
579132727Skanalign_fuzz (rtx start, rtx end, int known_align_log, unsigned int growth)
58050503Sobrien{
58150503Sobrien  int uid = INSN_UID (start);
58250503Sobrien  rtx align_label;
58350503Sobrien  int known_align = 1 << known_align_log;
58450503Sobrien  int end_shuid = INSN_SHUID (end);
58550503Sobrien  int fuzz = 0;
58650503Sobrien
58750503Sobrien  for (align_label = uid_align[uid]; align_label; align_label = uid_align[uid])
58850503Sobrien    {
58950503Sobrien      int align_addr, new_align;
59050503Sobrien
59150503Sobrien      uid = INSN_UID (align_label);
59290087Sobrien      align_addr = INSN_ADDRESSES (uid) - insn_lengths[uid];
59350503Sobrien      if (uid_shuid[uid] > end_shuid)
59450503Sobrien	break;
59550503Sobrien      known_align_log = LABEL_TO_ALIGNMENT (align_label);
59650503Sobrien      new_align = 1 << known_align_log;
59750503Sobrien      if (new_align < known_align)
59850503Sobrien	continue;
59950503Sobrien      fuzz += (-align_addr ^ growth) & (new_align - known_align);
60050503Sobrien      known_align = new_align;
60150503Sobrien    }
60250503Sobrien  return fuzz;
60350503Sobrien}
60450503Sobrien
60550503Sobrien/* Compute a worst-case reference address of a branch so that it
60650503Sobrien   can be safely used in the presence of aligned labels.  Since the
60750503Sobrien   size of the branch itself is unknown, the size of the branch is
60850503Sobrien   not included in the range.  I.e. for a forward branch, the reference
60950503Sobrien   address is the end address of the branch as known from the previous
61050503Sobrien   branch shortening pass, minus a value to account for possible size
61150503Sobrien   increase due to alignment.  For a backward branch, it is the start
61250503Sobrien   address of the branch as known from the current pass, plus a value
61350503Sobrien   to account for possible size increase due to alignment.
61450503Sobrien   NB.: Therefore, the maximum offset allowed for backward branches needs
61550503Sobrien   to exclude the branch size.  */
61690087Sobrien
61750503Sobrienint
618132727Skaninsn_current_reference_address (rtx branch)
61950503Sobrien{
62090087Sobrien  rtx dest, seq;
62190087Sobrien  int seq_uid;
62290087Sobrien
62390087Sobrien  if (! INSN_ADDRESSES_SET_P ())
62490087Sobrien    return 0;
62590087Sobrien
62690087Sobrien  seq = NEXT_INSN (PREV_INSN (branch));
62790087Sobrien  seq_uid = INSN_UID (seq);
62850503Sobrien  if (GET_CODE (branch) != JUMP_INSN)
62950503Sobrien    /* This can happen for example on the PA; the objective is to know the
63050503Sobrien       offset to address something in front of the start of the function.
63150503Sobrien       Thus, we can treat it like a backward branch.
63250503Sobrien       We assume here that FUNCTION_BOUNDARY / BITS_PER_UNIT is larger than
63350503Sobrien       any alignment we'd encounter, so we skip the call to align_fuzz.  */
63450503Sobrien    return insn_current_address;
63550503Sobrien  dest = JUMP_LABEL (branch);
63690087Sobrien
63790087Sobrien  /* BRANCH has no proper alignment chain set, so use SEQ.
63890087Sobrien     BRANCH also has no INSN_SHUID.  */
63990087Sobrien  if (INSN_SHUID (seq) < INSN_SHUID (dest))
64050503Sobrien    {
64190087Sobrien      /* Forward branch.  */
64250503Sobrien      return (insn_last_address + insn_lengths[seq_uid]
64350503Sobrien	      - align_fuzz (seq, dest, length_unit_log, ~0));
64450503Sobrien    }
64550503Sobrien  else
64650503Sobrien    {
64790087Sobrien      /* Backward branch.  */
64850503Sobrien      return (insn_current_address
64950503Sobrien	      + align_fuzz (dest, seq, length_unit_log, ~0));
65050503Sobrien    }
65150503Sobrien}
65250503Sobrien#endif /* HAVE_ATTR_length */
65350503Sobrien
65490087Sobrienvoid
655132727Skancompute_alignments (void)
65690087Sobrien{
65790087Sobrien  int log, max_skip, max_log;
658117404Skan  basic_block bb;
65990087Sobrien
66090087Sobrien  if (label_align)
66190087Sobrien    {
66290087Sobrien      free (label_align);
66390087Sobrien      label_align = 0;
66490087Sobrien    }
66590087Sobrien
66690087Sobrien  max_labelno = max_label_num ();
66790087Sobrien  min_labelno = get_first_label_num ();
668132727Skan  label_align = xcalloc (max_labelno - min_labelno + 1,
669132727Skan			 sizeof (struct label_alignment));
67090087Sobrien
67190087Sobrien  /* If not optimizing or optimizing for size, don't assign any alignments.  */
67290087Sobrien  if (! optimize || optimize_size)
67390087Sobrien    return;
67490087Sobrien
675117404Skan  FOR_EACH_BB (bb)
67690087Sobrien    {
677132727Skan      rtx label = BB_HEAD (bb);
67890087Sobrien      int fallthru_frequency = 0, branch_frequency = 0, has_fallthru = 0;
67990087Sobrien      edge e;
68090087Sobrien
681132727Skan      if (GET_CODE (label) != CODE_LABEL
682132727Skan	  || probably_never_executed_bb_p (bb))
68390087Sobrien	continue;
68490087Sobrien      max_log = LABEL_ALIGN (label);
68590087Sobrien      max_skip = LABEL_ALIGN_MAX_SKIP;
68690087Sobrien
68790087Sobrien      for (e = bb->pred; e; e = e->pred_next)
68890087Sobrien	{
68990087Sobrien	  if (e->flags & EDGE_FALLTHRU)
69090087Sobrien	    has_fallthru = 1, fallthru_frequency += EDGE_FREQUENCY (e);
69190087Sobrien	  else
69290087Sobrien	    branch_frequency += EDGE_FREQUENCY (e);
69390087Sobrien	}
69490087Sobrien
69590087Sobrien      /* There are two purposes to align block with no fallthru incoming edge:
69690087Sobrien	 1) to avoid fetch stalls when branch destination is near cache boundary
69790087Sobrien	 2) to improve cache efficiency in case the previous block is not executed
69890087Sobrien	    (so it does not need to be in the cache).
69990087Sobrien
70090087Sobrien	 We to catch first case, we align frequently executed blocks.
70190087Sobrien	 To catch the second, we align blocks that are executed more frequently
70290087Sobrien	 than the predecessor and the predecessor is likely to not be executed
70390087Sobrien	 when function is called.  */
70490087Sobrien
70590087Sobrien      if (!has_fallthru
70690087Sobrien	  && (branch_frequency > BB_FREQ_MAX / 10
707117404Skan	      || (bb->frequency > bb->prev_bb->frequency * 10
708117404Skan		  && (bb->prev_bb->frequency
70990087Sobrien		      <= ENTRY_BLOCK_PTR->frequency / 2))))
71090087Sobrien	{
71190087Sobrien	  log = JUMP_ALIGN (label);
71290087Sobrien	  if (max_log < log)
71390087Sobrien	    {
71490087Sobrien	      max_log = log;
71590087Sobrien	      max_skip = JUMP_ALIGN_MAX_SKIP;
71690087Sobrien	    }
71790087Sobrien	}
71890087Sobrien      /* In case block is frequent and reached mostly by non-fallthru edge,
719117404Skan	 align it.  It is most likely a first block of loop.  */
72090087Sobrien      if (has_fallthru
721132727Skan	  && maybe_hot_bb_p (bb)
72290087Sobrien	  && branch_frequency + fallthru_frequency > BB_FREQ_MAX / 10
723117404Skan	  && branch_frequency > fallthru_frequency * 2)
72490087Sobrien	{
72590087Sobrien	  log = LOOP_ALIGN (label);
72690087Sobrien	  if (max_log < log)
72790087Sobrien	    {
72890087Sobrien	      max_log = log;
72990087Sobrien	      max_skip = LOOP_ALIGN_MAX_SKIP;
73090087Sobrien	    }
73190087Sobrien	}
73290087Sobrien      LABEL_TO_ALIGNMENT (label) = max_log;
73390087Sobrien      LABEL_TO_MAX_SKIP (label) = max_skip;
73490087Sobrien    }
73590087Sobrien}
73690087Sobrien
73718334Speter/* Make a pass over all insns and compute their actual lengths by shortening
73818334Speter   any branches of variable length if possible.  */
73918334Speter
74050503Sobrien/* shorten_branches might be called multiple times:  for example, the SH
74150503Sobrien   port splits out-of-range conditional branches in MACHINE_DEPENDENT_REORG.
74250503Sobrien   In order to do this, it needs proper length information, which it obtains
74350503Sobrien   by calling shorten_branches.  This cannot be collapsed with
74490087Sobrien   shorten_branches itself into a single pass unless we also want to integrate
74550503Sobrien   reorg.c, since the branch splitting exposes new instructions with delay
74650503Sobrien   slots.  */
74750503Sobrien
74818334Spetervoid
749132727Skanshorten_branches (rtx first ATTRIBUTE_UNUSED)
75018334Speter{
75150503Sobrien  rtx insn;
75250503Sobrien  int max_uid;
75350503Sobrien  int i;
75450503Sobrien  int max_log;
75550503Sobrien  int max_skip;
75618334Speter#ifdef HAVE_ATTR_length
75750503Sobrien#define MAX_CODE_ALIGN 16
75850503Sobrien  rtx seq;
75918334Speter  int something_changed = 1;
76018334Speter  char *varying_length;
76118334Speter  rtx body;
76218334Speter  int uid;
76350503Sobrien  rtx align_tab[MAX_CODE_ALIGN];
76418334Speter
76550503Sobrien#endif
76618334Speter
76750503Sobrien  /* Compute maximum UID and allocate label_align / uid_shuid.  */
76850503Sobrien  max_uid = get_max_uid ();
76950503Sobrien
770132727Skan  uid_shuid = xmalloc (max_uid * sizeof *uid_shuid);
77150503Sobrien
77290087Sobrien  if (max_labelno != max_label_num ())
77390087Sobrien    {
77490087Sobrien      int old = max_labelno;
77590087Sobrien      int n_labels;
77690087Sobrien      int n_old_labels;
77790087Sobrien
77890087Sobrien      max_labelno = max_label_num ();
77990087Sobrien
78090087Sobrien      n_labels = max_labelno - min_labelno + 1;
78190087Sobrien      n_old_labels = old - min_labelno + 1;
78290087Sobrien
783132727Skan      label_align = xrealloc (label_align,
784132727Skan			      n_labels * sizeof (struct label_alignment));
78590087Sobrien
78690087Sobrien      /* Range of labels grows monotonically in the function.  Abort here
78790087Sobrien         means that the initialization of array got lost.  */
78890087Sobrien      if (n_old_labels > n_labels)
78990087Sobrien	abort ();
79090087Sobrien
79190087Sobrien      memset (label_align + n_old_labels, 0,
79290087Sobrien	      (n_labels - n_old_labels) * sizeof (struct label_alignment));
79390087Sobrien    }
79490087Sobrien
79550503Sobrien  /* Initialize label_align and set up uid_shuid to be strictly
79650503Sobrien     monotonically rising with insn order.  */
79750503Sobrien  /* We use max_log here to keep track of the maximum alignment we want to
79850503Sobrien     impose on the next CODE_LABEL (or the current one if we are processing
79950503Sobrien     the CODE_LABEL itself).  */
80090087Sobrien
80150503Sobrien  max_log = 0;
80250503Sobrien  max_skip = 0;
80350503Sobrien
80450503Sobrien  for (insn = get_insns (), i = 1; insn; insn = NEXT_INSN (insn))
80550503Sobrien    {
80650503Sobrien      int log;
80750503Sobrien
80850503Sobrien      INSN_SHUID (insn) = i++;
80990087Sobrien      if (INSN_P (insn))
81050503Sobrien	{
81150503Sobrien	  /* reorg might make the first insn of a loop being run once only,
81250503Sobrien             and delete the label in front of it.  Then we want to apply
81350503Sobrien             the loop alignment to the new label created by reorg, which
81450503Sobrien             is separated by the former loop start insn from the
81550503Sobrien	     NOTE_INSN_LOOP_BEG.  */
81650503Sobrien	}
81750503Sobrien      else if (GET_CODE (insn) == CODE_LABEL)
81850503Sobrien	{
81950503Sobrien	  rtx next;
82050503Sobrien
82190087Sobrien	  /* Merge in alignments computed by compute_alignments.  */
82290087Sobrien	  log = LABEL_TO_ALIGNMENT (insn);
82390087Sobrien	  if (max_log < log)
82490087Sobrien	    {
82590087Sobrien	      max_log = log;
82690087Sobrien	      max_skip = LABEL_TO_MAX_SKIP (insn);
82790087Sobrien	    }
82890087Sobrien
82950503Sobrien	  log = LABEL_ALIGN (insn);
83050503Sobrien	  if (max_log < log)
83150503Sobrien	    {
83250503Sobrien	      max_log = log;
83350503Sobrien	      max_skip = LABEL_ALIGN_MAX_SKIP;
83450503Sobrien	    }
83550503Sobrien	  next = NEXT_INSN (insn);
83650503Sobrien	  /* ADDR_VECs only take room if read-only data goes into the text
83750503Sobrien	     section.  */
838117404Skan	  if (JUMP_TABLES_IN_TEXT_SECTION || !HAVE_READONLY_DATA_SECTION)
83950503Sobrien	    if (next && GET_CODE (next) == JUMP_INSN)
84050503Sobrien	      {
84150503Sobrien		rtx nextbody = PATTERN (next);
84250503Sobrien		if (GET_CODE (nextbody) == ADDR_VEC
84350503Sobrien		    || GET_CODE (nextbody) == ADDR_DIFF_VEC)
84450503Sobrien		  {
84550503Sobrien		    log = ADDR_VEC_ALIGN (next);
84650503Sobrien		    if (max_log < log)
84750503Sobrien		      {
84850503Sobrien			max_log = log;
84950503Sobrien			max_skip = LABEL_ALIGN_MAX_SKIP;
85050503Sobrien		      }
85150503Sobrien		  }
85250503Sobrien	      }
85350503Sobrien	  LABEL_TO_ALIGNMENT (insn) = max_log;
85450503Sobrien	  LABEL_TO_MAX_SKIP (insn) = max_skip;
85550503Sobrien	  max_log = 0;
85650503Sobrien	  max_skip = 0;
85750503Sobrien	}
85850503Sobrien      else if (GET_CODE (insn) == BARRIER)
85950503Sobrien	{
86050503Sobrien	  rtx label;
86150503Sobrien
86290087Sobrien	  for (label = insn; label && ! INSN_P (label);
86350503Sobrien	       label = NEXT_INSN (label))
86450503Sobrien	    if (GET_CODE (label) == CODE_LABEL)
86550503Sobrien	      {
86650503Sobrien		log = LABEL_ALIGN_AFTER_BARRIER (insn);
86750503Sobrien		if (max_log < log)
86850503Sobrien		  {
86950503Sobrien		    max_log = log;
87050503Sobrien		    max_skip = LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP;
87150503Sobrien		  }
87250503Sobrien		break;
87350503Sobrien	      }
87450503Sobrien	}
87550503Sobrien    }
87650503Sobrien#ifdef HAVE_ATTR_length
87750503Sobrien
87850503Sobrien  /* Allocate the rest of the arrays.  */
879132727Skan  insn_lengths = xmalloc (max_uid * sizeof (*insn_lengths));
88052515Sobrien  insn_lengths_max_uid = max_uid;
88150503Sobrien  /* Syntax errors can lead to labels being outside of the main insn stream.
88250503Sobrien     Initialize insn_addresses, so that we get reproducible results.  */
88390087Sobrien  INSN_ADDRESSES_ALLOC (max_uid);
88450503Sobrien
885132727Skan  varying_length = xcalloc (max_uid, sizeof (char));
88650503Sobrien
88750503Sobrien  /* Initialize uid_align.  We scan instructions
88850503Sobrien     from end to start, and keep in align_tab[n] the last seen insn
88950503Sobrien     that does an alignment of at least n+1, i.e. the successor
89050503Sobrien     in the alignment chain for an insn that does / has a known
89150503Sobrien     alignment of n.  */
892132727Skan  uid_align = xcalloc (max_uid, sizeof *uid_align);
89350503Sobrien
89490087Sobrien  for (i = MAX_CODE_ALIGN; --i >= 0;)
89550503Sobrien    align_tab[i] = NULL_RTX;
89650503Sobrien  seq = get_last_insn ();
89750503Sobrien  for (; seq; seq = PREV_INSN (seq))
89850503Sobrien    {
89950503Sobrien      int uid = INSN_UID (seq);
90050503Sobrien      int log;
90150503Sobrien      log = (GET_CODE (seq) == CODE_LABEL ? LABEL_TO_ALIGNMENT (seq) : 0);
90250503Sobrien      uid_align[uid] = align_tab[0];
90350503Sobrien      if (log)
90450503Sobrien	{
90550503Sobrien	  /* Found an alignment label.  */
90650503Sobrien	  uid_align[uid] = align_tab[log];
90750503Sobrien	  for (i = log - 1; i >= 0; i--)
90850503Sobrien	    align_tab[i] = seq;
90950503Sobrien	}
91050503Sobrien    }
91150503Sobrien#ifdef CASE_VECTOR_SHORTEN_MODE
91250503Sobrien  if (optimize)
91350503Sobrien    {
91450503Sobrien      /* Look for ADDR_DIFF_VECs, and initialize their minimum and maximum
91550503Sobrien         label fields.  */
91650503Sobrien
91750503Sobrien      int min_shuid = INSN_SHUID (get_insns ()) - 1;
91850503Sobrien      int max_shuid = INSN_SHUID (get_last_insn ()) + 1;
91950503Sobrien      int rel;
92050503Sobrien
92150503Sobrien      for (insn = first; insn != 0; insn = NEXT_INSN (insn))
92250503Sobrien	{
92350503Sobrien	  rtx min_lab = NULL_RTX, max_lab = NULL_RTX, pat;
92450503Sobrien	  int len, i, min, max, insn_shuid;
92550503Sobrien	  int min_align;
92650503Sobrien	  addr_diff_vec_flags flags;
92750503Sobrien
92850503Sobrien	  if (GET_CODE (insn) != JUMP_INSN
92950503Sobrien	      || GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC)
93050503Sobrien	    continue;
93150503Sobrien	  pat = PATTERN (insn);
93250503Sobrien	  len = XVECLEN (pat, 1);
93350503Sobrien	  if (len <= 0)
93450503Sobrien	    abort ();
93550503Sobrien	  min_align = MAX_CODE_ALIGN;
93650503Sobrien	  for (min = max_shuid, max = min_shuid, i = len - 1; i >= 0; i--)
93750503Sobrien	    {
93850503Sobrien	      rtx lab = XEXP (XVECEXP (pat, 1, i), 0);
93950503Sobrien	      int shuid = INSN_SHUID (lab);
94050503Sobrien	      if (shuid < min)
94150503Sobrien		{
94250503Sobrien		  min = shuid;
94350503Sobrien		  min_lab = lab;
94450503Sobrien		}
94550503Sobrien	      if (shuid > max)
94650503Sobrien		{
94750503Sobrien		  max = shuid;
94850503Sobrien		  max_lab = lab;
94950503Sobrien		}
95050503Sobrien	      if (min_align > LABEL_TO_ALIGNMENT (lab))
95150503Sobrien		min_align = LABEL_TO_ALIGNMENT (lab);
95250503Sobrien	    }
95350503Sobrien	  XEXP (pat, 2) = gen_rtx_LABEL_REF (VOIDmode, min_lab);
95450503Sobrien	  XEXP (pat, 3) = gen_rtx_LABEL_REF (VOIDmode, max_lab);
95550503Sobrien	  insn_shuid = INSN_SHUID (insn);
95650503Sobrien	  rel = INSN_SHUID (XEXP (XEXP (pat, 0), 0));
95750503Sobrien	  flags.min_align = min_align;
95850503Sobrien	  flags.base_after_vec = rel > insn_shuid;
95950503Sobrien	  flags.min_after_vec  = min > insn_shuid;
96050503Sobrien	  flags.max_after_vec  = max > insn_shuid;
96150503Sobrien	  flags.min_after_base = min > rel;
96250503Sobrien	  flags.max_after_base = max > rel;
96350503Sobrien	  ADDR_DIFF_VEC_FLAGS (pat) = flags;
96450503Sobrien	}
96550503Sobrien    }
96650503Sobrien#endif /* CASE_VECTOR_SHORTEN_MODE */
96750503Sobrien
96818334Speter  /* Compute initial lengths, addresses, and varying flags for each insn.  */
969132727Skan  for (insn_current_address = 0, insn = first;
97018334Speter       insn != 0;
97118334Speter       insn_current_address += insn_lengths[uid], insn = NEXT_INSN (insn))
97218334Speter    {
97318334Speter      uid = INSN_UID (insn);
97450503Sobrien
97550503Sobrien      insn_lengths[uid] = 0;
97650503Sobrien
97750503Sobrien      if (GET_CODE (insn) == CODE_LABEL)
97850503Sobrien	{
97950503Sobrien	  int log = LABEL_TO_ALIGNMENT (insn);
98050503Sobrien	  if (log)
98150503Sobrien	    {
98250503Sobrien	      int align = 1 << log;
98350503Sobrien	      int new_address = (insn_current_address + align - 1) & -align;
98450503Sobrien	      insn_lengths[uid] = new_address - insn_current_address;
98550503Sobrien	    }
98650503Sobrien	}
98750503Sobrien
988117404Skan      INSN_ADDRESSES (uid) = insn_current_address + insn_lengths[uid];
98990087Sobrien
99018334Speter      if (GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER
99118334Speter	  || GET_CODE (insn) == CODE_LABEL)
99218334Speter	continue;
99350503Sobrien      if (INSN_DELETED_P (insn))
99450503Sobrien	continue;
99518334Speter
99618334Speter      body = PATTERN (insn);
99718334Speter      if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
99818334Speter	{
99918334Speter	  /* This only takes room if read-only data goes into the text
100018334Speter	     section.  */
1001117404Skan	  if (JUMP_TABLES_IN_TEXT_SECTION || !HAVE_READONLY_DATA_SECTION)
100250503Sobrien	    insn_lengths[uid] = (XVECLEN (body,
100350503Sobrien					  GET_CODE (body) == ADDR_DIFF_VEC)
100450503Sobrien				 * GET_MODE_SIZE (GET_MODE (body)));
100550503Sobrien	  /* Alignment is handled by ADDR_VEC_ALIGN.  */
100618334Speter	}
100790087Sobrien      else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0)
100818334Speter	insn_lengths[uid] = asm_insn_count (body) * insn_default_length (insn);
100918334Speter      else if (GET_CODE (body) == SEQUENCE)
101018334Speter	{
101118334Speter	  int i;
101218334Speter	  int const_delay_slots;
101318334Speter#ifdef DELAY_SLOTS
101418334Speter	  const_delay_slots = const_num_delay_slots (XVECEXP (body, 0, 0));
101518334Speter#else
101618334Speter	  const_delay_slots = 0;
101718334Speter#endif
101818334Speter	  /* Inside a delay slot sequence, we do not do any branch shortening
101918334Speter	     if the shortening could change the number of delay slots
102050503Sobrien	     of the branch.  */
102118334Speter	  for (i = 0; i < XVECLEN (body, 0); i++)
102218334Speter	    {
102318334Speter	      rtx inner_insn = XVECEXP (body, 0, i);
102418334Speter	      int inner_uid = INSN_UID (inner_insn);
102518334Speter	      int inner_length;
102618334Speter
102790087Sobrien	      if (GET_CODE (body) == ASM_INPUT
102890087Sobrien		  || asm_noperands (PATTERN (XVECEXP (body, 0, i))) >= 0)
102918334Speter		inner_length = (asm_insn_count (PATTERN (inner_insn))
103018334Speter				* insn_default_length (inner_insn));
103118334Speter	      else
103218334Speter		inner_length = insn_default_length (inner_insn);
103390087Sobrien
103418334Speter	      insn_lengths[inner_uid] = inner_length;
103518334Speter	      if (const_delay_slots)
103618334Speter		{
103718334Speter		  if ((varying_length[inner_uid]
103818334Speter		       = insn_variable_length_p (inner_insn)) != 0)
103918334Speter		    varying_length[uid] = 1;
104090087Sobrien		  INSN_ADDRESSES (inner_uid) = (insn_current_address
104190087Sobrien						+ insn_lengths[uid]);
104218334Speter		}
104318334Speter	      else
104418334Speter		varying_length[inner_uid] = 0;
104518334Speter	      insn_lengths[uid] += inner_length;
104618334Speter	    }
104718334Speter	}
104818334Speter      else if (GET_CODE (body) != USE && GET_CODE (body) != CLOBBER)
104918334Speter	{
105018334Speter	  insn_lengths[uid] = insn_default_length (insn);
105118334Speter	  varying_length[uid] = insn_variable_length_p (insn);
105218334Speter	}
105318334Speter
105418334Speter      /* If needed, do any adjustment.  */
105518334Speter#ifdef ADJUST_INSN_LENGTH
105618334Speter      ADJUST_INSN_LENGTH (insn, insn_lengths[uid]);
105752515Sobrien      if (insn_lengths[uid] < 0)
105890087Sobrien	fatal_insn ("negative insn length", insn);
105918334Speter#endif
106018334Speter    }
106118334Speter
106218334Speter  /* Now loop over all the insns finding varying length insns.  For each,
106318334Speter     get the current insn length.  If it has changed, reflect the change.
106418334Speter     When nothing changes for a full pass, we are done.  */
106518334Speter
106618334Speter  while (something_changed)
106718334Speter    {
106818334Speter      something_changed = 0;
106950503Sobrien      insn_current_align = MAX_CODE_ALIGN - 1;
1070132727Skan      for (insn_current_address = 0, insn = first;
107118334Speter	   insn != 0;
107218334Speter	   insn = NEXT_INSN (insn))
107318334Speter	{
107418334Speter	  int new_length;
107550503Sobrien#ifdef ADJUST_INSN_LENGTH
107618334Speter	  int tmp_length;
107750503Sobrien#endif
107850503Sobrien	  int length_align;
107918334Speter
108018334Speter	  uid = INSN_UID (insn);
108150503Sobrien
108250503Sobrien	  if (GET_CODE (insn) == CODE_LABEL)
108350503Sobrien	    {
108450503Sobrien	      int log = LABEL_TO_ALIGNMENT (insn);
108550503Sobrien	      if (log > insn_current_align)
108650503Sobrien		{
108750503Sobrien		  int align = 1 << log;
108850503Sobrien		  int new_address= (insn_current_address + align - 1) & -align;
108950503Sobrien		  insn_lengths[uid] = new_address - insn_current_address;
109050503Sobrien		  insn_current_align = log;
109150503Sobrien		  insn_current_address = new_address;
109250503Sobrien		}
109350503Sobrien	      else
109450503Sobrien		insn_lengths[uid] = 0;
109590087Sobrien	      INSN_ADDRESSES (uid) = insn_current_address;
109650503Sobrien	      continue;
109750503Sobrien	    }
109850503Sobrien
109950503Sobrien	  length_align = INSN_LENGTH_ALIGNMENT (insn);
110050503Sobrien	  if (length_align < insn_current_align)
110150503Sobrien	    insn_current_align = length_align;
110250503Sobrien
110390087Sobrien	  insn_last_address = INSN_ADDRESSES (uid);
110490087Sobrien	  INSN_ADDRESSES (uid) = insn_current_address;
110550503Sobrien
110650503Sobrien#ifdef CASE_VECTOR_SHORTEN_MODE
110750503Sobrien	  if (optimize && GET_CODE (insn) == JUMP_INSN
110850503Sobrien	      && GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
110918334Speter	    {
111050503Sobrien	      rtx body = PATTERN (insn);
111150503Sobrien	      int old_length = insn_lengths[uid];
111250503Sobrien	      rtx rel_lab = XEXP (XEXP (body, 0), 0);
111350503Sobrien	      rtx min_lab = XEXP (XEXP (body, 2), 0);
111450503Sobrien	      rtx max_lab = XEXP (XEXP (body, 3), 0);
111590087Sobrien	      int rel_addr = INSN_ADDRESSES (INSN_UID (rel_lab));
111690087Sobrien	      int min_addr = INSN_ADDRESSES (INSN_UID (min_lab));
111790087Sobrien	      int max_addr = INSN_ADDRESSES (INSN_UID (max_lab));
111850503Sobrien	      rtx prev;
111950503Sobrien	      int rel_align = 0;
112090087Sobrien	      addr_diff_vec_flags flags;
112150503Sobrien
112290087Sobrien	      /* Avoid automatic aggregate initialization.  */
112390087Sobrien	      flags = ADDR_DIFF_VEC_FLAGS (body);
112490087Sobrien
112550503Sobrien	      /* Try to find a known alignment for rel_lab.  */
112650503Sobrien	      for (prev = rel_lab;
112750503Sobrien		   prev
112850503Sobrien		   && ! insn_lengths[INSN_UID (prev)]
112950503Sobrien		   && ! (varying_length[INSN_UID (prev)] & 1);
113050503Sobrien		   prev = PREV_INSN (prev))
113150503Sobrien		if (varying_length[INSN_UID (prev)] & 2)
113250503Sobrien		  {
113350503Sobrien		    rel_align = LABEL_TO_ALIGNMENT (prev);
113450503Sobrien		    break;
113550503Sobrien		  }
113650503Sobrien
113750503Sobrien	      /* See the comment on addr_diff_vec_flags in rtl.h for the
113850503Sobrien		 meaning of the flags values.  base: REL_LAB   vec: INSN  */
113950503Sobrien	      /* Anything after INSN has still addresses from the last
114050503Sobrien		 pass; adjust these so that they reflect our current
114150503Sobrien		 estimate for this pass.  */
114250503Sobrien	      if (flags.base_after_vec)
114350503Sobrien		rel_addr += insn_current_address - insn_last_address;
114450503Sobrien	      if (flags.min_after_vec)
114550503Sobrien		min_addr += insn_current_address - insn_last_address;
114650503Sobrien	      if (flags.max_after_vec)
114750503Sobrien		max_addr += insn_current_address - insn_last_address;
114850503Sobrien	      /* We want to know the worst case, i.e. lowest possible value
114950503Sobrien		 for the offset of MIN_LAB.  If MIN_LAB is after REL_LAB,
115050503Sobrien		 its offset is positive, and we have to be wary of code shrink;
115150503Sobrien		 otherwise, it is negative, and we have to be vary of code
115250503Sobrien		 size increase.  */
115350503Sobrien	      if (flags.min_after_base)
115450503Sobrien		{
115550503Sobrien		  /* If INSN is between REL_LAB and MIN_LAB, the size
115650503Sobrien		     changes we are about to make can change the alignment
115750503Sobrien		     within the observed offset, therefore we have to break
115850503Sobrien		     it up into two parts that are independent.  */
115950503Sobrien		  if (! flags.base_after_vec && flags.min_after_vec)
116050503Sobrien		    {
116150503Sobrien		      min_addr -= align_fuzz (rel_lab, insn, rel_align, 0);
116250503Sobrien		      min_addr -= align_fuzz (insn, min_lab, 0, 0);
116350503Sobrien		    }
116450503Sobrien		  else
116550503Sobrien		    min_addr -= align_fuzz (rel_lab, min_lab, rel_align, 0);
116650503Sobrien		}
116750503Sobrien	      else
116850503Sobrien		{
116950503Sobrien		  if (flags.base_after_vec && ! flags.min_after_vec)
117050503Sobrien		    {
117150503Sobrien		      min_addr -= align_fuzz (min_lab, insn, 0, ~0);
117250503Sobrien		      min_addr -= align_fuzz (insn, rel_lab, 0, ~0);
117350503Sobrien		    }
117450503Sobrien		  else
117550503Sobrien		    min_addr -= align_fuzz (min_lab, rel_lab, 0, ~0);
117650503Sobrien		}
117750503Sobrien	      /* Likewise, determine the highest lowest possible value
117850503Sobrien		 for the offset of MAX_LAB.  */
117950503Sobrien	      if (flags.max_after_base)
118050503Sobrien		{
118150503Sobrien		  if (! flags.base_after_vec && flags.max_after_vec)
118250503Sobrien		    {
118350503Sobrien		      max_addr += align_fuzz (rel_lab, insn, rel_align, ~0);
118450503Sobrien		      max_addr += align_fuzz (insn, max_lab, 0, ~0);
118550503Sobrien		    }
118650503Sobrien		  else
118750503Sobrien		    max_addr += align_fuzz (rel_lab, max_lab, rel_align, ~0);
118850503Sobrien		}
118950503Sobrien	      else
119050503Sobrien		{
119150503Sobrien		  if (flags.base_after_vec && ! flags.max_after_vec)
119250503Sobrien		    {
119350503Sobrien		      max_addr += align_fuzz (max_lab, insn, 0, 0);
119450503Sobrien		      max_addr += align_fuzz (insn, rel_lab, 0, 0);
119550503Sobrien		    }
119650503Sobrien		  else
119750503Sobrien		    max_addr += align_fuzz (max_lab, rel_lab, 0, 0);
119850503Sobrien		}
119950503Sobrien	      PUT_MODE (body, CASE_VECTOR_SHORTEN_MODE (min_addr - rel_addr,
120050503Sobrien							max_addr - rel_addr,
120150503Sobrien							body));
1202117404Skan	      if (JUMP_TABLES_IN_TEXT_SECTION || !HAVE_READONLY_DATA_SECTION)
120350503Sobrien		{
120450503Sobrien		  insn_lengths[uid]
120550503Sobrien		    = (XVECLEN (body, 1) * GET_MODE_SIZE (GET_MODE (body)));
120650503Sobrien		  insn_current_address += insn_lengths[uid];
120750503Sobrien		  if (insn_lengths[uid] != old_length)
120850503Sobrien		    something_changed = 1;
120950503Sobrien		}
121050503Sobrien
121150503Sobrien	      continue;
121250503Sobrien	    }
121350503Sobrien#endif /* CASE_VECTOR_SHORTEN_MODE */
121450503Sobrien
121550503Sobrien	  if (! (varying_length[uid]))
121650503Sobrien	    {
121790087Sobrien	      if (GET_CODE (insn) == INSN
121890087Sobrien		  && GET_CODE (PATTERN (insn)) == SEQUENCE)
121990087Sobrien		{
122090087Sobrien		  int i;
122190087Sobrien
122290087Sobrien		  body = PATTERN (insn);
122390087Sobrien		  for (i = 0; i < XVECLEN (body, 0); i++)
122490087Sobrien		    {
122590087Sobrien		      rtx inner_insn = XVECEXP (body, 0, i);
122690087Sobrien		      int inner_uid = INSN_UID (inner_insn);
122790087Sobrien
122890087Sobrien		      INSN_ADDRESSES (inner_uid) = insn_current_address;
122990087Sobrien
123090087Sobrien		      insn_current_address += insn_lengths[inner_uid];
123190087Sobrien		    }
1232117404Skan		}
123390087Sobrien	      else
123490087Sobrien		insn_current_address += insn_lengths[uid];
123590087Sobrien
123618334Speter	      continue;
123718334Speter	    }
123890087Sobrien
123918334Speter	  if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE)
124018334Speter	    {
124118334Speter	      int i;
124290087Sobrien
124318334Speter	      body = PATTERN (insn);
124418334Speter	      new_length = 0;
124518334Speter	      for (i = 0; i < XVECLEN (body, 0); i++)
124618334Speter		{
124718334Speter		  rtx inner_insn = XVECEXP (body, 0, i);
124818334Speter		  int inner_uid = INSN_UID (inner_insn);
124918334Speter		  int inner_length;
125018334Speter
125190087Sobrien		  INSN_ADDRESSES (inner_uid) = insn_current_address;
125218334Speter
125318334Speter		  /* insn_current_length returns 0 for insns with a
125418334Speter		     non-varying length.  */
125518334Speter		  if (! varying_length[inner_uid])
125618334Speter		    inner_length = insn_lengths[inner_uid];
125718334Speter		  else
125818334Speter		    inner_length = insn_current_length (inner_insn);
125918334Speter
126018334Speter		  if (inner_length != insn_lengths[inner_uid])
126118334Speter		    {
126218334Speter		      insn_lengths[inner_uid] = inner_length;
126318334Speter		      something_changed = 1;
126418334Speter		    }
126518334Speter		  insn_current_address += insn_lengths[inner_uid];
126618334Speter		  new_length += inner_length;
126718334Speter		}
126818334Speter	    }
126918334Speter	  else
127018334Speter	    {
127118334Speter	      new_length = insn_current_length (insn);
127218334Speter	      insn_current_address += new_length;
127318334Speter	    }
127418334Speter
127518334Speter#ifdef ADJUST_INSN_LENGTH
127618334Speter	  /* If needed, do any adjustment.  */
127718334Speter	  tmp_length = new_length;
127818334Speter	  ADJUST_INSN_LENGTH (insn, new_length);
127918334Speter	  insn_current_address += (new_length - tmp_length);
128018334Speter#endif
128118334Speter
128218334Speter	  if (new_length != insn_lengths[uid])
128318334Speter	    {
128418334Speter	      insn_lengths[uid] = new_length;
128518334Speter	      something_changed = 1;
128618334Speter	    }
128718334Speter	}
128818334Speter      /* For a non-optimizing compile, do only a single pass.  */
128918334Speter      if (!optimize)
129018334Speter	break;
129118334Speter    }
129250503Sobrien
129350503Sobrien  free (varying_length);
129450503Sobrien
129518334Speter#endif /* HAVE_ATTR_length */
129618334Speter}
129718334Speter
129818334Speter#ifdef HAVE_ATTR_length
129918334Speter/* Given the body of an INSN known to be generated by an ASM statement, return
130018334Speter   the number of machine instructions likely to be generated for this insn.
130118334Speter   This is used to compute its length.  */
130218334Speter
130318334Speterstatic int
1304132727Skanasm_insn_count (rtx body)
130518334Speter{
130690087Sobrien  const char *template;
130718334Speter  int count = 1;
130818334Speter
130918334Speter  if (GET_CODE (body) == ASM_INPUT)
131018334Speter    template = XSTR (body, 0);
131118334Speter  else
131290087Sobrien    template = decode_asm_operands (body, NULL, NULL, NULL, NULL);
131318334Speter
131490087Sobrien  for (; *template; template++)
131590087Sobrien    if (IS_ASM_LOGICAL_LINE_SEPARATOR (*template) || *template == '\n')
131618334Speter      count++;
131718334Speter
131818334Speter  return count;
131918334Speter}
132018334Speter#endif
132118334Speter
132218334Speter/* Output assembler code for the start of a function,
132318334Speter   and initialize some of the variables in this file
132418334Speter   for the new function.  The label for the function and associated
132518334Speter   assembler pseudo-ops have already been output in `assemble_start_function'.
132618334Speter
132718334Speter   FIRST is the first insn of the rtl for the function being compiled.
132818334Speter   FILE is the file to write assembler code to.
132918334Speter   OPTIMIZE is nonzero if we should eliminate redundant
133018334Speter     test and compare insns.  */
133118334Speter
133218334Spetervoid
1333132727Skanfinal_start_function (rtx first ATTRIBUTE_UNUSED, FILE *file,
1334132727Skan		      int optimize ATTRIBUTE_UNUSED)
133518334Speter{
133618334Speter  block_depth = 0;
133718334Speter
133818334Speter  this_is_asm_operands = 0;
133918334Speter
1340132727Skan  last_filename = locator_file (prologue_locator);
1341132727Skan  last_linenum = locator_line (prologue_locator);
134218334Speter
134390087Sobrien  high_block_linenum = high_function_linenum = last_linenum;
134418334Speter
134590087Sobrien  (*debug_hooks->begin_prologue) (last_linenum, last_filename);
134650503Sobrien
134790087Sobrien#if defined (DWARF2_UNWIND_INFO) || defined (IA64_UNWIND_INFO)
134890087Sobrien  if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG)
134990087Sobrien    dwarf2out_begin_prologue (0, NULL);
135018334Speter#endif
135118334Speter
135218334Speter#ifdef LEAF_REG_REMAP
135352515Sobrien  if (current_function_uses_only_leaf_regs)
135418334Speter    leaf_renumber_regs (first);
135518334Speter#endif
135618334Speter
135718334Speter  /* The Sun386i and perhaps other machines don't work right
135818334Speter     if the profiling code comes after the prologue.  */
135918334Speter#ifdef PROFILE_BEFORE_PROLOGUE
136090087Sobrien  if (current_function_profile)
136118334Speter    profile_function (file);
136218334Speter#endif /* PROFILE_BEFORE_PROLOGUE */
136318334Speter
136450503Sobrien#if defined (DWARF2_UNWIND_INFO) && defined (HAVE_prologue)
136550503Sobrien  if (dwarf2out_do_frame ())
136650503Sobrien    dwarf2out_frame_debug (NULL_RTX);
136750503Sobrien#endif
136850503Sobrien
136990087Sobrien  /* If debugging, assign block numbers to all of the blocks in this
137090087Sobrien     function.  */
137190087Sobrien  if (write_symbols)
137290087Sobrien    {
137390087Sobrien      remove_unnecessary_notes ();
1374132727Skan      reemit_insn_block_notes ();
137590087Sobrien      number_blocks (current_function_decl);
137690087Sobrien      /* We never actually put out begin/end notes for the top-level
137790087Sobrien	 block in the function.  But, conceptually, that block is
137890087Sobrien	 always needed.  */
137990087Sobrien      TREE_ASM_WRITTEN (DECL_INITIAL (current_function_decl)) = 1;
138090087Sobrien    }
138190087Sobrien
138218334Speter  /* First output the function prologue: code to set up the stack frame.  */
138390087Sobrien  (*targetm.asm_out.function_prologue) (file, get_frame_size ());
138418334Speter
138518334Speter  /* If the machine represents the prologue as RTL, the profiling code must
138618334Speter     be emitted when NOTE_INSN_PROLOGUE_END is scanned.  */
138718334Speter#ifdef HAVE_prologue
138818334Speter  if (! HAVE_prologue)
138918334Speter#endif
139018334Speter    profile_after_prologue (file);
139118334Speter}
139218334Speter
139318334Speterstatic void
1394132727Skanprofile_after_prologue (FILE *file ATTRIBUTE_UNUSED)
139518334Speter{
139618334Speter#ifndef PROFILE_BEFORE_PROLOGUE
139790087Sobrien  if (current_function_profile)
139818334Speter    profile_function (file);
139918334Speter#endif /* not PROFILE_BEFORE_PROLOGUE */
140018334Speter}
140118334Speter
140218334Speterstatic void
1403132727Skanprofile_function (FILE *file ATTRIBUTE_UNUSED)
140418334Speter{
140574478Sobrien#ifndef NO_PROFILE_COUNTERS
1406132727Skan# define NO_PROFILE_COUNTERS	0
140774478Sobrien#endif
140850503Sobrien#if defined(ASM_OUTPUT_REG_PUSH)
140918334Speter  int sval = current_function_returns_struct;
1410132727Skan  rtx svrtx = targetm.calls.struct_value_rtx (TREE_TYPE (current_function_decl), 1);
141150503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) || defined(STATIC_CHAIN_REGNUM)
141218334Speter  int cxt = current_function_needs_context;
141350503Sobrien#endif
141450503Sobrien#endif /* ASM_OUTPUT_REG_PUSH */
141518334Speter
1416132727Skan  if (! NO_PROFILE_COUNTERS)
1417132727Skan    {
1418132727Skan      int align = MIN (BIGGEST_ALIGNMENT, LONG_TYPE_SIZE);
1419132727Skan      data_section ();
1420132727Skan      ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
1421132727Skan      (*targetm.asm_out.internal_label) (file, "LP", current_function_funcdef_no);
1422132727Skan      assemble_integer (const0_rtx, LONG_TYPE_SIZE / BITS_PER_UNIT, align, 1);
1423132727Skan    }
142418334Speter
142550503Sobrien  function_section (current_function_decl);
142618334Speter
1427132727Skan#if defined(ASM_OUTPUT_REG_PUSH)
1428132727Skan  if (sval && svrtx != NULL_RTX && GET_CODE (svrtx) == REG)
1429132727Skan    ASM_OUTPUT_REG_PUSH (file, REGNO (svrtx));
143018334Speter#endif
143118334Speter
143250503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
143318334Speter  if (cxt)
143418334Speter    ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_INCOMING_REGNUM);
143518334Speter#else
143650503Sobrien#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
143718334Speter  if (cxt)
143850503Sobrien    {
143950503Sobrien      ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_REGNUM);
144050503Sobrien    }
144118334Speter#endif
144218334Speter#endif
144318334Speter
1444117404Skan  FUNCTION_PROFILER (file, current_function_funcdef_no);
144518334Speter
144650503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
144718334Speter  if (cxt)
144818334Speter    ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_INCOMING_REGNUM);
144918334Speter#else
145050503Sobrien#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
145118334Speter  if (cxt)
145250503Sobrien    {
145350503Sobrien      ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_REGNUM);
145450503Sobrien    }
145518334Speter#endif
145618334Speter#endif
145718334Speter
1458132727Skan#if defined(ASM_OUTPUT_REG_PUSH)
1459132727Skan  if (sval && svrtx != NULL_RTX && GET_CODE (svrtx) == REG)
1460132727Skan    ASM_OUTPUT_REG_POP (file, REGNO (svrtx));
146118334Speter#endif
146218334Speter}
146318334Speter
146418334Speter/* Output assembler code for the end of a function.
146518334Speter   For clarity, args are same as those of `final_start_function'
146618334Speter   even though not all of them are needed.  */
146718334Speter
146818334Spetervoid
1469132727Skanfinal_end_function (void)
147018334Speter{
147190087Sobrien  app_disable ();
147218334Speter
147390087Sobrien  (*debug_hooks->end_function) (high_function_linenum);
147418334Speter
147518334Speter  /* Finally, output the function epilogue:
147618334Speter     code to restore the stack frame and return to the caller.  */
147790087Sobrien  (*targetm.asm_out.function_epilogue) (asm_out_file, get_frame_size ());
147818334Speter
147990087Sobrien  /* And debug output.  */
1480117404Skan  (*debug_hooks->end_epilogue) (last_linenum, last_filename);
148190087Sobrien
148290087Sobrien#if defined (DWARF2_UNWIND_INFO)
148390087Sobrien  if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG
148490087Sobrien      && dwarf2out_do_frame ())
1485117404Skan    dwarf2out_end_epilogue (last_linenum, last_filename);
148650503Sobrien#endif
148718334Speter}
148818334Speter
148918334Speter/* Output assembler code for some insns: all or part of a function.
149018334Speter   For description of args, see `final_start_function', above.
149118334Speter
149218334Speter   PRESCAN is 1 if we are not really outputting,
149318334Speter     just scanning as if we were outputting.
149418334Speter   Prescanning deletes and rearranges insns just like ordinary output.
149518334Speter   PRESCAN is -2 if we are outputting after having prescanned.
149618334Speter   In this case, don't try to delete or rearrange insns
149718334Speter   because that has already been done.
149818334Speter   Prescanning is done only on certain machines.  */
149918334Speter
150018334Spetervoid
1501132727Skanfinal (rtx first, FILE *file, int optimize, int prescan)
150218334Speter{
150390087Sobrien  rtx insn;
150450503Sobrien  int max_uid = 0;
1505132727Skan  int seen = 0;
150618334Speter
150718334Speter  last_ignored_compare = 0;
150818334Speter
1509132727Skan#ifdef SDB_DEBUGGING_INFO
1510132727Skan  /* When producing SDB debugging info, delete troublesome line number
151118334Speter     notes from inlined functions in other files as well as duplicate
151218334Speter     line number notes.  */
151318334Speter  if (write_symbols == SDB_DEBUG)
151418334Speter    {
151518334Speter      rtx last = 0;
151618334Speter      for (insn = first; insn; insn = NEXT_INSN (insn))
151718334Speter	if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
151818334Speter	  {
151918334Speter	    if ((RTX_INTEGRATED_P (insn)
152018334Speter		 && strcmp (NOTE_SOURCE_FILE (insn), main_input_filename) != 0)
1521132727Skan		|| (last != 0
1522132727Skan		    && NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last)
1523132727Skan		    && NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last)))
152418334Speter	      {
152590087Sobrien		delete_insn (insn);	/* Use delete_note.  */
152618334Speter		continue;
152718334Speter	      }
152818334Speter	    last = insn;
152918334Speter	  }
153018334Speter    }
153118334Speter#endif
153218334Speter
153318334Speter  for (insn = first; insn; insn = NEXT_INSN (insn))
153450503Sobrien    {
1535132727Skan      if (INSN_UID (insn) > max_uid)       /* Find largest UID.  */
153690087Sobrien	max_uid = INSN_UID (insn);
153752515Sobrien#ifdef HAVE_cc0
153852515Sobrien      /* If CC tracking across branches is enabled, record the insn which
153952515Sobrien	 jumps to each branch only reached from one place.  */
154052515Sobrien      if (optimize && GET_CODE (insn) == JUMP_INSN)
154152515Sobrien	{
154252515Sobrien	  rtx lab = JUMP_LABEL (insn);
154352515Sobrien	  if (lab && LABEL_NUSES (lab) == 1)
154452515Sobrien	    {
154552515Sobrien	      LABEL_REFS (lab) = insn;
154652515Sobrien	    }
154752515Sobrien	}
154852515Sobrien#endif
154950503Sobrien    }
155018334Speter
155118334Speter  init_recog ();
155218334Speter
155318334Speter  CC_STATUS_INIT;
155418334Speter
155518334Speter  /* Output the insns.  */
155618334Speter  for (insn = NEXT_INSN (first); insn;)
155750503Sobrien    {
155850503Sobrien#ifdef HAVE_ATTR_length
155990087Sobrien      if ((unsigned) INSN_UID (insn) >= INSN_ADDRESSES_SIZE ())
156090087Sobrien	{
156190087Sobrien	  /* This can be triggered by bugs elsewhere in the compiler if
156290087Sobrien	     new insns are created after init_insn_lengths is called.  */
1563117404Skan	  if (GET_CODE (insn) == NOTE)
1564117404Skan	    insn_current_address = -1;
1565117404Skan	  else
1566117404Skan	    abort ();
156790087Sobrien	}
156890087Sobrien      else
156990087Sobrien	insn_current_address = INSN_ADDRESSES (INSN_UID (insn));
157090087Sobrien#endif /* HAVE_ATTR_length */
157190087Sobrien
1572132727Skan      insn = final_scan_insn (insn, file, optimize, prescan, 0, &seen);
157350503Sobrien    }
157490087Sobrien}
157590087Sobrien
157690087Sobrienconst char *
1577132727Skanget_insn_template (int code, rtx insn)
157890087Sobrien{
157990087Sobrien  switch (insn_data[code].output_format)
158090087Sobrien    {
158190087Sobrien    case INSN_OUTPUT_FORMAT_SINGLE:
1582132727Skan      return insn_data[code].output.single;
158390087Sobrien    case INSN_OUTPUT_FORMAT_MULTI:
1584132727Skan      return insn_data[code].output.multi[which_alternative];
158590087Sobrien    case INSN_OUTPUT_FORMAT_FUNCTION:
158690087Sobrien      if (insn == NULL)
158790087Sobrien	abort ();
1588132727Skan      return (*insn_data[code].output.function) (recog_data.operand, insn);
158950503Sobrien
159090087Sobrien    default:
159190087Sobrien      abort ();
159290087Sobrien    }
159318334Speter}
159490087Sobrien
1595117404Skan/* Emit the appropriate declaration for an alternate-entry-point
1596117404Skan   symbol represented by INSN, to FILE.  INSN is a CODE_LABEL with
1597117404Skan   LABEL_KIND != LABEL_NORMAL.
1598117404Skan
1599117404Skan   The case fall-through in this function is intentional.  */
1600117404Skanstatic void
1601132727Skanoutput_alternate_entry_point (FILE *file, rtx insn)
1602117404Skan{
1603117404Skan  const char *name = LABEL_NAME (insn);
1604117404Skan
1605117404Skan  switch (LABEL_KIND (insn))
1606117404Skan    {
1607117404Skan    case LABEL_WEAK_ENTRY:
1608117404Skan#ifdef ASM_WEAKEN_LABEL
1609117404Skan      ASM_WEAKEN_LABEL (file, name);
1610117404Skan#endif
1611117404Skan    case LABEL_GLOBAL_ENTRY:
1612117404Skan      (*targetm.asm_out.globalize_label) (file, name);
1613117404Skan    case LABEL_STATIC_ENTRY:
1614117404Skan#ifdef ASM_OUTPUT_TYPE_DIRECTIVE
1615117404Skan      ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
1616117404Skan#endif
1617117404Skan      ASM_OUTPUT_LABEL (file, name);
1618117404Skan      break;
1619117404Skan
1620117404Skan    case LABEL_NORMAL:
1621117404Skan    default:
1622117404Skan      abort ();
1623117404Skan    }
1624117404Skan}
1625117404Skan
162618334Speter/* The final scan for one insn, INSN.
162718334Speter   Args are same as in `final', except that INSN
162818334Speter   is the insn being scanned.
162918334Speter   Value returned is the next insn to be scanned.
163018334Speter
163118334Speter   NOPEEPHOLES is the flag to disallow peephole processing (currently
1632132727Skan   used for within delayed branch sequence output).
163318334Speter
1634132727Skan   SEEN is used to track the end of the prologue, for emitting
1635132727Skan   debug information.  We force the emission of a line note after
1636132727Skan   both NOTE_INSN_PROLOGUE_END and NOTE_INSN_FUNCTION_BEG, or
1637132727Skan   at the beginning of the second basic block, whichever comes
1638132727Skan   first.  */
1639132727Skan
164018334Speterrtx
1641132727Skanfinal_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
1642132727Skan		 int prescan, int nopeepholes ATTRIBUTE_UNUSED,
1643132727Skan		 int *seen)
164418334Speter{
164550503Sobrien#ifdef HAVE_cc0
164650503Sobrien  rtx set;
164750503Sobrien#endif
164850503Sobrien
164918334Speter  insn_counter++;
165018334Speter
165118334Speter  /* Ignore deleted insns.  These can occur when we split insns (due to a
165218334Speter     template of "#") while not optimizing.  */
165318334Speter  if (INSN_DELETED_P (insn))
165418334Speter    return NEXT_INSN (insn);
165518334Speter
165618334Speter  switch (GET_CODE (insn))
165718334Speter    {
165818334Speter    case NOTE:
165918334Speter      if (prescan > 0)
166018334Speter	break;
166118334Speter
166290087Sobrien      switch (NOTE_LINE_NUMBER (insn))
166318334Speter	{
166490087Sobrien	case NOTE_INSN_DELETED:
166590087Sobrien	case NOTE_INSN_LOOP_BEG:
166690087Sobrien	case NOTE_INSN_LOOP_END:
166796281Sobrien	case NOTE_INSN_LOOP_END_TOP_COND:
166890087Sobrien	case NOTE_INSN_LOOP_CONT:
166990087Sobrien	case NOTE_INSN_LOOP_VTOP:
167090087Sobrien	case NOTE_INSN_FUNCTION_END:
167190087Sobrien	case NOTE_INSN_REPEATED_LINE_NUMBER:
167290087Sobrien	case NOTE_INSN_EXPECTED_VALUE:
167318334Speter	  break;
167418334Speter
167590087Sobrien	case NOTE_INSN_BASIC_BLOCK:
167690087Sobrien#ifdef IA64_UNWIND_INFO
167790087Sobrien	  IA64_UNWIND_EMIT (asm_out_file, insn);
167850503Sobrien#endif
167990087Sobrien	  if (flag_debug_asm)
168090087Sobrien	    fprintf (asm_out_file, "\t%s basic block %d\n",
168190087Sobrien		     ASM_COMMENT_START, NOTE_BASIC_BLOCK (insn)->index);
1682132727Skan
1683132727Skan	  if ((*seen & (SEEN_EMITTED | SEEN_BB)) == SEEN_BB)
1684132727Skan	    {
1685132727Skan	      *seen |= SEEN_EMITTED;
1686132727Skan	      last_filename = NULL;
1687132727Skan	    }
1688132727Skan	  else
1689132727Skan	    *seen |= SEEN_BB;
1690132727Skan
169150503Sobrien	  break;
169250503Sobrien
169390087Sobrien	case NOTE_INSN_EH_REGION_BEG:
169490087Sobrien	  ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LEHB",
169590087Sobrien				  NOTE_EH_HANDLER (insn));
169690087Sobrien	  break;
169790087Sobrien
169890087Sobrien	case NOTE_INSN_EH_REGION_END:
169990087Sobrien	  ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LEHE",
170090087Sobrien				  NOTE_EH_HANDLER (insn));
170190087Sobrien	  break;
170290087Sobrien
170390087Sobrien	case NOTE_INSN_PROLOGUE_END:
170490087Sobrien	  (*targetm.asm_out.function_end_prologue) (file);
170518334Speter	  profile_after_prologue (file);
1706132727Skan
1707132727Skan	  if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE)
1708132727Skan	    {
1709132727Skan	      *seen |= SEEN_EMITTED;
1710132727Skan	      last_filename = NULL;
1711132727Skan	    }
1712132727Skan	  else
1713132727Skan	    *seen |= SEEN_NOTE;
1714132727Skan
171518334Speter	  break;
171618334Speter
171790087Sobrien	case NOTE_INSN_EPILOGUE_BEG:
171890087Sobrien	  (*targetm.asm_out.function_begin_epilogue) (file);
171918334Speter	  break;
172018334Speter
172190087Sobrien	case NOTE_INSN_FUNCTION_BEG:
172290087Sobrien	  app_disable ();
1723117404Skan	  (*debug_hooks->end_prologue) (last_linenum, last_filename);
1724132727Skan
1725132727Skan	  if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE)
1726132727Skan	    {
1727132727Skan	      *seen |= SEEN_EMITTED;
1728132727Skan	      last_filename = NULL;
1729132727Skan	    }
1730132727Skan	  else
1731132727Skan	    *seen |= SEEN_NOTE;
1732132727Skan
173318334Speter	  break;
173490087Sobrien
173590087Sobrien	case NOTE_INSN_BLOCK_BEG:
173690087Sobrien	  if (debug_info_level == DINFO_LEVEL_NORMAL
173718334Speter	      || debug_info_level == DINFO_LEVEL_VERBOSE
173818334Speter	      || write_symbols == DWARF_DEBUG
173990087Sobrien	      || write_symbols == DWARF2_DEBUG
174090087Sobrien	      || write_symbols == VMS_AND_DWARF2_DEBUG
174190087Sobrien	      || write_symbols == VMS_DEBUG)
174290087Sobrien	    {
174390087Sobrien	      int n = BLOCK_NUMBER (NOTE_BLOCK (insn));
174418334Speter
174590087Sobrien	      app_disable ();
174690087Sobrien	      ++block_depth;
174790087Sobrien	      high_block_linenum = last_linenum;
174890087Sobrien
174990087Sobrien	      /* Output debugging info about the symbol-block beginning.  */
175090087Sobrien	      (*debug_hooks->begin_block) (last_linenum, n);
175190087Sobrien
175290087Sobrien	      /* Mark this block as output.  */
175390087Sobrien	      TREE_ASM_WRITTEN (NOTE_BLOCK (insn)) = 1;
175418334Speter	    }
175590087Sobrien	  break;
175618334Speter
175790087Sobrien	case NOTE_INSN_BLOCK_END:
175890087Sobrien	  if (debug_info_level == DINFO_LEVEL_NORMAL
175990087Sobrien	      || debug_info_level == DINFO_LEVEL_VERBOSE
176090087Sobrien	      || write_symbols == DWARF_DEBUG
176190087Sobrien	      || write_symbols == DWARF2_DEBUG
176290087Sobrien	      || write_symbols == VMS_AND_DWARF2_DEBUG
176390087Sobrien	      || write_symbols == VMS_DEBUG)
176490087Sobrien	    {
176590087Sobrien	      int n = BLOCK_NUMBER (NOTE_BLOCK (insn));
176618334Speter
176790087Sobrien	      app_disable ();
176818334Speter
176990087Sobrien	      /* End of a symbol-block.  */
177090087Sobrien	      --block_depth;
177190087Sobrien	      if (block_depth < 0)
177290087Sobrien		abort ();
177318334Speter
177490087Sobrien	      (*debug_hooks->end_block) (high_block_linenum, n);
177590087Sobrien	    }
177690087Sobrien	  break;
177718334Speter
177890087Sobrien	case NOTE_INSN_DELETED_LABEL:
177990087Sobrien	  /* Emit the label.  We may have deleted the CODE_LABEL because
178090087Sobrien	     the label could be proved to be unreachable, though still
178190087Sobrien	     referenced (in the form of having its address taken.  */
178290087Sobrien	  ASM_OUTPUT_DEBUG_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
178390087Sobrien	  break;
178418334Speter
178590087Sobrien	case 0:
178690087Sobrien	  break;
178718334Speter
178890087Sobrien	default:
178990087Sobrien	  if (NOTE_LINE_NUMBER (insn) <= 0)
179090087Sobrien	    abort ();
179190087Sobrien	  break;
179218334Speter	}
179318334Speter      break;
179418334Speter
179518334Speter    case BARRIER:
179690087Sobrien#if defined (DWARF2_UNWIND_INFO)
179790087Sobrien      if (dwarf2out_do_frame ())
179890087Sobrien	dwarf2out_frame_debug (insn);
179918334Speter#endif
180018334Speter      break;
180118334Speter
180218334Speter    case CODE_LABEL:
180350503Sobrien      /* The target port might emit labels in the output function for
180450503Sobrien	 some insn, e.g. sh.c output_branchy_insn.  */
180550503Sobrien      if (CODE_LABEL_NUMBER (insn) <= max_labelno)
180650503Sobrien	{
180750503Sobrien	  int align = LABEL_TO_ALIGNMENT (insn);
180850503Sobrien#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
180950503Sobrien	  int max_skip = LABEL_TO_MAX_SKIP (insn);
181050503Sobrien#endif
181150503Sobrien
181250503Sobrien	  if (align && NEXT_INSN (insn))
181390087Sobrien	    {
181450503Sobrien#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
181590087Sobrien	      ASM_OUTPUT_MAX_SKIP_ALIGN (file, align, max_skip);
181650503Sobrien#else
1817117404Skan#ifdef ASM_OUTPUT_ALIGN_WITH_NOP
1818117404Skan              ASM_OUTPUT_ALIGN_WITH_NOP (file, align);
1819117404Skan#else
182090087Sobrien	      ASM_OUTPUT_ALIGN (file, align);
182150503Sobrien#endif
1822117404Skan#endif
182390087Sobrien	    }
182450503Sobrien	}
182552515Sobrien#ifdef HAVE_cc0
182618334Speter      CC_STATUS_INIT;
182752515Sobrien      /* If this label is reached from only one place, set the condition
182852515Sobrien	 codes from the instruction just before the branch.  */
182952515Sobrien
183052515Sobrien      /* Disabled because some insns set cc_status in the C output code
183152515Sobrien	 and NOTICE_UPDATE_CC alone can set incorrect status.  */
183252515Sobrien      if (0 /* optimize && LABEL_NUSES (insn) == 1*/)
183352515Sobrien	{
183452515Sobrien	  rtx jump = LABEL_REFS (insn);
183552515Sobrien	  rtx barrier = prev_nonnote_insn (insn);
183652515Sobrien	  rtx prev;
183752515Sobrien	  /* If the LABEL_REFS field of this label has been set to point
183852515Sobrien	     at a branch, the predecessor of the branch is a regular
183952515Sobrien	     insn, and that branch is the only way to reach this label,
184052515Sobrien	     set the condition codes based on the branch and its
184152515Sobrien	     predecessor.  */
184252515Sobrien	  if (barrier && GET_CODE (barrier) == BARRIER
184352515Sobrien	      && jump && GET_CODE (jump) == JUMP_INSN
184452515Sobrien	      && (prev = prev_nonnote_insn (jump))
184552515Sobrien	      && GET_CODE (prev) == INSN)
184652515Sobrien	    {
184752515Sobrien	      NOTICE_UPDATE_CC (PATTERN (prev), prev);
184852515Sobrien	      NOTICE_UPDATE_CC (PATTERN (jump), jump);
184952515Sobrien	    }
185052515Sobrien	}
185152515Sobrien#endif
185218334Speter      if (prescan > 0)
185318334Speter	break;
185450503Sobrien
185590087Sobrien      if (LABEL_NAME (insn))
185690087Sobrien	(*debug_hooks->label) (insn);
185790087Sobrien
185818334Speter      if (app_on)
185918334Speter	{
186050503Sobrien	  fputs (ASM_APP_OFF, file);
186118334Speter	  app_on = 0;
186218334Speter	}
186318334Speter      if (NEXT_INSN (insn) != 0
186418334Speter	  && GET_CODE (NEXT_INSN (insn)) == JUMP_INSN)
186518334Speter	{
186618334Speter	  rtx nextbody = PATTERN (NEXT_INSN (insn));
186718334Speter
186818334Speter	  /* If this label is followed by a jump-table,
186918334Speter	     make sure we put the label in the read-only section.  Also
187018334Speter	     possibly write the label and jump table together.  */
187118334Speter
187218334Speter	  if (GET_CODE (nextbody) == ADDR_VEC
187318334Speter	      || GET_CODE (nextbody) == ADDR_DIFF_VEC)
187418334Speter	    {
187552515Sobrien#if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)
187652515Sobrien	      /* In this case, the case vector is being moved by the
187752515Sobrien		 target, so don't output the label at all.  Leave that
187852515Sobrien		 to the back end macros.  */
187952515Sobrien#else
188050503Sobrien	      if (! JUMP_TABLES_IN_TEXT_SECTION)
188150503Sobrien		{
188290087Sobrien		  int log_align;
188390087Sobrien
188450503Sobrien		  readonly_data_section ();
188590087Sobrien
188690087Sobrien#ifdef ADDR_VEC_ALIGN
188790087Sobrien		  log_align = ADDR_VEC_ALIGN (NEXT_INSN (insn));
188890087Sobrien#else
188990087Sobrien		  log_align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
189090087Sobrien#endif
189190087Sobrien		  ASM_OUTPUT_ALIGN (file, log_align);
189250503Sobrien		}
189350503Sobrien	      else
189450503Sobrien		function_section (current_function_decl);
189550503Sobrien
189618334Speter#ifdef ASM_OUTPUT_CASE_LABEL
189718334Speter	      ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn),
189818334Speter				     NEXT_INSN (insn));
189918334Speter#else
1900132727Skan	      (*targetm.asm_out.internal_label) (file, "L", CODE_LABEL_NUMBER (insn));
190118334Speter#endif
190252515Sobrien#endif
190318334Speter	      break;
190418334Speter	    }
190518334Speter	}
1906117404Skan      if (LABEL_ALT_ENTRY_P (insn))
1907117404Skan	output_alternate_entry_point (file, insn);
190890087Sobrien      else
1909132727Skan	(*targetm.asm_out.internal_label) (file, "L", CODE_LABEL_NUMBER (insn));
191018334Speter      break;
191118334Speter
191218334Speter    default:
191318334Speter      {
191490087Sobrien	rtx body = PATTERN (insn);
191518334Speter	int insn_code_number;
191652515Sobrien	const char *template;
191718334Speter	rtx note;
191818334Speter
191918334Speter	/* An INSN, JUMP_INSN or CALL_INSN.
192018334Speter	   First check for special kinds that recog doesn't recognize.  */
192118334Speter
1922132727Skan	if (GET_CODE (body) == USE /* These are just declarations.  */
192318334Speter	    || GET_CODE (body) == CLOBBER)
192418334Speter	  break;
192518334Speter
192618334Speter#ifdef HAVE_cc0
192718334Speter	/* If there is a REG_CC_SETTER note on this insn, it means that
192818334Speter	   the setting of the condition code was done in the delay slot
192918334Speter	   of the insn that branched here.  So recover the cc status
193018334Speter	   from the insn that set it.  */
193118334Speter
193218334Speter	note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX);
193318334Speter	if (note)
193418334Speter	  {
193518334Speter	    NOTICE_UPDATE_CC (PATTERN (XEXP (note, 0)), XEXP (note, 0));
193618334Speter	    cc_prev_status = cc_status;
193718334Speter	  }
193818334Speter#endif
193918334Speter
194018334Speter	/* Detect insns that are really jump-tables
194118334Speter	   and output them as such.  */
194218334Speter
194318334Speter	if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
194418334Speter	  {
194552515Sobrien#if !(defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC))
194690087Sobrien	    int vlen, idx;
194752515Sobrien#endif
194818334Speter
194918334Speter	    if (prescan > 0)
195018334Speter	      break;
195118334Speter
195218334Speter	    if (app_on)
195318334Speter	      {
195450503Sobrien		fputs (ASM_APP_OFF, file);
195518334Speter		app_on = 0;
195618334Speter	      }
195718334Speter
195852515Sobrien#if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)
195952515Sobrien	    if (GET_CODE (body) == ADDR_VEC)
196052515Sobrien	      {
196152515Sobrien#ifdef ASM_OUTPUT_ADDR_VEC
196252515Sobrien		ASM_OUTPUT_ADDR_VEC (PREV_INSN (insn), body);
196352515Sobrien#else
196490087Sobrien		abort ();
196552515Sobrien#endif
196652515Sobrien	      }
196752515Sobrien	    else
196852515Sobrien	      {
196952515Sobrien#ifdef ASM_OUTPUT_ADDR_DIFF_VEC
197052515Sobrien		ASM_OUTPUT_ADDR_DIFF_VEC (PREV_INSN (insn), body);
197152515Sobrien#else
197290087Sobrien		abort ();
197352515Sobrien#endif
197452515Sobrien	      }
197552515Sobrien#else
197618334Speter	    vlen = XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC);
197718334Speter	    for (idx = 0; idx < vlen; idx++)
197818334Speter	      {
197918334Speter		if (GET_CODE (body) == ADDR_VEC)
198018334Speter		  {
198118334Speter#ifdef ASM_OUTPUT_ADDR_VEC_ELT
198218334Speter		    ASM_OUTPUT_ADDR_VEC_ELT
198318334Speter		      (file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0)));
198418334Speter#else
198518334Speter		    abort ();
198618334Speter#endif
198718334Speter		  }
198818334Speter		else
198918334Speter		  {
199018334Speter#ifdef ASM_OUTPUT_ADDR_DIFF_ELT
199118334Speter		    ASM_OUTPUT_ADDR_DIFF_ELT
199218334Speter		      (file,
199350503Sobrien		       body,
199418334Speter		       CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)),
199518334Speter		       CODE_LABEL_NUMBER (XEXP (XEXP (body, 0), 0)));
199618334Speter#else
199718334Speter		    abort ();
199818334Speter#endif
199918334Speter		  }
200018334Speter	      }
200118334Speter#ifdef ASM_OUTPUT_CASE_END
200218334Speter	    ASM_OUTPUT_CASE_END (file,
200318334Speter				 CODE_LABEL_NUMBER (PREV_INSN (insn)),
200418334Speter				 insn);
200518334Speter#endif
200652515Sobrien#endif
200718334Speter
200818334Speter	    function_section (current_function_decl);
200918334Speter
201018334Speter	    break;
201118334Speter	  }
2012132727Skan	/* Output this line note if it is the first or the last line
2013132727Skan	   note in a row.  */
2014132727Skan	if (notice_source_line (insn))
2015132727Skan	  {
2016132727Skan	    (*debug_hooks->source_line) (last_linenum, last_filename);
2017132727Skan	  }
201818334Speter
201918334Speter	if (GET_CODE (body) == ASM_INPUT)
202018334Speter	  {
202190087Sobrien	    const char *string = XSTR (body, 0);
202290087Sobrien
202318334Speter	    /* There's no telling what that did to the condition codes.  */
202418334Speter	    CC_STATUS_INIT;
202518334Speter	    if (prescan > 0)
202618334Speter	      break;
202790087Sobrien
202890087Sobrien	    if (string[0])
202918334Speter	      {
203090087Sobrien		if (! app_on)
203190087Sobrien		  {
203290087Sobrien		    fputs (ASM_APP_ON, file);
203390087Sobrien		    app_on = 1;
203490087Sobrien		  }
203590087Sobrien		fprintf (asm_out_file, "\t%s\n", string);
203618334Speter	      }
203718334Speter	    break;
203818334Speter	  }
203918334Speter
204018334Speter	/* Detect `asm' construct with operands.  */
204118334Speter	if (asm_noperands (body) >= 0)
204218334Speter	  {
204350503Sobrien	    unsigned int noperands = asm_noperands (body);
2044132727Skan	    rtx *ops = alloca (noperands * sizeof (rtx));
204590087Sobrien	    const char *string;
204618334Speter
204718334Speter	    /* There's no telling what that did to the condition codes.  */
204818334Speter	    CC_STATUS_INIT;
204918334Speter	    if (prescan > 0)
205018334Speter	      break;
205118334Speter
205218334Speter	    /* Get out the operand values.  */
205390087Sobrien	    string = decode_asm_operands (body, ops, NULL, NULL, NULL);
205418334Speter	    /* Inhibit aborts on what would otherwise be compiler bugs.  */
205518334Speter	    insn_noperands = noperands;
205618334Speter	    this_is_asm_operands = insn;
205718334Speter
2058132727Skan#ifdef FINAL_PRESCAN_INSN
2059132727Skan	    FINAL_PRESCAN_INSN (insn, ops, insn_noperands);
2060132727Skan#endif
2061132727Skan
206218334Speter	    /* Output the insn using them.  */
206390087Sobrien	    if (string[0])
206490087Sobrien	      {
206590087Sobrien		if (! app_on)
206690087Sobrien		  {
206790087Sobrien		    fputs (ASM_APP_ON, file);
206890087Sobrien		    app_on = 1;
206990087Sobrien		  }
207090087Sobrien	        output_asm_insn (string, ops);
207190087Sobrien	      }
207290087Sobrien
207318334Speter	    this_is_asm_operands = 0;
207418334Speter	    break;
207518334Speter	  }
207618334Speter
207718334Speter	if (prescan <= 0 && app_on)
207818334Speter	  {
207950503Sobrien	    fputs (ASM_APP_OFF, file);
208018334Speter	    app_on = 0;
208118334Speter	  }
208218334Speter
208318334Speter	if (GET_CODE (body) == SEQUENCE)
208418334Speter	  {
208518334Speter	    /* A delayed-branch sequence */
208690087Sobrien	    int i;
208718334Speter	    rtx next;
208818334Speter
208918334Speter	    if (prescan > 0)
209018334Speter	      break;
209118334Speter	    final_sequence = body;
209218334Speter
2093132727Skan	    /* Record the delay slots' frame information before the branch.
2094132727Skan	       This is needed for delayed calls: see execute_cfa_program().  */
2095132727Skan#if defined (DWARF2_UNWIND_INFO)
2096132727Skan	    if (dwarf2out_do_frame ())
2097132727Skan	      for (i = 1; i < XVECLEN (body, 0); i++)
2098132727Skan		dwarf2out_frame_debug (XVECEXP (body, 0, i));
2099132727Skan#endif
2100132727Skan
210118334Speter	    /* The first insn in this SEQUENCE might be a JUMP_INSN that will
210218334Speter	       force the restoration of a comparison that was previously
210318334Speter	       thought unnecessary.  If that happens, cancel this sequence
210418334Speter	       and cause that insn to be restored.  */
210518334Speter
2106132727Skan	    next = final_scan_insn (XVECEXP (body, 0, 0), file, 0, prescan, 1, seen);
210718334Speter	    if (next != XVECEXP (body, 0, 1))
210818334Speter	      {
210918334Speter		final_sequence = 0;
211018334Speter		return next;
211118334Speter	      }
211218334Speter
211318334Speter	    for (i = 1; i < XVECLEN (body, 0); i++)
211418334Speter	      {
211518334Speter		rtx insn = XVECEXP (body, 0, i);
211618334Speter		rtx next = NEXT_INSN (insn);
211718334Speter		/* We loop in case any instruction in a delay slot gets
211818334Speter		   split.  */
211918334Speter		do
2120132727Skan		  insn = final_scan_insn (insn, file, 0, prescan, 1, seen);
212118334Speter		while (insn != next);
212218334Speter	      }
212318334Speter#ifdef DBR_OUTPUT_SEQEND
212418334Speter	    DBR_OUTPUT_SEQEND (file);
212518334Speter#endif
212618334Speter	    final_sequence = 0;
212718334Speter
212818334Speter	    /* If the insn requiring the delay slot was a CALL_INSN, the
212918334Speter	       insns in the delay slot are actually executed before the
213018334Speter	       called function.  Hence we don't preserve any CC-setting
213118334Speter	       actions in these insns and the CC must be marked as being
213218334Speter	       clobbered by the function.  */
213318334Speter	    if (GET_CODE (XVECEXP (body, 0, 0)) == CALL_INSN)
213450503Sobrien	      {
213550503Sobrien		CC_STATUS_INIT;
213650503Sobrien	      }
213718334Speter	    break;
213818334Speter	  }
213918334Speter
214018334Speter	/* We have a real machine instruction as rtl.  */
214118334Speter
214218334Speter	body = PATTERN (insn);
214318334Speter
214418334Speter#ifdef HAVE_cc0
214590087Sobrien	set = single_set (insn);
214650503Sobrien
214718334Speter	/* Check for redundant test and compare instructions
214818334Speter	   (when the condition codes are already set up as desired).
214918334Speter	   This is done only when optimizing; if not optimizing,
215018334Speter	   it should be possible for the user to alter a variable
215118334Speter	   with the debugger in between statements
215218334Speter	   and the next statement should reexamine the variable
215318334Speter	   to compute the condition codes.  */
215418334Speter
215550503Sobrien	if (optimize)
215618334Speter	  {
215750503Sobrien	    if (set
215850503Sobrien		&& GET_CODE (SET_DEST (set)) == CC0
215950503Sobrien		&& insn != last_ignored_compare)
216018334Speter	      {
216150503Sobrien		if (GET_CODE (SET_SRC (set)) == SUBREG)
216290087Sobrien		  SET_SRC (set) = alter_subreg (&SET_SRC (set));
216350503Sobrien		else if (GET_CODE (SET_SRC (set)) == COMPARE)
216418334Speter		  {
216550503Sobrien		    if (GET_CODE (XEXP (SET_SRC (set), 0)) == SUBREG)
216650503Sobrien		      XEXP (SET_SRC (set), 0)
216790087Sobrien			= alter_subreg (&XEXP (SET_SRC (set), 0));
216850503Sobrien		    if (GET_CODE (XEXP (SET_SRC (set), 1)) == SUBREG)
216950503Sobrien		      XEXP (SET_SRC (set), 1)
217090087Sobrien			= alter_subreg (&XEXP (SET_SRC (set), 1));
217118334Speter		  }
217250503Sobrien		if ((cc_status.value1 != 0
217350503Sobrien		     && rtx_equal_p (SET_SRC (set), cc_status.value1))
217450503Sobrien		    || (cc_status.value2 != 0
217550503Sobrien			&& rtx_equal_p (SET_SRC (set), cc_status.value2)))
217650503Sobrien		  {
217750503Sobrien		    /* Don't delete insn if it has an addressing side-effect.  */
217890087Sobrien		    if (! FIND_REG_INC_NOTE (insn, NULL_RTX)
217950503Sobrien			/* or if anything in it is volatile.  */
218050503Sobrien			&& ! volatile_refs_p (PATTERN (insn)))
218150503Sobrien		      {
218250503Sobrien			/* We don't really delete the insn; just ignore it.  */
218350503Sobrien			last_ignored_compare = insn;
218450503Sobrien			break;
218550503Sobrien		      }
218650503Sobrien		  }
218718334Speter	      }
218818334Speter	  }
218918334Speter#endif
219018334Speter
219118334Speter#ifndef STACK_REGS
219218334Speter	/* Don't bother outputting obvious no-ops, even without -O.
219318334Speter	   This optimization is fast and doesn't interfere with debugging.
219418334Speter	   Don't do this if the insn is in a delay slot, since this
219518334Speter	   will cause an improper number of delay insns to be written.  */
219618334Speter	if (final_sequence == 0
219718334Speter	    && prescan >= 0
219818334Speter	    && GET_CODE (insn) == INSN && GET_CODE (body) == SET
219918334Speter	    && GET_CODE (SET_SRC (body)) == REG
220018334Speter	    && GET_CODE (SET_DEST (body)) == REG
220118334Speter	    && REGNO (SET_SRC (body)) == REGNO (SET_DEST (body)))
220218334Speter	  break;
220318334Speter#endif
220418334Speter
220518334Speter#ifdef HAVE_cc0
220618334Speter	/* If this is a conditional branch, maybe modify it
220718334Speter	   if the cc's are in a nonstandard state
220818334Speter	   so that it accomplishes the same thing that it would
220918334Speter	   do straightforwardly if the cc's were set up normally.  */
221018334Speter
221118334Speter	if (cc_status.flags != 0
221218334Speter	    && GET_CODE (insn) == JUMP_INSN
221318334Speter	    && GET_CODE (body) == SET
221418334Speter	    && SET_DEST (body) == pc_rtx
221518334Speter	    && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE
221618334Speter	    && GET_RTX_CLASS (GET_CODE (XEXP (SET_SRC (body), 0))) == '<'
221718334Speter	    && XEXP (XEXP (SET_SRC (body), 0), 0) == cc0_rtx
221818334Speter	    /* This is done during prescan; it is not done again
221918334Speter	       in final scan when prescan has been done.  */
222018334Speter	    && prescan >= 0)
222118334Speter	  {
222218334Speter	    /* This function may alter the contents of its argument
222318334Speter	       and clear some of the cc_status.flags bits.
222418334Speter	       It may also return 1 meaning condition now always true
222518334Speter	       or -1 meaning condition now always false
222618334Speter	       or 2 meaning condition nontrivial but altered.  */
222790087Sobrien	    int result = alter_cond (XEXP (SET_SRC (body), 0));
222818334Speter	    /* If condition now has fixed value, replace the IF_THEN_ELSE
222918334Speter	       with its then-operand or its else-operand.  */
223018334Speter	    if (result == 1)
223118334Speter	      SET_SRC (body) = XEXP (SET_SRC (body), 1);
223218334Speter	    if (result == -1)
223318334Speter	      SET_SRC (body) = XEXP (SET_SRC (body), 2);
223418334Speter
223518334Speter	    /* The jump is now either unconditional or a no-op.
223618334Speter	       If it has become a no-op, don't try to output it.
223718334Speter	       (It would not be recognized.)  */
223818334Speter	    if (SET_SRC (body) == pc_rtx)
223918334Speter	      {
224090087Sobrien	        delete_insn (insn);
224118334Speter		break;
224218334Speter	      }
224318334Speter	    else if (GET_CODE (SET_SRC (body)) == RETURN)
224418334Speter	      /* Replace (set (pc) (return)) with (return).  */
224518334Speter	      PATTERN (insn) = body = SET_SRC (body);
224618334Speter
224718334Speter	    /* Rerecognize the instruction if it has changed.  */
224818334Speter	    if (result != 0)
224918334Speter	      INSN_CODE (insn) = -1;
225018334Speter	  }
225118334Speter
225218334Speter	/* Make same adjustments to instructions that examine the
225350503Sobrien	   condition codes without jumping and instructions that
225450503Sobrien	   handle conditional moves (if this machine has either one).  */
225518334Speter
225618334Speter	if (cc_status.flags != 0
225750503Sobrien	    && set != 0)
225818334Speter	  {
225950503Sobrien	    rtx cond_rtx, then_rtx, else_rtx;
226090087Sobrien
226150503Sobrien	    if (GET_CODE (insn) != JUMP_INSN
226250503Sobrien		&& GET_CODE (SET_SRC (set)) == IF_THEN_ELSE)
226318334Speter	      {
226450503Sobrien		cond_rtx = XEXP (SET_SRC (set), 0);
226550503Sobrien		then_rtx = XEXP (SET_SRC (set), 1);
226650503Sobrien		else_rtx = XEXP (SET_SRC (set), 2);
226750503Sobrien	      }
226850503Sobrien	    else
226950503Sobrien	      {
227050503Sobrien		cond_rtx = SET_SRC (set);
227150503Sobrien		then_rtx = const_true_rtx;
227250503Sobrien		else_rtx = const0_rtx;
227350503Sobrien	      }
227490087Sobrien
227550503Sobrien	    switch (GET_CODE (cond_rtx))
227650503Sobrien	      {
227718334Speter	      case GTU:
227818334Speter	      case GT:
227918334Speter	      case LTU:
228018334Speter	      case LT:
228118334Speter	      case GEU:
228218334Speter	      case GE:
228318334Speter	      case LEU:
228418334Speter	      case LE:
228518334Speter	      case EQ:
228618334Speter	      case NE:
228718334Speter		{
228890087Sobrien		  int result;
228950503Sobrien		  if (XEXP (cond_rtx, 0) != cc0_rtx)
229018334Speter		    break;
229150503Sobrien		  result = alter_cond (cond_rtx);
229218334Speter		  if (result == 1)
229350503Sobrien		    validate_change (insn, &SET_SRC (set), then_rtx, 0);
229418334Speter		  else if (result == -1)
229550503Sobrien		    validate_change (insn, &SET_SRC (set), else_rtx, 0);
229618334Speter		  else if (result == 2)
229718334Speter		    INSN_CODE (insn) = -1;
229850503Sobrien		  if (SET_DEST (set) == SET_SRC (set))
229990087Sobrien		    delete_insn (insn);
230018334Speter		}
230150503Sobrien		break;
230250503Sobrien
230350503Sobrien	      default:
230450503Sobrien		break;
230518334Speter	      }
230618334Speter	  }
230750503Sobrien
230818334Speter#endif
230918334Speter
231090087Sobrien#ifdef HAVE_peephole
231118334Speter	/* Do machine-specific peephole optimizations if desired.  */
231218334Speter
231318334Speter	if (optimize && !flag_no_peephole && !nopeepholes)
231418334Speter	  {
231518334Speter	    rtx next = peephole (insn);
231618334Speter	    /* When peepholing, if there were notes within the peephole,
231718334Speter	       emit them before the peephole.  */
231818334Speter	    if (next != 0 && next != NEXT_INSN (insn))
231918334Speter	      {
232018334Speter		rtx prev = PREV_INSN (insn);
232118334Speter
232218334Speter		for (note = NEXT_INSN (insn); note != next;
232318334Speter		     note = NEXT_INSN (note))
2324132727Skan		  final_scan_insn (note, file, optimize, prescan, nopeepholes, seen);
232518334Speter
232618334Speter		/* In case this is prescan, put the notes
232718334Speter		   in proper position for later rescan.  */
232818334Speter		note = NEXT_INSN (insn);
232918334Speter		PREV_INSN (note) = prev;
233018334Speter		NEXT_INSN (prev) = note;
233118334Speter		NEXT_INSN (PREV_INSN (next)) = insn;
233218334Speter		PREV_INSN (insn) = PREV_INSN (next);
233318334Speter		NEXT_INSN (insn) = next;
233418334Speter		PREV_INSN (next) = insn;
233518334Speter	      }
233618334Speter
233718334Speter	    /* PEEPHOLE might have changed this.  */
233818334Speter	    body = PATTERN (insn);
233918334Speter	  }
234090087Sobrien#endif
234118334Speter
234218334Speter	/* Try to recognize the instruction.
234318334Speter	   If successful, verify that the operands satisfy the
234418334Speter	   constraints for the instruction.  Crash if they don't,
234518334Speter	   since `reload' should have changed them so that they do.  */
234618334Speter
234718334Speter	insn_code_number = recog_memoized (insn);
234852515Sobrien	cleanup_subreg_operands (insn);
234918334Speter
2350117404Skan	/* Dump the insn in the assembly for debugging.  */
2351117404Skan	if (flag_dump_rtl_in_asm)
2352117404Skan	  {
2353117404Skan	    print_rtx_head = ASM_COMMENT_START;
2354117404Skan	    print_rtl_single (asm_out_file, insn);
2355117404Skan	    print_rtx_head = "";
2356117404Skan	  }
235790087Sobrien
235890087Sobrien	if (! constrain_operands_cached (1))
235918334Speter	  fatal_insn_not_found (insn);
236018334Speter
236118334Speter	/* Some target machines need to prescan each insn before
236218334Speter	   it is output.  */
236318334Speter
236418334Speter#ifdef FINAL_PRESCAN_INSN
236590087Sobrien	FINAL_PRESCAN_INSN (insn, recog_data.operand, recog_data.n_operands);
236618334Speter#endif
236718334Speter
236890087Sobrien#ifdef HAVE_conditional_execution
236990087Sobrien	if (GET_CODE (PATTERN (insn)) == COND_EXEC)
237090087Sobrien	  current_insn_predicate = COND_EXEC_TEST (PATTERN (insn));
237190087Sobrien	else
237290087Sobrien	  current_insn_predicate = NULL_RTX;
237390087Sobrien#endif
237490087Sobrien
237518334Speter#ifdef HAVE_cc0
237618334Speter	cc_prev_status = cc_status;
237718334Speter
237818334Speter	/* Update `cc_status' for this instruction.
237918334Speter	   The instruction's output routine may change it further.
238018334Speter	   If the output routine for a jump insn needs to depend
238118334Speter	   on the cc status, it should look at cc_prev_status.  */
238218334Speter
238318334Speter	NOTICE_UPDATE_CC (body, insn);
238418334Speter#endif
238518334Speter
238690087Sobrien	current_output_insn = debug_insn = insn;
238718334Speter
238890087Sobrien#if defined (DWARF2_UNWIND_INFO)
238950503Sobrien	if (GET_CODE (insn) == CALL_INSN && dwarf2out_do_frame ())
239050503Sobrien	  dwarf2out_frame_debug (insn);
239150503Sobrien#endif
239250503Sobrien
239390087Sobrien	/* Find the proper template for this insn.  */
239490087Sobrien	template = get_insn_template (insn_code_number, insn);
239518334Speter
239690087Sobrien	/* If the C code returns 0, it means that it is a jump insn
239790087Sobrien	   which follows a deleted test insn, and that test insn
239890087Sobrien	   needs to be reinserted.  */
239918334Speter	if (template == 0)
240018334Speter	  {
240190087Sobrien	    rtx prev;
240218334Speter
240390087Sobrien	    if (prev_nonnote_insn (insn) != last_ignored_compare)
240490087Sobrien	      abort ();
240590087Sobrien
240690087Sobrien	    /* We have already processed the notes between the setter and
240790087Sobrien	       the user.  Make sure we don't process them again, this is
240890087Sobrien	       particularly important if one of the notes is a block
240990087Sobrien	       scope note or an EH note.  */
241090087Sobrien	    for (prev = insn;
241190087Sobrien		 prev != last_ignored_compare;
241290087Sobrien		 prev = PREV_INSN (prev))
241318334Speter	      {
241490087Sobrien		if (GET_CODE (prev) == NOTE)
241590087Sobrien		  delete_insn (prev);	/* Use delete_note.  */
241618334Speter	      }
241790087Sobrien
241890087Sobrien	    return prev;
241918334Speter	  }
242018334Speter
242118334Speter	/* If the template is the string "#", it means that this insn must
242218334Speter	   be split.  */
242318334Speter	if (template[0] == '#' && template[1] == '\0')
242418334Speter	  {
242518334Speter	    rtx new = try_split (body, insn, 0);
242618334Speter
242718334Speter	    /* If we didn't split the insn, go away.  */
242818334Speter	    if (new == insn && PATTERN (new) == body)
242990087Sobrien	      fatal_insn ("could not split insn", insn);
243090087Sobrien
243150503Sobrien#ifdef HAVE_ATTR_length
243250503Sobrien	    /* This instruction should have been split in shorten_branches,
243350503Sobrien	       to ensure that we would have valid length info for the
243450503Sobrien	       splitees.  */
243550503Sobrien	    abort ();
243650503Sobrien#endif
243750503Sobrien
243818334Speter	    return new;
243918334Speter	  }
244090087Sobrien
244118334Speter	if (prescan > 0)
244218334Speter	  break;
244318334Speter
244490087Sobrien#ifdef IA64_UNWIND_INFO
244590087Sobrien	IA64_UNWIND_EMIT (asm_out_file, insn);
244690087Sobrien#endif
244718334Speter	/* Output assembler code from the template.  */
244818334Speter
244990087Sobrien	output_asm_insn (template, recog_data.operand);
245018334Speter
2451132727Skan	/* If necessary, report the effect that the instruction has on
2452132727Skan	   the unwind info.   We've already done this for delay slots
2453132727Skan	   and call instructions.  */
245450503Sobrien#if defined (DWARF2_UNWIND_INFO)
2455132727Skan	if (GET_CODE (insn) == INSN
2456132727Skan#if !defined (HAVE_prologue)
2457132727Skan	    && !ACCUMULATE_OUTGOING_ARGS
2458132727Skan#endif
2459132727Skan	    && final_sequence == 0
246090087Sobrien	    && dwarf2out_do_frame ())
246150503Sobrien	  dwarf2out_frame_debug (insn);
246250503Sobrien#endif
246350503Sobrien
246418334Speter#if 0
2465132727Skan	/* It's not at all clear why we did this and doing so used to
2466132727Skan	   interfere with tests that used REG_WAS_0 notes, which are
2467132727Skan	   now gone, so let's try with this out.  */
246818334Speter
246918334Speter	/* Mark this insn as having been output.  */
247018334Speter	INSN_DELETED_P (insn) = 1;
247118334Speter#endif
247218334Speter
247390087Sobrien	/* Emit information for vtable gc.  */
247490087Sobrien	note = find_reg_note (insn, REG_VTABLE_REF, NULL_RTX);
247590087Sobrien
247690087Sobrien	current_output_insn = debug_insn = 0;
247718334Speter      }
247818334Speter    }
247918334Speter  return NEXT_INSN (insn);
248018334Speter}
248118334Speter
248218334Speter/* Output debugging info to the assembler file FILE
248318334Speter   based on the NOTE-insn INSN, assumed to be a line number.  */
248418334Speter
2485132727Skanstatic bool
2486132727Skannotice_source_line (rtx insn)
248718334Speter{
2488132727Skan  const char *filename = insn_file (insn);
2489132727Skan  int linenum = insn_line (insn);
249018334Speter
2491132727Skan  if (filename && (filename != last_filename || last_linenum != linenum))
2492132727Skan    {
2493132727Skan      last_filename = filename;
2494132727Skan      last_linenum = linenum;
2495132727Skan      high_block_linenum = MAX (last_linenum, high_block_linenum);
2496132727Skan      high_function_linenum = MAX (last_linenum, high_function_linenum);
2497132727Skan      return true;
2498132727Skan    }
2499132727Skan  return false;
250018334Speter}
250118334Speter
250252515Sobrien/* For each operand in INSN, simplify (subreg (reg)) so that it refers
250352515Sobrien   directly to the desired hard register.  */
250490087Sobrien
250552515Sobrienvoid
2506132727Skancleanup_subreg_operands (rtx insn)
250752515Sobrien{
250852515Sobrien  int i;
250990087Sobrien  extract_insn_cached (insn);
251090087Sobrien  for (i = 0; i < recog_data.n_operands; i++)
251152515Sobrien    {
2512132727Skan      /* The following test cannot use recog_data.operand when testing
251390087Sobrien	 for a SUBREG: the underlying object might have been changed
251490087Sobrien	 already if we are inside a match_operator expression that
251590087Sobrien	 matches the else clause.  Instead we test the underlying
251690087Sobrien	 expression directly.  */
251790087Sobrien      if (GET_CODE (*recog_data.operand_loc[i]) == SUBREG)
251890087Sobrien	recog_data.operand[i] = alter_subreg (recog_data.operand_loc[i]);
251990087Sobrien      else if (GET_CODE (recog_data.operand[i]) == PLUS
252090087Sobrien	       || GET_CODE (recog_data.operand[i]) == MULT
252190087Sobrien	       || GET_CODE (recog_data.operand[i]) == MEM)
252290087Sobrien	recog_data.operand[i] = walk_alter_subreg (recog_data.operand_loc[i]);
252352515Sobrien    }
252452515Sobrien
252590087Sobrien  for (i = 0; i < recog_data.n_dups; i++)
252652515Sobrien    {
252790087Sobrien      if (GET_CODE (*recog_data.dup_loc[i]) == SUBREG)
252890087Sobrien	*recog_data.dup_loc[i] = alter_subreg (recog_data.dup_loc[i]);
252990087Sobrien      else if (GET_CODE (*recog_data.dup_loc[i]) == PLUS
253090087Sobrien	       || GET_CODE (*recog_data.dup_loc[i]) == MULT
253190087Sobrien	       || GET_CODE (*recog_data.dup_loc[i]) == MEM)
253290087Sobrien	*recog_data.dup_loc[i] = walk_alter_subreg (recog_data.dup_loc[i]);
253352515Sobrien    }
253452515Sobrien}
253552515Sobrien
253618334Speter/* If X is a SUBREG, replace it with a REG or a MEM,
253718334Speter   based on the thing it is a subreg of.  */
253818334Speter
253918334Speterrtx
2540132727Skanalter_subreg (rtx *xp)
254118334Speter{
254290087Sobrien  rtx x = *xp;
254390087Sobrien  rtx y = SUBREG_REG (x);
254450503Sobrien
254590087Sobrien  /* simplify_subreg does not remove subreg from volatile references.
254690087Sobrien     We are required to.  */
254790087Sobrien  if (GET_CODE (y) == MEM)
254890087Sobrien    *xp = adjust_address (y, GET_MODE (x), SUBREG_BYTE (x));
254990087Sobrien  else
255018334Speter    {
255190087Sobrien      rtx new = simplify_subreg (GET_MODE (x), y, GET_MODE (y),
255290087Sobrien				 SUBREG_BYTE (x));
255350503Sobrien
255490087Sobrien      if (new != 0)
255590087Sobrien	*xp = new;
255690087Sobrien      /* Simplify_subreg can't handle some REG cases, but we have to.  */
255790087Sobrien      else if (GET_CODE (y) == REG)
255890087Sobrien	{
255990087Sobrien	  unsigned int regno = subreg_hard_regno (x, 1);
2560132727Skan	  *xp = gen_rtx_REG_offset (y, GET_MODE (x), regno, SUBREG_BYTE (x));
256190087Sobrien	}
256290087Sobrien      else
256390087Sobrien	abort ();
256418334Speter    }
256518334Speter
256690087Sobrien  return *xp;
256718334Speter}
256818334Speter
256918334Speter/* Do alter_subreg on all the SUBREGs contained in X.  */
257018334Speter
257118334Speterstatic rtx
2572132727Skanwalk_alter_subreg (rtx *xp)
257318334Speter{
257490087Sobrien  rtx x = *xp;
257518334Speter  switch (GET_CODE (x))
257618334Speter    {
257718334Speter    case PLUS:
257818334Speter    case MULT:
257990087Sobrien      XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0));
258090087Sobrien      XEXP (x, 1) = walk_alter_subreg (&XEXP (x, 1));
258118334Speter      break;
258218334Speter
258318334Speter    case MEM:
258490087Sobrien      XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0));
258518334Speter      break;
258618334Speter
258718334Speter    case SUBREG:
258890087Sobrien      return alter_subreg (xp);
258990087Sobrien
259050503Sobrien    default:
259150503Sobrien      break;
259218334Speter    }
259318334Speter
259490087Sobrien  return *xp;
259518334Speter}
259618334Speter
259718334Speter#ifdef HAVE_cc0
259818334Speter
259918334Speter/* Given BODY, the body of a jump instruction, alter the jump condition
260018334Speter   as required by the bits that are set in cc_status.flags.
260118334Speter   Not all of the bits there can be handled at this level in all cases.
260218334Speter
260318334Speter   The value is normally 0.
260418334Speter   1 means that the condition has become always true.
260518334Speter   -1 means that the condition has become always false.
260618334Speter   2 means that COND has been altered.  */
260718334Speter
260818334Speterstatic int
2609132727Skanalter_cond (rtx cond)
261018334Speter{
261118334Speter  int value = 0;
261218334Speter
261318334Speter  if (cc_status.flags & CC_REVERSED)
261418334Speter    {
261518334Speter      value = 2;
261618334Speter      PUT_CODE (cond, swap_condition (GET_CODE (cond)));
261718334Speter    }
261818334Speter
261918334Speter  if (cc_status.flags & CC_INVERTED)
262018334Speter    {
262118334Speter      value = 2;
262218334Speter      PUT_CODE (cond, reverse_condition (GET_CODE (cond)));
262318334Speter    }
262418334Speter
262518334Speter  if (cc_status.flags & CC_NOT_POSITIVE)
262618334Speter    switch (GET_CODE (cond))
262718334Speter      {
262818334Speter      case LE:
262918334Speter      case LEU:
263018334Speter      case GEU:
263118334Speter	/* Jump becomes unconditional.  */
263218334Speter	return 1;
263318334Speter
263418334Speter      case GT:
263518334Speter      case GTU:
263618334Speter      case LTU:
263718334Speter	/* Jump becomes no-op.  */
263818334Speter	return -1;
263918334Speter
264018334Speter      case GE:
264118334Speter	PUT_CODE (cond, EQ);
264218334Speter	value = 2;
264318334Speter	break;
264418334Speter
264518334Speter      case LT:
264618334Speter	PUT_CODE (cond, NE);
264718334Speter	value = 2;
264818334Speter	break;
264990087Sobrien
265050503Sobrien      default:
265150503Sobrien	break;
265218334Speter      }
265318334Speter
265418334Speter  if (cc_status.flags & CC_NOT_NEGATIVE)
265518334Speter    switch (GET_CODE (cond))
265618334Speter      {
265718334Speter      case GE:
265818334Speter      case GEU:
265918334Speter	/* Jump becomes unconditional.  */
266018334Speter	return 1;
266118334Speter
266218334Speter      case LT:
266318334Speter      case LTU:
266418334Speter	/* Jump becomes no-op.  */
266518334Speter	return -1;
266618334Speter
266718334Speter      case LE:
266818334Speter      case LEU:
266918334Speter	PUT_CODE (cond, EQ);
267018334Speter	value = 2;
267118334Speter	break;
267218334Speter
267318334Speter      case GT:
267418334Speter      case GTU:
267518334Speter	PUT_CODE (cond, NE);
267618334Speter	value = 2;
267718334Speter	break;
267890087Sobrien
267950503Sobrien      default:
268050503Sobrien	break;
268118334Speter      }
268218334Speter
268318334Speter  if (cc_status.flags & CC_NO_OVERFLOW)
268418334Speter    switch (GET_CODE (cond))
268518334Speter      {
268618334Speter      case GEU:
268718334Speter	/* Jump becomes unconditional.  */
268818334Speter	return 1;
268918334Speter
269018334Speter      case LEU:
269118334Speter	PUT_CODE (cond, EQ);
269218334Speter	value = 2;
269318334Speter	break;
269418334Speter
269518334Speter      case GTU:
269618334Speter	PUT_CODE (cond, NE);
269718334Speter	value = 2;
269818334Speter	break;
269918334Speter
270018334Speter      case LTU:
270118334Speter	/* Jump becomes no-op.  */
270218334Speter	return -1;
270390087Sobrien
270450503Sobrien      default:
270550503Sobrien	break;
270618334Speter      }
270718334Speter
270818334Speter  if (cc_status.flags & (CC_Z_IN_NOT_N | CC_Z_IN_N))
270918334Speter    switch (GET_CODE (cond))
271018334Speter      {
271150503Sobrien      default:
271218334Speter	abort ();
271318334Speter
271418334Speter      case NE:
271518334Speter	PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? GE : LT);
271618334Speter	value = 2;
271718334Speter	break;
271818334Speter
271918334Speter      case EQ:
272018334Speter	PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? LT : GE);
272118334Speter	value = 2;
272218334Speter	break;
272318334Speter      }
272418334Speter
272518334Speter  if (cc_status.flags & CC_NOT_SIGNED)
272618334Speter    /* The flags are valid if signed condition operators are converted
272718334Speter       to unsigned.  */
272818334Speter    switch (GET_CODE (cond))
272918334Speter      {
273018334Speter      case LE:
273118334Speter	PUT_CODE (cond, LEU);
273218334Speter	value = 2;
273318334Speter	break;
273418334Speter
273518334Speter      case LT:
273618334Speter	PUT_CODE (cond, LTU);
273718334Speter	value = 2;
273818334Speter	break;
273918334Speter
274018334Speter      case GT:
274118334Speter	PUT_CODE (cond, GTU);
274218334Speter	value = 2;
274318334Speter	break;
274418334Speter
274518334Speter      case GE:
274618334Speter	PUT_CODE (cond, GEU);
274718334Speter	value = 2;
274818334Speter	break;
274950503Sobrien
275050503Sobrien      default:
275150503Sobrien	break;
275218334Speter      }
275318334Speter
275418334Speter  return value;
275518334Speter}
275618334Speter#endif
275718334Speter
275818334Speter/* Report inconsistency between the assembler template and the operands.
275918334Speter   In an `asm', it's the user's fault; otherwise, the compiler's fault.  */
276018334Speter
276118334Spetervoid
2762132727Skanoutput_operand_lossage (const char *msgid, ...)
276318334Speter{
276496281Sobrien  char *fmt_string;
276596281Sobrien  char *new_message;
276696281Sobrien  const char *pfx_str;
2767132727Skan  va_list ap;
276896281Sobrien
2769132727Skan  va_start (ap, msgid);
2770132727Skan
277196281Sobrien  pfx_str = this_is_asm_operands ? _("invalid `asm': ") : "output_operand: ";
277296281Sobrien  asprintf (&fmt_string, "%s%s", pfx_str, _(msgid));
277396281Sobrien  vasprintf (&new_message, fmt_string, ap);
2774117404Skan
277518334Speter  if (this_is_asm_operands)
277696281Sobrien    error_for_asm (this_is_asm_operands, "%s", new_message);
277718334Speter  else
277896281Sobrien    internal_error ("%s", new_message);
277996281Sobrien
278096281Sobrien  free (fmt_string);
278196281Sobrien  free (new_message);
2782132727Skan  va_end (ap);
278318334Speter}
278418334Speter
278518334Speter/* Output of assembler code from a template, and its subroutines.  */
278618334Speter
278790087Sobrien/* Annotate the assembly with a comment describing the pattern and
278890087Sobrien   alternative used.  */
278990087Sobrien
279090087Sobrienstatic void
2791132727Skanoutput_asm_name (void)
279290087Sobrien{
279390087Sobrien  if (debug_insn)
279490087Sobrien    {
279590087Sobrien      int num = INSN_CODE (debug_insn);
279690087Sobrien      fprintf (asm_out_file, "\t%s %d\t%s",
279790087Sobrien	       ASM_COMMENT_START, INSN_UID (debug_insn),
279890087Sobrien	       insn_data[num].name);
279990087Sobrien      if (insn_data[num].n_alternatives > 1)
280090087Sobrien	fprintf (asm_out_file, "/%d", which_alternative + 1);
280190087Sobrien#ifdef HAVE_ATTR_length
280290087Sobrien      fprintf (asm_out_file, "\t[length = %d]",
280390087Sobrien	       get_attr_length (debug_insn));
280490087Sobrien#endif
280590087Sobrien      /* Clear this so only the first assembler insn
280690087Sobrien	 of any rtl insn will get the special comment for -dp.  */
280790087Sobrien      debug_insn = 0;
280890087Sobrien    }
280990087Sobrien}
281090087Sobrien
281190087Sobrien/* If OP is a REG or MEM and we can find a MEM_EXPR corresponding to it
281290087Sobrien   or its address, return that expr .  Set *PADDRESSP to 1 if the expr
281390087Sobrien   corresponds to the address of the object and 0 if to the object.  */
281490087Sobrien
281590087Sobrienstatic tree
2816132727Skanget_mem_expr_from_op (rtx op, int *paddressp)
281790087Sobrien{
281890087Sobrien  tree expr;
281990087Sobrien  int inner_addressp;
282090087Sobrien
282190087Sobrien  *paddressp = 0;
282290087Sobrien
2823132727Skan  if (GET_CODE (op) == REG)
2824132727Skan    return REG_EXPR (op);
282590087Sobrien  else if (GET_CODE (op) != MEM)
282690087Sobrien    return 0;
282790087Sobrien
282890087Sobrien  if (MEM_EXPR (op) != 0)
282990087Sobrien    return MEM_EXPR (op);
283090087Sobrien
283190087Sobrien  /* Otherwise we have an address, so indicate it and look at the address.  */
283290087Sobrien  *paddressp = 1;
283390087Sobrien  op = XEXP (op, 0);
283490087Sobrien
283590087Sobrien  /* First check if we have a decl for the address, then look at the right side
283690087Sobrien     if it is a PLUS.  Otherwise, strip off arithmetic and keep looking.
283790087Sobrien     But don't allow the address to itself be indirect.  */
283890087Sobrien  if ((expr = get_mem_expr_from_op (op, &inner_addressp)) && ! inner_addressp)
283990087Sobrien    return expr;
284090087Sobrien  else if (GET_CODE (op) == PLUS
284190087Sobrien	   && (expr = get_mem_expr_from_op (XEXP (op, 1), &inner_addressp)))
284290087Sobrien    return expr;
284390087Sobrien
284490087Sobrien  while (GET_RTX_CLASS (GET_CODE (op)) == '1'
284590087Sobrien	 || GET_RTX_CLASS (GET_CODE (op)) == '2')
284690087Sobrien    op = XEXP (op, 0);
284790087Sobrien
284890087Sobrien  expr = get_mem_expr_from_op (op, &inner_addressp);
284990087Sobrien  return inner_addressp ? 0 : expr;
285090087Sobrien}
285190087Sobrien
285290087Sobrien/* Output operand names for assembler instructions.  OPERANDS is the
285390087Sobrien   operand vector, OPORDER is the order to write the operands, and NOPS
285490087Sobrien   is the number of operands to write.  */
285590087Sobrien
285690087Sobrienstatic void
2857132727Skanoutput_asm_operand_names (rtx *operands, int *oporder, int nops)
285890087Sobrien{
285990087Sobrien  int wrote = 0;
286090087Sobrien  int i;
286190087Sobrien
286290087Sobrien  for (i = 0; i < nops; i++)
286390087Sobrien    {
286490087Sobrien      int addressp;
2865132727Skan      rtx op = operands[oporder[i]];
2866132727Skan      tree expr = get_mem_expr_from_op (op, &addressp);
286790087Sobrien
2868132727Skan      fprintf (asm_out_file, "%c%s",
2869132727Skan	       wrote ? ',' : '\t', wrote ? "" : ASM_COMMENT_START);
2870132727Skan      wrote = 1;
287190087Sobrien      if (expr)
287290087Sobrien	{
2873132727Skan	  fprintf (asm_out_file, "%s",
287490087Sobrien		   addressp ? "*" : "");
287590087Sobrien	  print_mem_expr (asm_out_file, expr);
287690087Sobrien	  wrote = 1;
287790087Sobrien	}
2878132727Skan      else if (REG_P (op) && ORIGINAL_REGNO (op)
2879132727Skan	       && ORIGINAL_REGNO (op) != REGNO (op))
2880132727Skan	fprintf (asm_out_file, " tmp%i", ORIGINAL_REGNO (op));
288190087Sobrien    }
288290087Sobrien}
288390087Sobrien
288418334Speter/* Output text from TEMPLATE to the assembler output file,
288518334Speter   obeying %-directions to substitute operands taken from
288618334Speter   the vector OPERANDS.
288718334Speter
288818334Speter   %N (for N a digit) means print operand N in usual manner.
288918334Speter   %lN means require operand N to be a CODE_LABEL or LABEL_REF
289018334Speter      and print the label name with no punctuation.
289118334Speter   %cN means require operand N to be a constant
289218334Speter      and print the constant expression with no punctuation.
289318334Speter   %aN means expect operand N to be a memory address
289418334Speter      (not a memory reference!) and print a reference
289518334Speter      to that address.
289618334Speter   %nN means expect operand N to be a constant
289718334Speter      and print a constant expression for minus the value
289818334Speter      of the operand, with no other punctuation.  */
289918334Speter
290018334Spetervoid
2901132727Skanoutput_asm_insn (const char *template, rtx *operands)
290218334Speter{
290390087Sobrien  const char *p;
290490087Sobrien  int c;
290590087Sobrien#ifdef ASSEMBLER_DIALECT
290690087Sobrien  int dialect = 0;
290790087Sobrien#endif
290890087Sobrien  int oporder[MAX_RECOG_OPERANDS];
290990087Sobrien  char opoutput[MAX_RECOG_OPERANDS];
291090087Sobrien  int ops = 0;
291118334Speter
291218334Speter  /* An insn may return a null string template
291318334Speter     in a case where no assembler code is needed.  */
291418334Speter  if (*template == 0)
291518334Speter    return;
291618334Speter
291790087Sobrien  memset (opoutput, 0, sizeof opoutput);
291818334Speter  p = template;
291918334Speter  putc ('\t', asm_out_file);
292018334Speter
292118334Speter#ifdef ASM_OUTPUT_OPCODE
292218334Speter  ASM_OUTPUT_OPCODE (asm_out_file, p);
292318334Speter#endif
292418334Speter
292550503Sobrien  while ((c = *p++))
292618334Speter    switch (c)
292718334Speter      {
292818334Speter      case '\n':
292990087Sobrien	if (flag_verbose_asm)
293090087Sobrien	  output_asm_operand_names (operands, oporder, ops);
293190087Sobrien	if (flag_print_asm_name)
293290087Sobrien	  output_asm_name ();
293390087Sobrien
293490087Sobrien	ops = 0;
293590087Sobrien	memset (opoutput, 0, sizeof opoutput);
293690087Sobrien
293718334Speter	putc (c, asm_out_file);
293818334Speter#ifdef ASM_OUTPUT_OPCODE
293918334Speter	while ((c = *p) == '\t')
294018334Speter	  {
294118334Speter	    putc (c, asm_out_file);
294218334Speter	    p++;
294318334Speter	  }
294418334Speter	ASM_OUTPUT_OPCODE (asm_out_file, p);
294518334Speter#endif
294618334Speter	break;
294718334Speter
294818334Speter#ifdef ASSEMBLER_DIALECT
294918334Speter      case '{':
295050503Sobrien	{
295190087Sobrien	  int i;
295290087Sobrien
295390087Sobrien	  if (dialect)
295490087Sobrien	    output_operand_lossage ("nested assembly dialect alternatives");
295590087Sobrien	  else
295690087Sobrien	    dialect = 1;
295790087Sobrien
295850503Sobrien	  /* If we want the first dialect, do nothing.  Otherwise, skip
295950503Sobrien	     DIALECT_NUMBER of strings ending with '|'.  */
296050503Sobrien	  for (i = 0; i < dialect_number; i++)
296150503Sobrien	    {
296290087Sobrien	      while (*p && *p != '}' && *p++ != '|')
296350503Sobrien		;
296490087Sobrien	      if (*p == '}')
296590087Sobrien		break;
296650503Sobrien	      if (*p == '|')
296750503Sobrien		p++;
296850503Sobrien	    }
296990087Sobrien
297090087Sobrien	  if (*p == '\0')
297190087Sobrien	    output_operand_lossage ("unterminated assembly dialect alternative");
297250503Sobrien	}
297318334Speter	break;
297418334Speter
297518334Speter      case '|':
297690087Sobrien	if (dialect)
297790087Sobrien	  {
297890087Sobrien	    /* Skip to close brace.  */
297990087Sobrien	    do
298090087Sobrien	      {
298190087Sobrien		if (*p == '\0')
298290087Sobrien		  {
298390087Sobrien		    output_operand_lossage ("unterminated assembly dialect alternative");
298490087Sobrien		    break;
298590087Sobrien		  }
298690087Sobrien	      }
298790087Sobrien	    while (*p++ != '}');
298890087Sobrien	    dialect = 0;
298990087Sobrien	  }
299090087Sobrien	else
299190087Sobrien	  putc (c, asm_out_file);
299218334Speter	break;
299318334Speter
299418334Speter      case '}':
299590087Sobrien	if (! dialect)
299690087Sobrien	  putc (c, asm_out_file);
299790087Sobrien	dialect = 0;
299818334Speter	break;
299918334Speter#endif
300018334Speter
300118334Speter      case '%':
300218334Speter	/* %% outputs a single %.  */
300318334Speter	if (*p == '%')
300418334Speter	  {
300518334Speter	    p++;
300618334Speter	    putc (c, asm_out_file);
300718334Speter	  }
300818334Speter	/* %= outputs a number which is unique to each insn in the entire
300918334Speter	   compilation.  This is useful for making local labels that are
301018334Speter	   referred to more than once in a given insn.  */
301118334Speter	else if (*p == '=')
301218334Speter	  {
301318334Speter	    p++;
301418334Speter	    fprintf (asm_out_file, "%d", insn_counter);
301518334Speter	  }
301618334Speter	/* % followed by a letter and some digits
301718334Speter	   outputs an operand in a special way depending on the letter.
301818334Speter	   Letters `acln' are implemented directly.
301918334Speter	   Other letters are passed to `output_operand' so that
302018334Speter	   the PRINT_OPERAND macro can define them.  */
302190087Sobrien	else if (ISALPHA (*p))
302218334Speter	  {
302318334Speter	    int letter = *p++;
302418334Speter	    c = atoi (p);
302518334Speter
302690087Sobrien	    if (! ISDIGIT (*p))
302796281Sobrien	      output_operand_lossage ("operand number missing after %%-letter");
302890087Sobrien	    else if (this_is_asm_operands
302990087Sobrien		     && (c < 0 || (unsigned int) c >= insn_noperands))
303018334Speter	      output_operand_lossage ("operand number out of range");
303118334Speter	    else if (letter == 'l')
303218334Speter	      output_asm_label (operands[c]);
303318334Speter	    else if (letter == 'a')
303418334Speter	      output_address (operands[c]);
303518334Speter	    else if (letter == 'c')
303618334Speter	      {
303718334Speter		if (CONSTANT_ADDRESS_P (operands[c]))
303818334Speter		  output_addr_const (asm_out_file, operands[c]);
303918334Speter		else
304018334Speter		  output_operand (operands[c], 'c');
304118334Speter	      }
304218334Speter	    else if (letter == 'n')
304318334Speter	      {
304418334Speter		if (GET_CODE (operands[c]) == CONST_INT)
304550503Sobrien		  fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC,
304618334Speter			   - INTVAL (operands[c]));
304718334Speter		else
304818334Speter		  {
304918334Speter		    putc ('-', asm_out_file);
305018334Speter		    output_addr_const (asm_out_file, operands[c]);
305118334Speter		  }
305218334Speter	      }
305318334Speter	    else
305418334Speter	      output_operand (operands[c], letter);
305590087Sobrien
305690087Sobrien	    if (!opoutput[c])
305790087Sobrien	      oporder[ops++] = c;
305890087Sobrien	    opoutput[c] = 1;
305990087Sobrien
306090087Sobrien	    while (ISDIGIT (c = *p))
306190087Sobrien	      p++;
306218334Speter	  }
306318334Speter	/* % followed by a digit outputs an operand the default way.  */
306490087Sobrien	else if (ISDIGIT (*p))
306518334Speter	  {
306618334Speter	    c = atoi (p);
306790087Sobrien	    if (this_is_asm_operands
306890087Sobrien		&& (c < 0 || (unsigned int) c >= insn_noperands))
306918334Speter	      output_operand_lossage ("operand number out of range");
307018334Speter	    else
307118334Speter	      output_operand (operands[c], 0);
307290087Sobrien
307390087Sobrien	    if (!opoutput[c])
307490087Sobrien	      oporder[ops++] = c;
307590087Sobrien	    opoutput[c] = 1;
307690087Sobrien
307790087Sobrien	    while (ISDIGIT (c = *p))
307890087Sobrien	      p++;
307918334Speter	  }
308018334Speter	/* % followed by punctuation: output something for that
308118334Speter	   punctuation character alone, with no operand.
308218334Speter	   The PRINT_OPERAND macro decides what is actually done.  */
308318334Speter#ifdef PRINT_OPERAND_PUNCT_VALID_P
308490087Sobrien	else if (PRINT_OPERAND_PUNCT_VALID_P ((unsigned char) *p))
308518334Speter	  output_operand (NULL_RTX, *p++);
308618334Speter#endif
308718334Speter	else
308818334Speter	  output_operand_lossage ("invalid %%-code");
308918334Speter	break;
309018334Speter
309118334Speter      default:
309218334Speter	putc (c, asm_out_file);
309318334Speter      }
309418334Speter
309590087Sobrien  /* Write out the variable names for operands, if we know them.  */
309690087Sobrien  if (flag_verbose_asm)
309790087Sobrien    output_asm_operand_names (operands, oporder, ops);
309890087Sobrien  if (flag_print_asm_name)
309990087Sobrien    output_asm_name ();
310018334Speter
310118334Speter  putc ('\n', asm_out_file);
310218334Speter}
310318334Speter
310418334Speter/* Output a LABEL_REF, or a bare CODE_LABEL, as an assembler symbol.  */
310518334Speter
310618334Spetervoid
3107132727Skanoutput_asm_label (rtx x)
310818334Speter{
310918334Speter  char buf[256];
311018334Speter
311118334Speter  if (GET_CODE (x) == LABEL_REF)
311290087Sobrien    x = XEXP (x, 0);
311390087Sobrien  if (GET_CODE (x) == CODE_LABEL
311490087Sobrien      || (GET_CODE (x) == NOTE
311590087Sobrien	  && NOTE_LINE_NUMBER (x) == NOTE_INSN_DELETED_LABEL))
311618334Speter    ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
311718334Speter  else
311896281Sobrien    output_operand_lossage ("`%%l' operand isn't a label");
311918334Speter
312018334Speter  assemble_name (asm_out_file, buf);
312118334Speter}
312218334Speter
312318334Speter/* Print operand X using machine-dependent assembler syntax.
312418334Speter   The macro PRINT_OPERAND is defined just to control this function.
312518334Speter   CODE is a non-digit that preceded the operand-number in the % spec,
312618334Speter   such as 'z' if the spec was `%z3'.  CODE is 0 if there was no char
312718334Speter   between the % and the digits.
312818334Speter   When CODE is a non-letter, X is 0.
312918334Speter
313018334Speter   The meanings of the letters are machine-dependent and controlled
313118334Speter   by PRINT_OPERAND.  */
313218334Speter
313318334Speterstatic void
3134132727Skanoutput_operand (rtx x, int code ATTRIBUTE_UNUSED)
313518334Speter{
313618334Speter  if (x && GET_CODE (x) == SUBREG)
313790087Sobrien    x = alter_subreg (&x);
313818334Speter
313918334Speter  /* If X is a pseudo-register, abort now rather than writing trash to the
314018334Speter     assembler file.  */
314118334Speter
314218334Speter  if (x && GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER)
314318334Speter    abort ();
314418334Speter
314518334Speter  PRINT_OPERAND (asm_out_file, x, code);
314618334Speter}
314718334Speter
314818334Speter/* Print a memory reference operand for address X
314918334Speter   using machine-dependent assembler syntax.
315018334Speter   The macro PRINT_OPERAND_ADDRESS exists just to control this function.  */
315118334Speter
315218334Spetervoid
3153132727Skanoutput_address (rtx x)
315418334Speter{
315590087Sobrien  walk_alter_subreg (&x);
315618334Speter  PRINT_OPERAND_ADDRESS (asm_out_file, x);
315718334Speter}
315818334Speter
315918334Speter/* Print an integer constant expression in assembler syntax.
316018334Speter   Addition and subtraction are the only arithmetic
316118334Speter   that may appear in these expressions.  */
316218334Speter
316318334Spetervoid
3164132727Skanoutput_addr_const (FILE *file, rtx x)
316518334Speter{
316618334Speter  char buf[256];
316718334Speter
316818334Speter restart:
316918334Speter  switch (GET_CODE (x))
317018334Speter    {
317118334Speter    case PC:
317290087Sobrien      putc ('.', file);
317318334Speter      break;
317418334Speter
317518334Speter    case SYMBOL_REF:
317690087Sobrien#ifdef ASM_OUTPUT_SYMBOL_REF
317790087Sobrien      ASM_OUTPUT_SYMBOL_REF (file, x);
317890087Sobrien#else
317918334Speter      assemble_name (file, XSTR (x, 0));
318090087Sobrien#endif
318118334Speter      break;
318218334Speter
318318334Speter    case LABEL_REF:
318490087Sobrien      x = XEXP (x, 0);
318590087Sobrien      /* Fall through.  */
318618334Speter    case CODE_LABEL:
318718334Speter      ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
318890087Sobrien#ifdef ASM_OUTPUT_LABEL_REF
318990087Sobrien      ASM_OUTPUT_LABEL_REF (file, buf);
319090087Sobrien#else
319118334Speter      assemble_name (file, buf);
319290087Sobrien#endif
319318334Speter      break;
319418334Speter
319518334Speter    case CONST_INT:
319650503Sobrien      fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
319718334Speter      break;
319818334Speter
319918334Speter    case CONST:
320018334Speter      /* This used to output parentheses around the expression,
320118334Speter	 but that does not work on the 386 (either ATT or BSD assembler).  */
320218334Speter      output_addr_const (file, XEXP (x, 0));
320318334Speter      break;
320418334Speter
320518334Speter    case CONST_DOUBLE:
320618334Speter      if (GET_MODE (x) == VOIDmode)
320718334Speter	{
320818334Speter	  /* We can use %d if the number is one word and positive.  */
320918334Speter	  if (CONST_DOUBLE_HIGH (x))
321050503Sobrien	    fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
321118334Speter		     CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x));
321290087Sobrien	  else if (CONST_DOUBLE_LOW (x) < 0)
321350503Sobrien	    fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (x));
321418334Speter	  else
321550503Sobrien	    fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x));
321618334Speter	}
321718334Speter      else
321818334Speter	/* We can't handle floating point constants;
321918334Speter	   PRINT_OPERAND must handle them.  */
322018334Speter	output_operand_lossage ("floating constant misused");
322118334Speter      break;
322218334Speter
322318334Speter    case PLUS:
322418334Speter      /* Some assemblers need integer constants to appear last (eg masm).  */
322518334Speter      if (GET_CODE (XEXP (x, 0)) == CONST_INT)
322618334Speter	{
322718334Speter	  output_addr_const (file, XEXP (x, 1));
322818334Speter	  if (INTVAL (XEXP (x, 0)) >= 0)
322918334Speter	    fprintf (file, "+");
323018334Speter	  output_addr_const (file, XEXP (x, 0));
323118334Speter	}
323218334Speter      else
323318334Speter	{
323418334Speter	  output_addr_const (file, XEXP (x, 0));
323590087Sobrien	  if (GET_CODE (XEXP (x, 1)) != CONST_INT
323690087Sobrien	      || INTVAL (XEXP (x, 1)) >= 0)
323718334Speter	    fprintf (file, "+");
323818334Speter	  output_addr_const (file, XEXP (x, 1));
323918334Speter	}
324018334Speter      break;
324118334Speter
324218334Speter    case MINUS:
324318334Speter      /* Avoid outputting things like x-x or x+5-x,
324418334Speter	 since some assemblers can't handle that.  */
324518334Speter      x = simplify_subtraction (x);
324618334Speter      if (GET_CODE (x) != MINUS)
324718334Speter	goto restart;
324818334Speter
324918334Speter      output_addr_const (file, XEXP (x, 0));
325018334Speter      fprintf (file, "-");
325190087Sobrien      if ((GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) >= 0)
325290087Sobrien	  || GET_CODE (XEXP (x, 1)) == PC
325390087Sobrien	  || GET_CODE (XEXP (x, 1)) == SYMBOL_REF)
325490087Sobrien	output_addr_const (file, XEXP (x, 1));
325590087Sobrien      else
325618334Speter	{
325790087Sobrien	  fputs (targetm.asm_out.open_paren, file);
325818334Speter	  output_addr_const (file, XEXP (x, 1));
325990087Sobrien	  fputs (targetm.asm_out.close_paren, file);
326018334Speter	}
326118334Speter      break;
326218334Speter
326318334Speter    case ZERO_EXTEND:
326418334Speter    case SIGN_EXTEND:
326596281Sobrien    case SUBREG:
326618334Speter      output_addr_const (file, XEXP (x, 0));
326718334Speter      break;
326818334Speter
326918334Speter    default:
327090087Sobrien#ifdef OUTPUT_ADDR_CONST_EXTRA
327190087Sobrien      OUTPUT_ADDR_CONST_EXTRA (file, x, fail);
327290087Sobrien      break;
327390087Sobrien
327490087Sobrien    fail:
327590087Sobrien#endif
327618334Speter      output_operand_lossage ("invalid expression as operand");
327718334Speter    }
327818334Speter}
327918334Speter
328018334Speter/* A poor man's fprintf, with the added features of %I, %R, %L, and %U.
328118334Speter   %R prints the value of REGISTER_PREFIX.
328218334Speter   %L prints the value of LOCAL_LABEL_PREFIX.
328318334Speter   %U prints the value of USER_LABEL_PREFIX.
328418334Speter   %I prints the value of IMMEDIATE_PREFIX.
328518334Speter   %O runs ASM_OUTPUT_OPCODE to transform what follows in the string.
3286132727Skan   Also supported are %d, %i, %u, %x, %X, %o, %c, %s and %%.
328718334Speter
328818334Speter   We handle alternate assembler dialects here, just like output_asm_insn.  */
328918334Speter
329018334Spetervoid
3291132727Skanasm_fprintf (FILE *file, const char *p, ...)
329218334Speter{
329318334Speter  char buf[10];
329418334Speter  char *q, c;
3295132727Skan  va_list argptr;
329618334Speter
3297132727Skan  va_start (argptr, p);
329818334Speter
329918334Speter  buf[0] = '%';
330018334Speter
330150503Sobrien  while ((c = *p++))
330218334Speter    switch (c)
330318334Speter      {
330418334Speter#ifdef ASSEMBLER_DIALECT
330518334Speter      case '{':
330650503Sobrien	{
330750503Sobrien	  int i;
330818334Speter
330950503Sobrien	  /* If we want the first dialect, do nothing.  Otherwise, skip
331050503Sobrien	     DIALECT_NUMBER of strings ending with '|'.  */
331150503Sobrien	  for (i = 0; i < dialect_number; i++)
331250503Sobrien	    {
331350503Sobrien	      while (*p && *p++ != '|')
331450503Sobrien		;
331550503Sobrien
331650503Sobrien	      if (*p == '|')
331750503Sobrien		p++;
331890087Sobrien	    }
331950503Sobrien	}
332018334Speter	break;
332118334Speter
332218334Speter      case '|':
332318334Speter	/* Skip to close brace.  */
332418334Speter	while (*p && *p++ != '}')
332518334Speter	  ;
332618334Speter	break;
332718334Speter
332818334Speter      case '}':
332918334Speter	break;
333018334Speter#endif
333118334Speter
333218334Speter      case '%':
333318334Speter	c = *p++;
333418334Speter	q = &buf[1];
3335132727Skan	while (strchr ("-+ #0", c))
3336132727Skan	  {
3337132727Skan	    *q++ = c;
3338132727Skan	    c = *p++;
3339132727Skan	  }
334090087Sobrien	while (ISDIGIT (c) || c == '.')
334118334Speter	  {
334218334Speter	    *q++ = c;
334318334Speter	    c = *p++;
334418334Speter	  }
334518334Speter	switch (c)
334618334Speter	  {
334718334Speter	  case '%':
3348132727Skan	    putc ('%', file);
334918334Speter	    break;
335018334Speter
335118334Speter	  case 'd':  case 'i':  case 'u':
3352132727Skan	  case 'x':  case 'X':  case 'o':
3353132727Skan	  case 'c':
335418334Speter	    *q++ = c;
335518334Speter	    *q = 0;
335618334Speter	    fprintf (file, buf, va_arg (argptr, int));
335718334Speter	    break;
335818334Speter
335918334Speter	  case 'w':
3360132727Skan	    /* This is a prefix to the 'd', 'i', 'u', 'x', 'X', and
3361132727Skan	       'o' cases, but we do not check for those cases.  It
3362132727Skan	       means that the value is a HOST_WIDE_INT, which may be
3363132727Skan	       either `long' or `long long'.  */
3364132727Skan	    memcpy (q, HOST_WIDE_INT_PRINT, strlen (HOST_WIDE_INT_PRINT));
3365132727Skan	    q += strlen (HOST_WIDE_INT_PRINT);
336618334Speter	    *q++ = *p++;
336718334Speter	    *q = 0;
336818334Speter	    fprintf (file, buf, va_arg (argptr, HOST_WIDE_INT));
336918334Speter	    break;
337018334Speter
337118334Speter	  case 'l':
337218334Speter	    *q++ = c;
3373132727Skan#ifdef HAVE_LONG_LONG
3374132727Skan	    if (*p == 'l')
3375132727Skan	      {
3376132727Skan		*q++ = *p++;
3377132727Skan		*q++ = *p++;
3378132727Skan		*q = 0;
3379132727Skan		fprintf (file, buf, va_arg (argptr, long long));
3380132727Skan	      }
3381132727Skan	    else
3382132727Skan#endif
3383132727Skan	      {
3384132727Skan		*q++ = *p++;
3385132727Skan		*q = 0;
3386132727Skan		fprintf (file, buf, va_arg (argptr, long));
3387132727Skan	      }
338818334Speter
338918334Speter	    break;
339018334Speter
339118334Speter	  case 's':
339218334Speter	    *q++ = c;
339318334Speter	    *q = 0;
339418334Speter	    fprintf (file, buf, va_arg (argptr, char *));
339518334Speter	    break;
339618334Speter
339718334Speter	  case 'O':
339818334Speter#ifdef ASM_OUTPUT_OPCODE
339918334Speter	    ASM_OUTPUT_OPCODE (asm_out_file, p);
340018334Speter#endif
340118334Speter	    break;
340218334Speter
340318334Speter	  case 'R':
340418334Speter#ifdef REGISTER_PREFIX
340518334Speter	    fprintf (file, "%s", REGISTER_PREFIX);
340618334Speter#endif
340718334Speter	    break;
340818334Speter
340918334Speter	  case 'I':
341018334Speter#ifdef IMMEDIATE_PREFIX
341118334Speter	    fprintf (file, "%s", IMMEDIATE_PREFIX);
341218334Speter#endif
341318334Speter	    break;
341418334Speter
341518334Speter	  case 'L':
341618334Speter#ifdef LOCAL_LABEL_PREFIX
341718334Speter	    fprintf (file, "%s", LOCAL_LABEL_PREFIX);
341818334Speter#endif
341918334Speter	    break;
342018334Speter
342118334Speter	  case 'U':
342252515Sobrien	    fputs (user_label_prefix, file);
342318334Speter	    break;
342418334Speter
342590087Sobrien#ifdef ASM_FPRINTF_EXTENSIONS
3426132727Skan	    /* Uppercase letters are reserved for general use by asm_fprintf
342790087Sobrien	       and so are not available to target specific code.  In order to
342890087Sobrien	       prevent the ASM_FPRINTF_EXTENSIONS macro from using them then,
342990087Sobrien	       they are defined here.  As they get turned into real extensions
343090087Sobrien	       to asm_fprintf they should be removed from this list.  */
343190087Sobrien	  case 'A': case 'B': case 'C': case 'D': case 'E':
343290087Sobrien	  case 'F': case 'G': case 'H': case 'J': case 'K':
343390087Sobrien	  case 'M': case 'N': case 'P': case 'Q': case 'S':
343490087Sobrien	  case 'T': case 'V': case 'W': case 'Y': case 'Z':
343590087Sobrien	    break;
343690087Sobrien
343790087Sobrien	  ASM_FPRINTF_EXTENSIONS (file, argptr, p)
343890087Sobrien#endif
343918334Speter	  default:
344018334Speter	    abort ();
344118334Speter	  }
344218334Speter	break;
344318334Speter
344418334Speter      default:
3445132727Skan	putc (c, file);
344618334Speter      }
3447132727Skan  va_end (argptr);
344818334Speter}
344918334Speter
345018334Speter/* Split up a CONST_DOUBLE or integer constant rtx
345118334Speter   into two rtx's for single words,
345218334Speter   storing in *FIRST the word that comes first in memory in the target
345318334Speter   and in *SECOND the other.  */
345418334Speter
345518334Spetervoid
3456132727Skansplit_double (rtx value, rtx *first, rtx *second)
345718334Speter{
345818334Speter  if (GET_CODE (value) == CONST_INT)
345918334Speter    {
346018334Speter      if (HOST_BITS_PER_WIDE_INT >= (2 * BITS_PER_WORD))
346118334Speter	{
346218334Speter	  /* In this case the CONST_INT holds both target words.
346350503Sobrien	     Extract the bits from it into two word-sized pieces.
346450503Sobrien	     Sign extend each half to HOST_WIDE_INT.  */
346590087Sobrien	  unsigned HOST_WIDE_INT low, high;
346690087Sobrien	  unsigned HOST_WIDE_INT mask, sign_bit, sign_extend;
346718334Speter
346890087Sobrien	  /* Set sign_bit to the most significant bit of a word.  */
346990087Sobrien	  sign_bit = 1;
347090087Sobrien	  sign_bit <<= BITS_PER_WORD - 1;
347190087Sobrien
347290087Sobrien	  /* Set mask so that all bits of the word are set.  We could
347390087Sobrien	     have used 1 << BITS_PER_WORD instead of basing the
347490087Sobrien	     calculation on sign_bit.  However, on machines where
347590087Sobrien	     HOST_BITS_PER_WIDE_INT == BITS_PER_WORD, it could cause a
347690087Sobrien	     compiler warning, even though the code would never be
347790087Sobrien	     executed.  */
347890087Sobrien	  mask = sign_bit << 1;
347990087Sobrien	  mask--;
348090087Sobrien
348190087Sobrien	  /* Set sign_extend as any remaining bits.  */
348290087Sobrien	  sign_extend = ~mask;
348390087Sobrien
348490087Sobrien	  /* Pick the lower word and sign-extend it.  */
348590087Sobrien	  low = INTVAL (value);
348690087Sobrien	  low &= mask;
348790087Sobrien	  if (low & sign_bit)
348890087Sobrien	    low |= sign_extend;
348990087Sobrien
349090087Sobrien	  /* Pick the higher word, shifted to the least significant
349190087Sobrien	     bits, and sign-extend it.  */
349290087Sobrien	  high = INTVAL (value);
349390087Sobrien	  high >>= BITS_PER_WORD - 1;
349490087Sobrien	  high >>= 1;
349590087Sobrien	  high &= mask;
349690087Sobrien	  if (high & sign_bit)
349790087Sobrien	    high |= sign_extend;
349890087Sobrien
349990087Sobrien	  /* Store the words in the target machine order.  */
350018334Speter	  if (WORDS_BIG_ENDIAN)
350118334Speter	    {
350290087Sobrien	      *first = GEN_INT (high);
350390087Sobrien	      *second = GEN_INT (low);
350418334Speter	    }
350518334Speter	  else
350618334Speter	    {
350790087Sobrien	      *first = GEN_INT (low);
350890087Sobrien	      *second = GEN_INT (high);
350918334Speter	    }
351018334Speter	}
351118334Speter      else
351218334Speter	{
351318334Speter	  /* The rule for using CONST_INT for a wider mode
351418334Speter	     is that we regard the value as signed.
351518334Speter	     So sign-extend it.  */
351618334Speter	  rtx high = (INTVAL (value) < 0 ? constm1_rtx : const0_rtx);
351718334Speter	  if (WORDS_BIG_ENDIAN)
351818334Speter	    {
351918334Speter	      *first = high;
352018334Speter	      *second = value;
352118334Speter	    }
352218334Speter	  else
352318334Speter	    {
352418334Speter	      *first = value;
352518334Speter	      *second = high;
352618334Speter	    }
352718334Speter	}
352818334Speter    }
352918334Speter  else if (GET_CODE (value) != CONST_DOUBLE)
353018334Speter    {
353118334Speter      if (WORDS_BIG_ENDIAN)
353218334Speter	{
353318334Speter	  *first = const0_rtx;
353418334Speter	  *second = value;
353518334Speter	}
353618334Speter      else
353718334Speter	{
353818334Speter	  *first = value;
353918334Speter	  *second = const0_rtx;
354018334Speter	}
354118334Speter    }
354218334Speter  else if (GET_MODE (value) == VOIDmode
354318334Speter	   /* This is the old way we did CONST_DOUBLE integers.  */
354418334Speter	   || GET_MODE_CLASS (GET_MODE (value)) == MODE_INT)
354518334Speter    {
354618334Speter      /* In an integer, the words are defined as most and least significant.
354718334Speter	 So order them by the target's convention.  */
354818334Speter      if (WORDS_BIG_ENDIAN)
354918334Speter	{
355018334Speter	  *first = GEN_INT (CONST_DOUBLE_HIGH (value));
355118334Speter	  *second = GEN_INT (CONST_DOUBLE_LOW (value));
355218334Speter	}
355318334Speter      else
355418334Speter	{
355518334Speter	  *first = GEN_INT (CONST_DOUBLE_LOW (value));
355618334Speter	  *second = GEN_INT (CONST_DOUBLE_HIGH (value));
355718334Speter	}
355818334Speter    }
355918334Speter  else
356018334Speter    {
356190087Sobrien      REAL_VALUE_TYPE r;
356290087Sobrien      long l[2];
356318334Speter      REAL_VALUE_FROM_CONST_DOUBLE (r, value);
356418334Speter
356518334Speter      /* Note, this converts the REAL_VALUE_TYPE to the target's
356618334Speter	 format, splits up the floating point double and outputs
356718334Speter	 exactly 32 bits of it into each of l[0] and l[1] --
356850503Sobrien	 not necessarily BITS_PER_WORD bits.  */
356918334Speter      REAL_VALUE_TO_TARGET_DOUBLE (r, l);
357018334Speter
357152515Sobrien      /* If 32 bits is an entire word for the target, but not for the host,
357252515Sobrien	 then sign-extend on the host so that the number will look the same
357352515Sobrien	 way on the host that it would on the target.  See for instance
357452515Sobrien	 simplify_unary_operation.  The #if is needed to avoid compiler
357552515Sobrien	 warnings.  */
357652515Sobrien
357752515Sobrien#if HOST_BITS_PER_LONG > 32
357852515Sobrien      if (BITS_PER_WORD < HOST_BITS_PER_LONG && BITS_PER_WORD == 32)
357952515Sobrien	{
358052515Sobrien	  if (l[0] & ((long) 1 << 31))
358152515Sobrien	    l[0] |= ((long) (-1) << 32);
358252515Sobrien	  if (l[1] & ((long) 1 << 31))
358352515Sobrien	    l[1] |= ((long) (-1) << 32);
358452515Sobrien	}
358552515Sobrien#endif
358652515Sobrien
358718334Speter      *first = GEN_INT ((HOST_WIDE_INT) l[0]);
358818334Speter      *second = GEN_INT ((HOST_WIDE_INT) l[1]);
358918334Speter    }
359018334Speter}
359118334Speter
359218334Speter/* Return nonzero if this function has no function calls.  */
359318334Speter
359418334Speterint
3595132727Skanleaf_function_p (void)
359618334Speter{
359718334Speter  rtx insn;
359890087Sobrien  rtx link;
359918334Speter
360090087Sobrien  if (current_function_profile || profile_arc_flag)
360118334Speter    return 0;
360218334Speter
360318334Speter  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
360418334Speter    {
360590087Sobrien      if (GET_CODE (insn) == CALL_INSN
360690087Sobrien	  && ! SIBLING_CALL_P (insn))
360718334Speter	return 0;
360818334Speter      if (GET_CODE (insn) == INSN
360918334Speter	  && GET_CODE (PATTERN (insn)) == SEQUENCE
361090087Sobrien	  && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN
361190087Sobrien	  && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0)))
361218334Speter	return 0;
361318334Speter    }
361490087Sobrien  for (link = current_function_epilogue_delay_list;
361590087Sobrien       link;
361690087Sobrien       link = XEXP (link, 1))
361718334Speter    {
361890087Sobrien      insn = XEXP (link, 0);
361990087Sobrien
362090087Sobrien      if (GET_CODE (insn) == CALL_INSN
362190087Sobrien	  && ! SIBLING_CALL_P (insn))
362218334Speter	return 0;
362390087Sobrien      if (GET_CODE (insn) == INSN
362490087Sobrien	  && GET_CODE (PATTERN (insn)) == SEQUENCE
362590087Sobrien	  && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN
362690087Sobrien	  && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0)))
362718334Speter	return 0;
362818334Speter    }
362918334Speter
363018334Speter  return 1;
363118334Speter}
363218334Speter
3633117404Skan/* Return 1 if branch is a forward branch.
363490087Sobrien   Uses insn_shuid array, so it works only in the final pass.  May be used by
363590087Sobrien   output templates to customary add branch prediction hints.
363690087Sobrien */
363790087Sobrienint
3638132727Skanfinal_forward_branch_p (rtx insn)
363990087Sobrien{
364090087Sobrien  int insn_id, label_id;
364190087Sobrien  if (!uid_shuid)
364290087Sobrien    abort ();
364390087Sobrien  insn_id = INSN_SHUID (insn);
364490087Sobrien  label_id = INSN_SHUID (JUMP_LABEL (insn));
364590087Sobrien  /* We've hit some insns that does not have id information available.  */
364690087Sobrien  if (!insn_id || !label_id)
364790087Sobrien    abort ();
364890087Sobrien  return insn_id < label_id;
364990087Sobrien}
365090087Sobrien
365118334Speter/* On some machines, a function with no call insns
365218334Speter   can run faster if it doesn't create its own register window.
365318334Speter   When output, the leaf function should use only the "output"
365418334Speter   registers.  Ordinarily, the function would be compiled to use
365518334Speter   the "input" registers to find its arguments; it is a candidate
365618334Speter   for leaf treatment if it uses only the "input" registers.
365718334Speter   Leaf function treatment means renumbering so the function
365818334Speter   uses the "output" registers instead.  */
365918334Speter
366018334Speter#ifdef LEAF_REGISTERS
366118334Speter
366218334Speter/* Return 1 if this function uses only the registers that can be
366318334Speter   safely renumbered.  */
366418334Speter
366518334Speterint
3666132727Skanonly_leaf_regs_used (void)
366718334Speter{
366818334Speter  int i;
3669132727Skan  const char *const permitted_reg_in_leaf_functions = LEAF_REGISTERS;
367018334Speter
367118334Speter  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
367250503Sobrien    if ((regs_ever_live[i] || global_regs[i])
367350503Sobrien	&& ! permitted_reg_in_leaf_functions[i])
367450503Sobrien      return 0;
367550503Sobrien
367650503Sobrien  if (current_function_uses_pic_offset_table
367750503Sobrien      && pic_offset_table_rtx != 0
367850503Sobrien      && GET_CODE (pic_offset_table_rtx) == REG
367950503Sobrien      && ! permitted_reg_in_leaf_functions[REGNO (pic_offset_table_rtx)])
368050503Sobrien    return 0;
368150503Sobrien
368218334Speter  return 1;
368318334Speter}
368418334Speter
368518334Speter/* Scan all instructions and renumber all registers into those
368618334Speter   available in leaf functions.  */
368718334Speter
368818334Speterstatic void
3689132727Skanleaf_renumber_regs (rtx first)
369018334Speter{
369118334Speter  rtx insn;
369218334Speter
369318334Speter  /* Renumber only the actual patterns.
369418334Speter     The reg-notes can contain frame pointer refs,
369518334Speter     and renumbering them could crash, and should not be needed.  */
369618334Speter  for (insn = first; insn; insn = NEXT_INSN (insn))
369790087Sobrien    if (INSN_P (insn))
369818334Speter      leaf_renumber_regs_insn (PATTERN (insn));
369990087Sobrien  for (insn = current_function_epilogue_delay_list;
370090087Sobrien       insn;
370190087Sobrien       insn = XEXP (insn, 1))
370290087Sobrien    if (INSN_P (XEXP (insn, 0)))
370318334Speter      leaf_renumber_regs_insn (PATTERN (XEXP (insn, 0)));
370418334Speter}
370518334Speter
370618334Speter/* Scan IN_RTX and its subexpressions, and renumber all regs into those
370718334Speter   available in leaf functions.  */
370818334Speter
370918334Spetervoid
3710132727Skanleaf_renumber_regs_insn (rtx in_rtx)
371118334Speter{
371290087Sobrien  int i, j;
371390087Sobrien  const char *format_ptr;
371418334Speter
371518334Speter  if (in_rtx == 0)
371618334Speter    return;
371718334Speter
371818334Speter  /* Renumber all input-registers into output-registers.
371918334Speter     renumbered_regs would be 1 for an output-register;
372018334Speter     they  */
372118334Speter
372218334Speter  if (GET_CODE (in_rtx) == REG)
372318334Speter    {
372418334Speter      int newreg;
372518334Speter
372618334Speter      /* Don't renumber the same reg twice.  */
372718334Speter      if (in_rtx->used)
372818334Speter	return;
372918334Speter
373018334Speter      newreg = REGNO (in_rtx);
373118334Speter      /* Don't try to renumber pseudo regs.  It is possible for a pseudo reg
373218334Speter	 to reach here as part of a REG_NOTE.  */
373318334Speter      if (newreg >= FIRST_PSEUDO_REGISTER)
373418334Speter	{
373518334Speter	  in_rtx->used = 1;
373618334Speter	  return;
373718334Speter	}
373818334Speter      newreg = LEAF_REG_REMAP (newreg);
373918334Speter      if (newreg < 0)
374018334Speter	abort ();
374118334Speter      regs_ever_live[REGNO (in_rtx)] = 0;
374218334Speter      regs_ever_live[newreg] = 1;
374318334Speter      REGNO (in_rtx) = newreg;
374418334Speter      in_rtx->used = 1;
374518334Speter    }
374618334Speter
374790087Sobrien  if (INSN_P (in_rtx))
374818334Speter    {
374918334Speter      /* Inside a SEQUENCE, we find insns.
375018334Speter	 Renumber just the patterns of these insns,
375118334Speter	 just as we do for the top-level insns.  */
375218334Speter      leaf_renumber_regs_insn (PATTERN (in_rtx));
375318334Speter      return;
375418334Speter    }
375518334Speter
375618334Speter  format_ptr = GET_RTX_FORMAT (GET_CODE (in_rtx));
375718334Speter
375818334Speter  for (i = 0; i < GET_RTX_LENGTH (GET_CODE (in_rtx)); i++)
375918334Speter    switch (*format_ptr++)
376018334Speter      {
376118334Speter      case 'e':
376218334Speter	leaf_renumber_regs_insn (XEXP (in_rtx, i));
376318334Speter	break;
376418334Speter
376518334Speter      case 'E':
376618334Speter	if (NULL != XVEC (in_rtx, i))
376718334Speter	  {
376818334Speter	    for (j = 0; j < XVECLEN (in_rtx, i); j++)
376918334Speter	      leaf_renumber_regs_insn (XVECEXP (in_rtx, i, j));
377018334Speter	  }
377118334Speter	break;
377218334Speter
377318334Speter      case 'S':
377418334Speter      case 's':
377518334Speter      case '0':
377618334Speter      case 'i':
377718334Speter      case 'w':
377818334Speter      case 'n':
377918334Speter      case 'u':
378018334Speter	break;
378118334Speter
378218334Speter      default:
378318334Speter	abort ();
378418334Speter      }
378518334Speter}
378618334Speter#endif
3787132727Skan
3788132727Skan
3789132727Skan/* When -gused is used, emit debug info for only used symbols. But in
3790132727Skan   addition to the standard intercepted debug_hooks there are some direct
3791132727Skan   calls into this file, i.e., dbxout_symbol, dbxout_parms, and dbxout_reg_params.
3792132727Skan   Those routines may also be called from a higher level intercepted routine. So
3793132727Skan   to prevent recording data for an inner call to one of these for an intercept,
3794132727Skan   we maintain an intercept nesting counter (debug_nesting). We only save the
3795132727Skan   intercepted arguments if the nesting is 1.  */
3796132727Skanint debug_nesting = 0;
3797132727Skan
3798132727Skanstatic tree *symbol_queue;
3799132727Skanint symbol_queue_index = 0;
3800132727Skanstatic int symbol_queue_size = 0;
3801132727Skan
3802132727Skan/* Generate the symbols for any queued up type symbols we encountered
3803132727Skan   while generating the type info for some originally used symbol.
3804132727Skan   This might generate additional entries in the queue.  Only when
3805132727Skan   the nesting depth goes to 0 is this routine called.  */
3806132727Skan
3807132727Skanvoid
3808132727Skandebug_flush_symbol_queue (void)
3809132727Skan{
3810132727Skan  int i;
3811132727Skan
3812132727Skan  /* Make sure that additionally queued items are not flushed
3813132727Skan     prematurely.  */
3814132727Skan
3815132727Skan  ++debug_nesting;
3816132727Skan
3817132727Skan  for (i = 0; i < symbol_queue_index; ++i)
3818132727Skan    {
3819132727Skan      /* If we pushed queued symbols then such symbols are must be
3820132727Skan         output no matter what anyone else says.  Specifically,
3821132727Skan         we need to make sure dbxout_symbol() thinks the symbol was
3822132727Skan         used and also we need to override TYPE_DECL_SUPPRESS_DEBUG
3823132727Skan         which may be set for outside reasons.  */
3824132727Skan      int saved_tree_used = TREE_USED (symbol_queue[i]);
3825132727Skan      int saved_suppress_debug = TYPE_DECL_SUPPRESS_DEBUG (symbol_queue[i]);
3826132727Skan      TREE_USED (symbol_queue[i]) = 1;
3827132727Skan      TYPE_DECL_SUPPRESS_DEBUG (symbol_queue[i]) = 0;
3828132727Skan
3829132727Skan#ifdef DBX_DEBUGGING_INFO
3830132727Skan      dbxout_symbol (symbol_queue[i], 0);
3831132727Skan#endif
3832132727Skan
3833132727Skan      TREE_USED (symbol_queue[i]) = saved_tree_used;
3834132727Skan      TYPE_DECL_SUPPRESS_DEBUG (symbol_queue[i]) = saved_suppress_debug;
3835132727Skan    }
3836132727Skan
3837132727Skan  symbol_queue_index = 0;
3838132727Skan  --debug_nesting;
3839132727Skan}
3840132727Skan
3841132727Skan/* Queue a type symbol needed as part of the definition of a decl
3842132727Skan   symbol.  These symbols are generated when debug_flush_symbol_queue()
3843132727Skan   is called.  */
3844132727Skan
3845132727Skanvoid
3846132727Skandebug_queue_symbol (tree decl)
3847132727Skan{
3848132727Skan  if (symbol_queue_index >= symbol_queue_size)
3849132727Skan    {
3850132727Skan      symbol_queue_size += 10;
3851132727Skan      symbol_queue = xrealloc (symbol_queue,
3852132727Skan			       symbol_queue_size * sizeof (tree));
3853132727Skan    }
3854132727Skan
3855132727Skan  symbol_queue[symbol_queue_index++] = decl;
3856132727Skan}
3857132727Skan
3858132727Skan/* Free symbol queue.  */
3859132727Skanvoid
3860132727Skandebug_free_queue (void)
3861132727Skan{
3862132727Skan  if (symbol_queue)
3863132727Skan    {
3864132727Skan      free (symbol_queue);
3865132727Skan      symbol_queue = NULL;
3866132727Skan      symbol_queue_size = 0;
3867132727Skan    }
3868132727Skan}
3869