final.c revision 50503
118334Speter/* Convert RTL to assembler code and output it, for GNU compiler.
250503Sobrien   Copyright (C) 1987, 88, 89, 92-97, 1998 Free Software Foundation, Inc.
318334Speter
418334SpeterThis file is part of GNU CC.
518334Speter
618334SpeterGNU CC is free software; you can redistribute it and/or modify
718334Speterit under the terms of the GNU General Public License as published by
818334Speterthe Free Software Foundation; either version 2, or (at your option)
918334Speterany later version.
1018334Speter
1118334SpeterGNU CC is distributed in the hope that it will be useful,
1218334Speterbut WITHOUT ANY WARRANTY; without even the implied warranty of
1318334SpeterMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1418334SpeterGNU General Public License for more details.
1518334Speter
1618334SpeterYou should have received a copy of the GNU General Public License
1718334Speteralong with GNU CC; see the file COPYING.  If not, write to
1818334Speterthe Free Software Foundation, 59 Temple Place - Suite 330,
1918334SpeterBoston, MA 02111-1307, USA.  */
2018334Speter
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
4418334Speter   directly as assembler code by the macros FUNCTION_PROLOGUE and
4518334Speter   FUNCTION_EPILOGUE.  Those instructions never exist as rtl.  */
4618334Speter
4718334Speter#include "config.h"
4818334Speter#ifdef __STDC__
4918334Speter#include <stdarg.h>
5018334Speter#else
5118334Speter#include <varargs.h>
5218334Speter#endif
5350503Sobrien#include "system.h"
5418334Speter
5518334Speter#include "tree.h"
5618334Speter#include "rtl.h"
5718334Speter#include "regs.h"
5818334Speter#include "insn-config.h"
5918334Speter#include "insn-flags.h"
6018334Speter#include "insn-attr.h"
6118334Speter#include "insn-codes.h"
6218334Speter#include "recog.h"
6318334Speter#include "conditions.h"
6418334Speter#include "flags.h"
6518334Speter#include "real.h"
6618334Speter#include "hard-reg-set.h"
6718334Speter#include "defaults.h"
6818334Speter#include "output.h"
6950503Sobrien#include "except.h"
7050503Sobrien#include "toplev.h"
7150503Sobrien#include "reload.h"
7218334Speter
7318334Speter/* Get N_SLINE and N_SOL from stab.h if we can expect the file to exist.  */
7418334Speter#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
7550503Sobrien#include "dbxout.h"
7650503Sobrien#if defined (USG) || !defined (HAVE_STAB_H)
7718334Speter#include "gstab.h"  /* If doing DBX on sysV, use our own stab.h.  */
7818334Speter#else
7950503Sobrien#include <stab.h>
8050503Sobrien#endif
8150503Sobrien
8218334Speter#endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */
8318334Speter
8418334Speter#ifdef XCOFF_DEBUGGING_INFO
8518334Speter#include "xcoffout.h"
8618334Speter#endif
8718334Speter
8850503Sobrien#ifdef DWARF_DEBUGGING_INFO
8950503Sobrien#include "dwarfout.h"
9050503Sobrien#endif
9150503Sobrien
9250503Sobrien#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
9350503Sobrien#include "dwarf2out.h"
9450503Sobrien#endif
9550503Sobrien
9650503Sobrien#ifdef SDB_DEBUGGING_INFO
9750503Sobrien#include "sdbout.h"
9850503Sobrien#endif
9950503Sobrien
10018334Speter/* .stabd code for line number.  */
10118334Speter#ifndef N_SLINE
10218334Speter#define	N_SLINE	0x44
10318334Speter#endif
10418334Speter
10518334Speter/* .stabs code for included file name.  */
10618334Speter#ifndef N_SOL
10718334Speter#define	N_SOL 0x84
10818334Speter#endif
10918334Speter
11018334Speter#ifndef INT_TYPE_SIZE
11118334Speter#define INT_TYPE_SIZE BITS_PER_WORD
11218334Speter#endif
11318334Speter
11450503Sobrien#ifndef LONG_TYPE_SIZE
11550503Sobrien#define LONG_TYPE_SIZE BITS_PER_WORD
11650503Sobrien#endif
11750503Sobrien
11818334Speter/* If we aren't using cc0, CC_STATUS_INIT shouldn't exist.  So define a
11918334Speter   null default for it to save conditionalization later.  */
12018334Speter#ifndef CC_STATUS_INIT
12118334Speter#define CC_STATUS_INIT
12218334Speter#endif
12318334Speter
12418334Speter/* How to start an assembler comment.  */
12518334Speter#ifndef ASM_COMMENT_START
12618334Speter#define ASM_COMMENT_START ";#"
12718334Speter#endif
12818334Speter
12918334Speter/* Is the given character a logical line separator for the assembler?  */
13018334Speter#ifndef IS_ASM_LOGICAL_LINE_SEPARATOR
13118334Speter#define IS_ASM_LOGICAL_LINE_SEPARATOR(C) ((C) == ';')
13218334Speter#endif
13318334Speter
13450503Sobrien#ifndef JUMP_TABLES_IN_TEXT_SECTION
13550503Sobrien#define JUMP_TABLES_IN_TEXT_SECTION 0
13650503Sobrien#endif
13750503Sobrien
13818334Speter/* Nonzero means this function is a leaf function, with no function calls.
13918334Speter   This variable exists to be examined in FUNCTION_PROLOGUE
14018334Speter   and FUNCTION_EPILOGUE.  Always zero, unless set by some action.  */
14118334Speterint leaf_function;
14218334Speter
14318334Speter/* Last insn processed by final_scan_insn.  */
14418334Speterstatic rtx debug_insn = 0;
14518334Speter
14618334Speter/* Line number of last NOTE.  */
14718334Speterstatic int last_linenum;
14818334Speter
14918334Speter/* Highest line number in current block.  */
15018334Speterstatic int high_block_linenum;
15118334Speter
15218334Speter/* Likewise for function.  */
15318334Speterstatic int high_function_linenum;
15418334Speter
15518334Speter/* Filename of last NOTE.  */
15618334Speterstatic char *last_filename;
15718334Speter
15818334Speter/* Number of basic blocks seen so far;
15918334Speter   used if profile_block_flag is set.  */
16018334Speterstatic int count_basic_blocks;
16118334Speter
16250503Sobrien/* Number of instrumented arcs when profile_arc_flag is set.  */
16350503Sobrienextern int count_instrumented_arcs;
16450503Sobrien
16550503Sobrienextern int length_unit_log; /* This is defined in insn-attrtab.c.  */
16650503Sobrien
16718334Speter/* Nonzero while outputting an `asm' with operands.
16818334Speter   This means that inconsistencies are the user's fault, so don't abort.
16918334Speter   The precise value is the insn being output, to pass to error_for_asm.  */
17018334Speterstatic rtx this_is_asm_operands;
17118334Speter
17218334Speter/* Number of operands of this insn, for an `asm' with operands.  */
17350503Sobrienstatic unsigned int insn_noperands;
17418334Speter
17518334Speter/* Compare optimization flag.  */
17618334Speter
17718334Speterstatic rtx last_ignored_compare = 0;
17818334Speter
17918334Speter/* Flag indicating this insn is the start of a new basic block.  */
18018334Speter
18118334Speterstatic int new_block = 1;
18218334Speter
18318334Speter/* All the symbol-blocks (levels of scoping) in the compilation
18418334Speter   are assigned sequence numbers in order of appearance of the
18518334Speter   beginnings of the symbol-blocks.  Both final and dbxout do this,
18618334Speter   and assume that they will both give the same number to each block.
18718334Speter   Final uses these sequence numbers to generate assembler label names
18818334Speter   LBBnnn and LBEnnn for the beginning and end of the symbol-block.
18918334Speter   Dbxout uses the sequence numbers to generate references to the same labels
19018334Speter   from the dbx debugging information.
19118334Speter
19218334Speter   Sdb records this level at the beginning of each function,
19318334Speter   in order to find the current level when recursing down declarations.
19418334Speter   It outputs the block beginning and endings
19518334Speter   at the point in the asm file where the blocks would begin and end.  */
19618334Speter
19718334Speterint next_block_index;
19818334Speter
19918334Speter/* Assign a unique number to each insn that is output.
20018334Speter   This can be used to generate unique local labels.  */
20118334Speter
20218334Speterstatic int insn_counter = 0;
20318334Speter
20418334Speter#ifdef HAVE_cc0
20518334Speter/* This variable contains machine-dependent flags (defined in tm.h)
20618334Speter   set and examined by output routines
20718334Speter   that describe how to interpret the condition codes properly.  */
20818334Speter
20918334SpeterCC_STATUS cc_status;
21018334Speter
21118334Speter/* During output of an insn, this contains a copy of cc_status
21218334Speter   from before the insn.  */
21318334Speter
21418334SpeterCC_STATUS cc_prev_status;
21518334Speter#endif
21618334Speter
21718334Speter/* Indexed by hardware reg number, is 1 if that register is ever
21818334Speter   used in the current function.
21918334Speter
22018334Speter   In life_analysis, or in stupid_life_analysis, this is set
22118334Speter   up to record the hard regs used explicitly.  Reload adds
22218334Speter   in the hard regs used for holding pseudo regs.  Final uses
22318334Speter   it to generate the code in the function prologue and epilogue
22418334Speter   to save and restore registers as needed.  */
22518334Speter
22618334Speterchar regs_ever_live[FIRST_PSEUDO_REGISTER];
22718334Speter
22818334Speter/* Nonzero means current function must be given a frame pointer.
22918334Speter   Set in stmt.c if anything is allocated on the stack there.
23018334Speter   Set in reload1.c if anything is allocated on the stack there.  */
23118334Speter
23218334Speterint frame_pointer_needed;
23318334Speter
23418334Speter/* Assign unique numbers to labels generated for profiling.  */
23518334Speter
23618334Speterint profile_label_no;
23718334Speter
23818334Speter/* Length so far allocated in PENDING_BLOCKS.  */
23918334Speter
24018334Speterstatic int max_block_depth;
24118334Speter
24218334Speter/* Stack of sequence numbers of symbol-blocks of which we have seen the
24318334Speter   beginning but not yet the end.  Sequence numbers are assigned at
24418334Speter   the beginning; this stack allows us to find the sequence number
24518334Speter   of a block that is ending.  */
24618334Speter
24718334Speterstatic int *pending_blocks;
24818334Speter
24918334Speter/* Number of elements currently in use in PENDING_BLOCKS.  */
25018334Speter
25118334Speterstatic int block_depth;
25218334Speter
25318334Speter/* Nonzero if have enabled APP processing of our assembler output.  */
25418334Speter
25518334Speterstatic int app_on;
25618334Speter
25718334Speter/* If we are outputting an insn sequence, this contains the sequence rtx.
25818334Speter   Zero otherwise.  */
25918334Speter
26018334Speterrtx final_sequence;
26118334Speter
26218334Speter#ifdef ASSEMBLER_DIALECT
26318334Speter
26418334Speter/* Number of the assembler dialect to use, starting at 0.  */
26518334Speterstatic int dialect_number;
26618334Speter#endif
26718334Speter
26818334Speter/* Indexed by line number, nonzero if there is a note for that line.  */
26918334Speter
27018334Speterstatic char *line_note_exists;
27118334Speter
27218334Speter/* Linked list to hold line numbers for each basic block.  */
27318334Speter
27418334Speterstruct bb_list {
27518334Speter  struct bb_list *next;		/* pointer to next basic block */
27618334Speter  int line_num;			/* line number */
27718334Speter  int file_label_num;		/* LPBC<n> label # for stored filename */
27818334Speter  int func_label_num;		/* LPBC<n> label # for stored function name */
27918334Speter};
28018334Speter
28118334Speterstatic struct bb_list *bb_head	= 0;		/* Head of basic block list */
28218334Speterstatic struct bb_list **bb_tail = &bb_head;	/* Ptr to store next bb ptr */
28318334Speterstatic int bb_file_label_num	= -1;		/* Current label # for file */
28418334Speterstatic int bb_func_label_num	= -1;		/* Current label # for func */
28518334Speter
28618334Speter/* Linked list to hold the strings for each file and function name output.  */
28718334Speter
28818334Speterstruct bb_str {
28918334Speter  struct bb_str *next;		/* pointer to next string */
29018334Speter  char *string;			/* string */
29118334Speter  int label_num;		/* label number */
29218334Speter  int length;			/* string length */
29318334Speter};
29418334Speter
29518334Speterextern rtx peephole		PROTO((rtx));
29618334Speter
29718334Speterstatic struct bb_str *sbb_head	= 0;		/* Head of string list.  */
29818334Speterstatic struct bb_str **sbb_tail	= &sbb_head;	/* Ptr to store next bb str */
29918334Speterstatic int sbb_label_num	= 0;		/* Last label used */
30018334Speter
30150503Sobrien#ifdef HAVE_ATTR_length
30218334Speterstatic int asm_insn_count	PROTO((rtx));
30350503Sobrien#endif
30418334Speterstatic void profile_function	PROTO((FILE *));
30518334Speterstatic void profile_after_prologue PROTO((FILE *));
30618334Speterstatic void add_bb		PROTO((FILE *));
30718334Speterstatic int add_bb_string	PROTO((char *, int));
30818334Speterstatic void output_source_line	PROTO((FILE *, rtx));
30918334Speterstatic rtx walk_alter_subreg	PROTO((rtx));
31018334Speterstatic void output_asm_name	PROTO((void));
31118334Speterstatic void output_operand	PROTO((rtx, int));
31250503Sobrien#ifdef LEAF_REGISTERS
31318334Speterstatic void leaf_renumber_regs	PROTO((rtx));
31450503Sobrien#endif
31550503Sobrien#ifdef HAVE_cc0
31650503Sobrienstatic int alter_cond		PROTO((rtx));
31750503Sobrien#endif
31818334Speter
31918334Speterextern char *getpwd ();
32018334Speter
32118334Speter/* Initialize data in final at the beginning of a compilation.  */
32218334Speter
32318334Spetervoid
32418334Speterinit_final (filename)
32518334Speter     char *filename;
32618334Speter{
32718334Speter  next_block_index = 2;
32818334Speter  app_on = 0;
32918334Speter  max_block_depth = 20;
33018334Speter  pending_blocks = (int *) xmalloc (20 * sizeof *pending_blocks);
33118334Speter  final_sequence = 0;
33218334Speter
33318334Speter#ifdef ASSEMBLER_DIALECT
33418334Speter  dialect_number = ASSEMBLER_DIALECT;
33518334Speter#endif
33618334Speter}
33718334Speter
33818334Speter/* Called at end of source file,
33918334Speter   to output the block-profiling table for this entire compilation.  */
34018334Speter
34118334Spetervoid
34218334Speterend_final (filename)
34318334Speter     char *filename;
34418334Speter{
34518334Speter  int i;
34618334Speter
34750503Sobrien  if (profile_block_flag || profile_arc_flag)
34818334Speter    {
34918334Speter      char name[20];
35018334Speter      int align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
35150503Sobrien      int size, rounded;
35218334Speter      struct bb_list *ptr;
35318334Speter      struct bb_str *sptr;
35450503Sobrien      int long_bytes = LONG_TYPE_SIZE / BITS_PER_UNIT;
35550503Sobrien      int pointer_bytes = POINTER_SIZE / BITS_PER_UNIT;
35618334Speter
35750503Sobrien      if (profile_block_flag)
35850503Sobrien	size = long_bytes * count_basic_blocks;
35950503Sobrien      else
36050503Sobrien	size = long_bytes * count_instrumented_arcs;
36150503Sobrien      rounded = size;
36250503Sobrien
36318334Speter      rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;
36418334Speter      rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
36518334Speter		 * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
36618334Speter
36718334Speter      data_section ();
36818334Speter
36950503Sobrien      /* Output the main header, of 11 words:
37050503Sobrien	 0:  1 if this file is initialized, else 0.
37118334Speter	 1:  address of file name (LPBX1).
37218334Speter	 2:  address of table of counts (LPBX2).
37318334Speter	 3:  number of counts in the table.
37418334Speter	 4:  always 0, for compatibility with Sun.
37518334Speter
37618334Speter         The following are GNU extensions:
37718334Speter
37818334Speter	 5:  address of table of start addrs of basic blocks (LPBX3).
37918334Speter	 6:  Number of bytes in this header.
38018334Speter	 7:  address of table of function names (LPBX4).
38118334Speter	 8:  address of table of line numbers (LPBX5) or 0.
38250503Sobrien	 9:  address of table of file names (LPBX6) or 0.
38350503Sobrien	10:  space reserved for basic block profiling.  */
38418334Speter
38518334Speter      ASM_OUTPUT_ALIGN (asm_out_file, align);
38618334Speter
38718334Speter      ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 0);
38818334Speter      /* zero word */
38950503Sobrien      assemble_integer (const0_rtx, long_bytes, 1);
39018334Speter
39118334Speter      /* address of filename */
39218334Speter      ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 1);
39350503Sobrien      assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes, 1);
39418334Speter
39518334Speter      /* address of count table */
39618334Speter      ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2);
39750503Sobrien      assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes, 1);
39818334Speter
39950503Sobrien      /* count of the # of basic blocks or # of instrumented arcs */
40050503Sobrien      if (profile_block_flag)
40150503Sobrien	assemble_integer (GEN_INT (count_basic_blocks), long_bytes, 1);
40250503Sobrien      else
40350503Sobrien	assemble_integer (GEN_INT (count_instrumented_arcs), long_bytes,
40450503Sobrien			  1);
40518334Speter
40618334Speter      /* zero word (link field) */
40750503Sobrien      assemble_integer (const0_rtx, pointer_bytes, 1);
40818334Speter
40918334Speter      /* address of basic block start address table */
41050503Sobrien      if (profile_block_flag)
41150503Sobrien	{
41250503Sobrien	  ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 3);
41350503Sobrien	  assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes,
41450503Sobrien			    1);
41550503Sobrien	}
41650503Sobrien      else
41750503Sobrien	assemble_integer (const0_rtx, pointer_bytes, 1);
41818334Speter
41918334Speter      /* byte count for extended structure.  */
42050503Sobrien      assemble_integer (GEN_INT (10 * UNITS_PER_WORD), long_bytes, 1);
42118334Speter
42218334Speter      /* address of function name table */
42350503Sobrien      if (profile_block_flag)
42450503Sobrien	{
42550503Sobrien	  ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 4);
42650503Sobrien	  assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes,
42750503Sobrien			    1);
42850503Sobrien	}
42950503Sobrien      else
43050503Sobrien	assemble_integer (const0_rtx, pointer_bytes, 1);
43118334Speter
43218334Speter      /* address of line number and filename tables if debugging.  */
43350503Sobrien      if (write_symbols != NO_DEBUG && profile_block_flag)
43418334Speter	{
43518334Speter	  ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 5);
43650503Sobrien	  assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes, 1);
43718334Speter	  ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 6);
43850503Sobrien	  assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes, 1);
43918334Speter	}
44018334Speter      else
44118334Speter	{
44250503Sobrien	  assemble_integer (const0_rtx, pointer_bytes, 1);
44350503Sobrien	  assemble_integer (const0_rtx, pointer_bytes, 1);
44418334Speter	}
44518334Speter
44650503Sobrien      /* space for extension ptr (link field) */
44750503Sobrien      assemble_integer (const0_rtx, UNITS_PER_WORD, 1);
44850503Sobrien
44918334Speter      /* Output the file name changing the suffix to .d for Sun tcov
45018334Speter	 compatibility.  */
45118334Speter      ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 1);
45218334Speter      {
45318334Speter	char *cwd = getpwd ();
45418334Speter	int len = strlen (filename) + strlen (cwd) + 1;
45518334Speter	char *data_file = (char *) alloca (len + 4);
45618334Speter
45718334Speter	strcpy (data_file, cwd);
45818334Speter	strcat (data_file, "/");
45918334Speter	strcat (data_file, filename);
46018334Speter	strip_off_ending (data_file, len);
46150503Sobrien	if (profile_block_flag)
46250503Sobrien	  strcat (data_file, ".d");
46350503Sobrien	else
46450503Sobrien	  strcat (data_file, ".da");
46518334Speter	assemble_string (data_file, strlen (data_file) + 1);
46618334Speter      }
46718334Speter
46818334Speter      /* Make space for the table of counts.  */
46950503Sobrien      if (size == 0)
47018334Speter	{
47118334Speter	  /* Realign data section.  */
47218334Speter	  ASM_OUTPUT_ALIGN (asm_out_file, align);
47318334Speter	  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 2);
47418334Speter	  if (size != 0)
47518334Speter	    assemble_zeros (size);
47618334Speter	}
47718334Speter      else
47818334Speter	{
47918334Speter	  ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2);
48018334Speter#ifdef ASM_OUTPUT_SHARED_LOCAL
48118334Speter	  if (flag_shared_data)
48218334Speter	    ASM_OUTPUT_SHARED_LOCAL (asm_out_file, name, size, rounded);
48318334Speter	  else
48418334Speter#endif
48550503Sobrien#ifdef ASM_OUTPUT_ALIGNED_DECL_LOCAL
48650503Sobrien	    ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, NULL_TREE, name, size,
48750503Sobrien					      BIGGEST_ALIGNMENT);
48850503Sobrien#else
48918334Speter#ifdef ASM_OUTPUT_ALIGNED_LOCAL
49018334Speter	    ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size,
49118334Speter				      BIGGEST_ALIGNMENT);
49218334Speter#else
49318334Speter	    ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
49418334Speter#endif
49550503Sobrien#endif
49618334Speter	}
49718334Speter
49818334Speter      /* Output any basic block strings */
49950503Sobrien      if (profile_block_flag)
50018334Speter	{
50150503Sobrien	  readonly_data_section ();
50250503Sobrien	  if (sbb_head)
50318334Speter	    {
50450503Sobrien	      ASM_OUTPUT_ALIGN (asm_out_file, align);
50550503Sobrien	      for (sptr = sbb_head; sptr != 0; sptr = sptr->next)
50650503Sobrien		{
50750503Sobrien		  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBC",
50850503Sobrien					     sptr->label_num);
50950503Sobrien		  assemble_string (sptr->string, sptr->length);
51050503Sobrien		}
51118334Speter	    }
51218334Speter	}
51318334Speter
51418334Speter      /* Output the table of addresses.  */
51550503Sobrien      if (profile_block_flag)
51618334Speter	{
51750503Sobrien	  /* Realign in new section */
51850503Sobrien	  ASM_OUTPUT_ALIGN (asm_out_file, align);
51950503Sobrien	  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 3);
52050503Sobrien	  for (i = 0; i < count_basic_blocks; i++)
52150503Sobrien	    {
52250503Sobrien	      ASM_GENERATE_INTERNAL_LABEL (name, "LPB", i);
52350503Sobrien	      assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name),
52450503Sobrien				pointer_bytes, 1);
52550503Sobrien	    }
52618334Speter	}
52718334Speter
52818334Speter      /* Output the table of function names.  */
52950503Sobrien      if (profile_block_flag)
53018334Speter	{
53150503Sobrien	  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 4);
53250503Sobrien	  for ((ptr = bb_head), (i = 0); ptr != 0; (ptr = ptr->next), i++)
53318334Speter	    {
53450503Sobrien	      if (ptr->func_label_num >= 0)
53550503Sobrien		{
53650503Sobrien		  ASM_GENERATE_INTERNAL_LABEL (name, "LPBC",
53750503Sobrien					       ptr->func_label_num);
53850503Sobrien		  assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name),
53950503Sobrien				    pointer_bytes, 1);
54050503Sobrien		}
54150503Sobrien	      else
54250503Sobrien		assemble_integer (const0_rtx, pointer_bytes, 1);
54318334Speter	    }
54450503Sobrien
54550503Sobrien	  for ( ; i < count_basic_blocks; i++)
54650503Sobrien	    assemble_integer (const0_rtx, pointer_bytes, 1);
54718334Speter	}
54818334Speter
54950503Sobrien      if (write_symbols != NO_DEBUG && profile_block_flag)
55018334Speter	{
55118334Speter	  /* Output the table of line numbers.  */
55218334Speter	  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 5);
55318334Speter	  for ((ptr = bb_head), (i = 0); ptr != 0; (ptr = ptr->next), i++)
55450503Sobrien	    assemble_integer (GEN_INT (ptr->line_num), long_bytes, 1);
55518334Speter
55618334Speter	  for ( ; i < count_basic_blocks; i++)
55750503Sobrien	    assemble_integer (const0_rtx, long_bytes, 1);
55818334Speter
55918334Speter	  /* Output the table of file names.  */
56018334Speter	  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 6);
56118334Speter	  for ((ptr = bb_head), (i = 0); ptr != 0; (ptr = ptr->next), i++)
56218334Speter	    {
56318334Speter	      if (ptr->file_label_num >= 0)
56418334Speter		{
56550503Sobrien		  ASM_GENERATE_INTERNAL_LABEL (name, "LPBC",
56650503Sobrien					       ptr->file_label_num);
56750503Sobrien		  assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name),
56850503Sobrien				    pointer_bytes, 1);
56918334Speter		}
57018334Speter	      else
57150503Sobrien		assemble_integer (const0_rtx, pointer_bytes, 1);
57218334Speter	    }
57318334Speter
57418334Speter	  for ( ; i < count_basic_blocks; i++)
57550503Sobrien	    assemble_integer (const0_rtx, pointer_bytes, 1);
57618334Speter	}
57718334Speter
57818334Speter      /* End with the address of the table of addresses,
57918334Speter	 so we can find it easily, as the last word in the file's text.  */
58050503Sobrien      if (profile_block_flag)
58150503Sobrien	{
58250503Sobrien	  ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 3);
58350503Sobrien	  assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes,
58450503Sobrien			    1);
58550503Sobrien	}
58618334Speter    }
58718334Speter}
58818334Speter
58918334Speter/* Enable APP processing of subsequent output.
59018334Speter   Used before the output from an `asm' statement.  */
59118334Speter
59218334Spetervoid
59318334Speterapp_enable ()
59418334Speter{
59518334Speter  if (! app_on)
59618334Speter    {
59750503Sobrien      fputs (ASM_APP_ON, asm_out_file);
59818334Speter      app_on = 1;
59918334Speter    }
60018334Speter}
60118334Speter
60218334Speter/* Disable APP processing of subsequent output.
60318334Speter   Called from varasm.c before most kinds of output.  */
60418334Speter
60518334Spetervoid
60618334Speterapp_disable ()
60718334Speter{
60818334Speter  if (app_on)
60918334Speter    {
61050503Sobrien      fputs (ASM_APP_OFF, asm_out_file);
61118334Speter      app_on = 0;
61218334Speter    }
61318334Speter}
61418334Speter
61518334Speter/* Return the number of slots filled in the current
61618334Speter   delayed branch sequence (we don't count the insn needing the
61718334Speter   delay slot).   Zero if not in a delayed branch sequence.  */
61818334Speter
61918334Speter#ifdef DELAY_SLOTS
62018334Speterint
62118334Speterdbr_sequence_length ()
62218334Speter{
62318334Speter  if (final_sequence != 0)
62418334Speter    return XVECLEN (final_sequence, 0) - 1;
62518334Speter  else
62618334Speter    return 0;
62718334Speter}
62818334Speter#endif
62918334Speter
63018334Speter/* The next two pages contain routines used to compute the length of an insn
63118334Speter   and to shorten branches.  */
63218334Speter
63318334Speter/* Arrays for insn lengths, and addresses.  The latter is referenced by
63418334Speter   `insn_current_length'.  */
63518334Speter
63618334Speterstatic short *insn_lengths;
63718334Speterint *insn_addresses;
63818334Speter
63918334Speter/* Address of insn being processed.  Used by `insn_current_length'.  */
64018334Speterint insn_current_address;
64118334Speter
64250503Sobrien/* Address of insn being processed in previous iteration.  */
64350503Sobrienint insn_last_address;
64450503Sobrien
64550503Sobrien/* konwn invariant alignment of insn being processed.  */
64650503Sobrienint insn_current_align;
64750503Sobrien
64850503Sobrien/* After shorten_branches, for any insn, uid_align[INSN_UID (insn)]
64950503Sobrien   gives the next following alignment insn that increases the known
65050503Sobrien   alignment, or NULL_RTX if there is no such insn.
65150503Sobrien   For any alignment obtained this way, we can again index uid_align with
65250503Sobrien   its uid to obtain the next following align that in turn increases the
65350503Sobrien   alignment, till we reach NULL_RTX; the sequence obtained this way
65450503Sobrien   for each insn we'll call the alignment chain of this insn in the following
65550503Sobrien   comments.  */
65650503Sobrien
65750503Sobrienstruct label_alignment {
65850503Sobrien  short alignment;
65950503Sobrien  short max_skip;
66050503Sobrien};
66150503Sobrien
66250503Sobrienstatic rtx *uid_align;
66350503Sobrienstatic int *uid_shuid;
66450503Sobrienstatic struct label_alignment *label_align;
66550503Sobrien
66618334Speter/* Indicate that branch shortening hasn't yet been done.  */
66718334Speter
66818334Spetervoid
66918334Speterinit_insn_lengths ()
67018334Speter{
67150503Sobrien  if (label_align)
67250503Sobrien    {
67350503Sobrien      free (label_align);
67450503Sobrien      label_align = 0;
67550503Sobrien    }
67650503Sobrien  if (uid_shuid)
67750503Sobrien    {
67850503Sobrien      free (uid_shuid);
67950503Sobrien      uid_shuid = 0;
68050503Sobrien    }
68150503Sobrien  if (insn_lengths)
68250503Sobrien    {
68350503Sobrien      free (insn_lengths);
68450503Sobrien      insn_lengths = 0;
68550503Sobrien    }
68650503Sobrien  if (insn_addresses)
68750503Sobrien    {
68850503Sobrien      free (insn_addresses);
68950503Sobrien      insn_addresses = 0;
69050503Sobrien    }
69150503Sobrien  if (uid_align)
69250503Sobrien    {
69350503Sobrien      free (uid_align);
69450503Sobrien      uid_align = 0;
69550503Sobrien    }
69618334Speter}
69718334Speter
69818334Speter/* Obtain the current length of an insn.  If branch shortening has been done,
69918334Speter   get its actual length.  Otherwise, get its maximum length.  */
70018334Speter
70118334Speterint
70218334Speterget_attr_length (insn)
70318334Speter     rtx insn;
70418334Speter{
70518334Speter#ifdef HAVE_ATTR_length
70618334Speter  rtx body;
70718334Speter  int i;
70818334Speter  int length = 0;
70918334Speter
71018334Speter  if (insn_lengths)
71118334Speter    return insn_lengths[INSN_UID (insn)];
71218334Speter  else
71318334Speter    switch (GET_CODE (insn))
71418334Speter      {
71518334Speter      case NOTE:
71618334Speter      case BARRIER:
71718334Speter      case CODE_LABEL:
71818334Speter	return 0;
71918334Speter
72018334Speter      case CALL_INSN:
72118334Speter	length = insn_default_length (insn);
72218334Speter	break;
72318334Speter
72418334Speter      case JUMP_INSN:
72518334Speter	body = PATTERN (insn);
72618334Speter        if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
72718334Speter	  {
72850503Sobrien	    /* Alignment is machine-dependent and should be handled by
72950503Sobrien	       ADDR_VEC_ALIGN.  */
73018334Speter	  }
73118334Speter	else
73218334Speter	  length = insn_default_length (insn);
73318334Speter	break;
73418334Speter
73518334Speter      case INSN:
73618334Speter	body = PATTERN (insn);
73718334Speter	if (GET_CODE (body) == USE || GET_CODE (body) == CLOBBER)
73818334Speter	  return 0;
73918334Speter
74018334Speter	else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0)
74118334Speter	  length = asm_insn_count (body) * insn_default_length (insn);
74218334Speter	else if (GET_CODE (body) == SEQUENCE)
74318334Speter	  for (i = 0; i < XVECLEN (body, 0); i++)
74418334Speter	    length += get_attr_length (XVECEXP (body, 0, i));
74518334Speter	else
74618334Speter	  length = insn_default_length (insn);
74750503Sobrien	break;
74850503Sobrien
74950503Sobrien      default:
75050503Sobrien	break;
75118334Speter      }
75218334Speter
75318334Speter#ifdef ADJUST_INSN_LENGTH
75418334Speter  ADJUST_INSN_LENGTH (insn, length);
75518334Speter#endif
75618334Speter  return length;
75718334Speter#else /* not HAVE_ATTR_length */
75818334Speter  return 0;
75918334Speter#endif /* not HAVE_ATTR_length */
76018334Speter}
76118334Speter
76250503Sobrien/* Code to handle alignment inside shorten_branches.  */
76350503Sobrien
76450503Sobrien/* Here is an explanation how the algorithm in align_fuzz can give
76550503Sobrien   proper results:
76650503Sobrien
76750503Sobrien   Call a sequence of instructions beginning with alignment point X
76850503Sobrien   and continuing until the next alignment point `block X'.  When `X'
76950503Sobrien   is used in an expression, it means the alignment value of the
77050503Sobrien   alignment point.
77150503Sobrien
77250503Sobrien   Call the distance between the start of the first insn of block X, and
77350503Sobrien   the end of the last insn of block X `IX', for the `inner size of X'.
77450503Sobrien   This is clearly the sum of the instruction lengths.
77550503Sobrien
77650503Sobrien   Likewise with the next alignment-delimited block following X, which we
77750503Sobrien   shall call block Y.
77850503Sobrien
77950503Sobrien   Call the distance between the start of the first insn of block X, and
78050503Sobrien   the start of the first insn of block Y `OX', for the `outer size of X'.
78150503Sobrien
78250503Sobrien   The estimated padding is then OX - IX.
78350503Sobrien
78450503Sobrien   OX can be safely estimated as
78550503Sobrien
78650503Sobrien           if (X >= Y)
78750503Sobrien                   OX = round_up(IX, Y)
78850503Sobrien           else
78950503Sobrien                   OX = round_up(IX, X) + Y - X
79050503Sobrien
79150503Sobrien   Clearly est(IX) >= real(IX), because that only depends on the
79250503Sobrien   instruction lengths, and those being overestimated is a given.
79350503Sobrien
79450503Sobrien   Clearly round_up(foo, Z) >= round_up(bar, Z) if foo >= bar, so
79550503Sobrien   we needn't worry about that when thinking about OX.
79650503Sobrien
79750503Sobrien   When X >= Y, the alignment provided by Y adds no uncertainty factor
79850503Sobrien   for branch ranges starting before X, so we can just round what we have.
79950503Sobrien   But when X < Y, we don't know anything about the, so to speak,
80050503Sobrien   `middle bits', so we have to assume the worst when aligning up from an
80150503Sobrien   address mod X to one mod Y, which is Y - X.  */
80250503Sobrien
80350503Sobrien#ifndef LABEL_ALIGN
80450503Sobrien#define LABEL_ALIGN(LABEL) 0
80550503Sobrien#endif
80650503Sobrien
80750503Sobrien#ifndef LABEL_ALIGN_MAX_SKIP
80850503Sobrien#define LABEL_ALIGN_MAX_SKIP 0
80950503Sobrien#endif
81050503Sobrien
81150503Sobrien#ifndef LOOP_ALIGN
81250503Sobrien#define LOOP_ALIGN(LABEL) 0
81350503Sobrien#endif
81450503Sobrien
81550503Sobrien#ifndef LOOP_ALIGN_MAX_SKIP
81650503Sobrien#define LOOP_ALIGN_MAX_SKIP 0
81750503Sobrien#endif
81850503Sobrien
81950503Sobrien#ifndef LABEL_ALIGN_AFTER_BARRIER
82050503Sobrien#define LABEL_ALIGN_AFTER_BARRIER(LABEL) 0
82150503Sobrien#endif
82250503Sobrien
82350503Sobrien#ifndef LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP
82450503Sobrien#define LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP 0
82550503Sobrien#endif
82650503Sobrien
82750503Sobrien#ifndef ADDR_VEC_ALIGN
82850503Sobrienint
82950503Sobrienfinal_addr_vec_align (addr_vec)
83050503Sobrien     rtx addr_vec;
83150503Sobrien{
83250503Sobrien  int align = exact_log2 (GET_MODE_SIZE (GET_MODE (PATTERN (addr_vec))));
83350503Sobrien
83450503Sobrien  if (align > BIGGEST_ALIGNMENT / BITS_PER_UNIT)
83550503Sobrien    align = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
83650503Sobrien  return align;
83750503Sobrien
83850503Sobrien}
83950503Sobrien#define ADDR_VEC_ALIGN(ADDR_VEC) final_addr_vec_align (ADDR_VEC)
84050503Sobrien#endif
84150503Sobrien
84250503Sobrien#ifndef INSN_LENGTH_ALIGNMENT
84350503Sobrien#define INSN_LENGTH_ALIGNMENT(INSN) length_unit_log
84450503Sobrien#endif
84550503Sobrien
84650503Sobrien#define INSN_SHUID(INSN) (uid_shuid[INSN_UID (INSN)])
84750503Sobrien
84850503Sobrienstatic int min_labelno, max_labelno;
84950503Sobrien
85050503Sobrien#define LABEL_TO_ALIGNMENT(LABEL) \
85150503Sobrien  (label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno].alignment)
85250503Sobrien
85350503Sobrien#define LABEL_TO_MAX_SKIP(LABEL) \
85450503Sobrien  (label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno].max_skip)
85550503Sobrien
85650503Sobrien/* For the benefit of port specific code do this also as a function.  */
85750503Sobrienint
85850503Sobrienlabel_to_alignment (label)
85950503Sobrien     rtx label;
86050503Sobrien{
86150503Sobrien  return LABEL_TO_ALIGNMENT (label);
86250503Sobrien}
86350503Sobrien
86450503Sobrien#ifdef HAVE_ATTR_length
86550503Sobrien/* The differences in addresses
86650503Sobrien   between a branch and its target might grow or shrink depending on
86750503Sobrien   the alignment the start insn of the range (the branch for a forward
86850503Sobrien   branch or the label for a backward branch) starts out on; if these
86950503Sobrien   differences are used naively, they can even oscillate infinitely.
87050503Sobrien   We therefore want to compute a 'worst case' address difference that
87150503Sobrien   is independent of the alignment the start insn of the range end
87250503Sobrien   up on, and that is at least as large as the actual difference.
87350503Sobrien   The function align_fuzz calculates the amount we have to add to the
87450503Sobrien   naively computed difference, by traversing the part of the alignment
87550503Sobrien   chain of the start insn of the range that is in front of the end insn
87650503Sobrien   of the range, and considering for each alignment the maximum amount
87750503Sobrien   that it might contribute to a size increase.
87850503Sobrien
87950503Sobrien   For casesi tables, we also want to know worst case minimum amounts of
88050503Sobrien   address difference, in case a machine description wants to introduce
88150503Sobrien   some common offset that is added to all offsets in a table.
88250503Sobrien   For this purpose, align_fuzz with a growth argument of 0 comuptes the
88350503Sobrien   appropriate adjustment.  */
88450503Sobrien
88550503Sobrien
88650503Sobrien/* Compute the maximum delta by which the difference of the addresses of
88750503Sobrien   START and END might grow / shrink due to a different address for start
88850503Sobrien   which changes the size of alignment insns between START and END.
88950503Sobrien   KNOWN_ALIGN_LOG is the alignment known for START.
89050503Sobrien   GROWTH should be ~0 if the objective is to compute potential code size
89150503Sobrien   increase, and 0 if the objective is to compute potential shrink.
89250503Sobrien   The return value is undefined for any other value of GROWTH.  */
89350503Sobrienint
89450503Sobrienalign_fuzz (start, end, known_align_log, growth)
89550503Sobrien     rtx start, end;
89650503Sobrien     int known_align_log;
89750503Sobrien     unsigned growth;
89850503Sobrien{
89950503Sobrien  int uid = INSN_UID (start);
90050503Sobrien  rtx align_label;
90150503Sobrien  int known_align = 1 << known_align_log;
90250503Sobrien  int end_shuid = INSN_SHUID (end);
90350503Sobrien  int fuzz = 0;
90450503Sobrien
90550503Sobrien  for (align_label = uid_align[uid]; align_label; align_label = uid_align[uid])
90650503Sobrien    {
90750503Sobrien      int align_addr, new_align;
90850503Sobrien
90950503Sobrien      uid = INSN_UID (align_label);
91050503Sobrien      align_addr = insn_addresses[uid] - insn_lengths[uid];
91150503Sobrien      if (uid_shuid[uid] > end_shuid)
91250503Sobrien	break;
91350503Sobrien      known_align_log = LABEL_TO_ALIGNMENT (align_label);
91450503Sobrien      new_align = 1 << known_align_log;
91550503Sobrien      if (new_align < known_align)
91650503Sobrien	continue;
91750503Sobrien      fuzz += (-align_addr ^ growth) & (new_align - known_align);
91850503Sobrien      known_align = new_align;
91950503Sobrien    }
92050503Sobrien  return fuzz;
92150503Sobrien}
92250503Sobrien
92350503Sobrien/* Compute a worst-case reference address of a branch so that it
92450503Sobrien   can be safely used in the presence of aligned labels.  Since the
92550503Sobrien   size of the branch itself is unknown, the size of the branch is
92650503Sobrien   not included in the range.  I.e. for a forward branch, the reference
92750503Sobrien   address is the end address of the branch as known from the previous
92850503Sobrien   branch shortening pass, minus a value to account for possible size
92950503Sobrien   increase due to alignment.  For a backward branch, it is the start
93050503Sobrien   address of the branch as known from the current pass, plus a value
93150503Sobrien   to account for possible size increase due to alignment.
93250503Sobrien   NB.: Therefore, the maximum offset allowed for backward branches needs
93350503Sobrien   to exclude the branch size.  */
93450503Sobrienint
93550503Sobrieninsn_current_reference_address (branch)
93650503Sobrien     rtx branch;
93750503Sobrien{
93850503Sobrien  rtx dest;
93950503Sobrien  rtx seq = NEXT_INSN (PREV_INSN (branch));
94050503Sobrien  int seq_uid = INSN_UID (seq);
94150503Sobrien  if (GET_CODE (branch) != JUMP_INSN)
94250503Sobrien    /* This can happen for example on the PA; the objective is to know the
94350503Sobrien       offset to address something in front of the start of the function.
94450503Sobrien       Thus, we can treat it like a backward branch.
94550503Sobrien       We assume here that FUNCTION_BOUNDARY / BITS_PER_UNIT is larger than
94650503Sobrien       any alignment we'd encounter, so we skip the call to align_fuzz.  */
94750503Sobrien    return insn_current_address;
94850503Sobrien  dest = JUMP_LABEL (branch);
94950503Sobrien  /* BRANCH has no proper alignment chain set, so use SEQ.  */
95050503Sobrien  if (INSN_SHUID (branch) < INSN_SHUID (dest))
95150503Sobrien    {
95250503Sobrien      /* Forward branch. */
95350503Sobrien      return (insn_last_address + insn_lengths[seq_uid]
95450503Sobrien	      - align_fuzz (seq, dest, length_unit_log, ~0));
95550503Sobrien    }
95650503Sobrien  else
95750503Sobrien    {
95850503Sobrien      /* Backward branch. */
95950503Sobrien      return (insn_current_address
96050503Sobrien	      + align_fuzz (dest, seq, length_unit_log, ~0));
96150503Sobrien    }
96250503Sobrien}
96350503Sobrien#endif /* HAVE_ATTR_length */
96450503Sobrien
96518334Speter/* Make a pass over all insns and compute their actual lengths by shortening
96618334Speter   any branches of variable length if possible.  */
96718334Speter
96818334Speter/* Give a default value for the lowest address in a function.  */
96918334Speter
97018334Speter#ifndef FIRST_INSN_ADDRESS
97118334Speter#define FIRST_INSN_ADDRESS 0
97218334Speter#endif
97318334Speter
97450503Sobrien/* shorten_branches might be called multiple times:  for example, the SH
97550503Sobrien   port splits out-of-range conditional branches in MACHINE_DEPENDENT_REORG.
97650503Sobrien   In order to do this, it needs proper length information, which it obtains
97750503Sobrien   by calling shorten_branches.  This cannot be collapsed with
97850503Sobrien   shorten_branches itself into a single pass unless we also want to intergate
97950503Sobrien   reorg.c, since the branch splitting exposes new instructions with delay
98050503Sobrien   slots.  */
98150503Sobrien
98218334Spetervoid
98318334Spetershorten_branches (first)
98418334Speter     rtx first;
98518334Speter{
98650503Sobrien  rtx insn;
98750503Sobrien  int max_uid;
98850503Sobrien  int i;
98950503Sobrien  int max_log;
99050503Sobrien  int max_skip;
99118334Speter#ifdef HAVE_ATTR_length
99250503Sobrien#define MAX_CODE_ALIGN 16
99350503Sobrien  rtx seq;
99418334Speter  int something_changed = 1;
99518334Speter  char *varying_length;
99618334Speter  rtx body;
99718334Speter  int uid;
99850503Sobrien  rtx align_tab[MAX_CODE_ALIGN];
99918334Speter
100050503Sobrien  /* In order to make sure that all instructions have valid length info,
100150503Sobrien     we must split them before we compute the address/length info.  */
100218334Speter
100350503Sobrien  for (insn = NEXT_INSN (first); insn; insn = NEXT_INSN (insn))
100450503Sobrien    if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
100550503Sobrien      {
100650503Sobrien	rtx old = insn;
100750503Sobrien	insn = try_split (PATTERN (old), old, 1);
100850503Sobrien	/* When not optimizing, the old insn will be still left around
100950503Sobrien	   with only the 'deleted' bit set.  Transform it into a note
101050503Sobrien	   to avoid confusion of subsequent processing.  */
101150503Sobrien	if (INSN_DELETED_P (old))
101250503Sobrien          {
101350503Sobrien            PUT_CODE (old , NOTE);
101450503Sobrien            NOTE_LINE_NUMBER (old) = NOTE_INSN_DELETED;
101550503Sobrien            NOTE_SOURCE_FILE (old) = 0;
101650503Sobrien          }
101750503Sobrien      }
101850503Sobrien#endif
101918334Speter
102050503Sobrien  /* We must do some computations even when not actually shortening, in
102150503Sobrien     order to get the alignment information for the labels.  */
102250503Sobrien
102350503Sobrien  init_insn_lengths ();
102450503Sobrien
102550503Sobrien  /* Compute maximum UID and allocate label_align / uid_shuid.  */
102650503Sobrien  max_uid = get_max_uid ();
102750503Sobrien
102850503Sobrien  max_labelno = max_label_num ();
102950503Sobrien  min_labelno = get_first_label_num ();
103050503Sobrien  label_align = (struct label_alignment *) xmalloc (
103150503Sobrien    (max_labelno - min_labelno + 1) * sizeof (struct label_alignment));
103250503Sobrien  bzero ((char *) label_align,
103350503Sobrien    (max_labelno - min_labelno + 1) * sizeof (struct label_alignment));
103450503Sobrien
103550503Sobrien  uid_shuid = (int *) xmalloc (max_uid * sizeof *uid_shuid);
103650503Sobrien
103750503Sobrien  /* Initialize label_align and set up uid_shuid to be strictly
103850503Sobrien     monotonically rising with insn order.  */
103950503Sobrien  /* We use max_log here to keep track of the maximum alignment we want to
104050503Sobrien     impose on the next CODE_LABEL (or the current one if we are processing
104150503Sobrien     the CODE_LABEL itself).  */
104250503Sobrien
104350503Sobrien  max_log = 0;
104450503Sobrien  max_skip = 0;
104550503Sobrien
104650503Sobrien  for (insn = get_insns (), i = 1; insn; insn = NEXT_INSN (insn))
104750503Sobrien    {
104850503Sobrien      int log;
104950503Sobrien
105050503Sobrien      INSN_SHUID (insn) = i++;
105150503Sobrien      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
105250503Sobrien	{
105350503Sobrien	  /* reorg might make the first insn of a loop being run once only,
105450503Sobrien             and delete the label in front of it.  Then we want to apply
105550503Sobrien             the loop alignment to the new label created by reorg, which
105650503Sobrien             is separated by the former loop start insn from the
105750503Sobrien	     NOTE_INSN_LOOP_BEG.  */
105850503Sobrien	}
105950503Sobrien      else if (GET_CODE (insn) == CODE_LABEL)
106050503Sobrien	{
106150503Sobrien	  rtx next;
106250503Sobrien
106350503Sobrien	  log = LABEL_ALIGN (insn);
106450503Sobrien	  if (max_log < log)
106550503Sobrien	    {
106650503Sobrien	      max_log = log;
106750503Sobrien	      max_skip = LABEL_ALIGN_MAX_SKIP;
106850503Sobrien	    }
106950503Sobrien	  next = NEXT_INSN (insn);
107050503Sobrien	  /* ADDR_VECs only take room if read-only data goes into the text
107150503Sobrien	     section.  */
107250503Sobrien	  if (JUMP_TABLES_IN_TEXT_SECTION
107350503Sobrien#if !defined(READONLY_DATA_SECTION)
107450503Sobrien	      || 1
107550503Sobrien#endif
107650503Sobrien	      )
107750503Sobrien	    if (next && GET_CODE (next) == JUMP_INSN)
107850503Sobrien	      {
107950503Sobrien		rtx nextbody = PATTERN (next);
108050503Sobrien		if (GET_CODE (nextbody) == ADDR_VEC
108150503Sobrien		    || GET_CODE (nextbody) == ADDR_DIFF_VEC)
108250503Sobrien		  {
108350503Sobrien		    log = ADDR_VEC_ALIGN (next);
108450503Sobrien		    if (max_log < log)
108550503Sobrien		      {
108650503Sobrien			max_log = log;
108750503Sobrien			max_skip = LABEL_ALIGN_MAX_SKIP;
108850503Sobrien		      }
108950503Sobrien		  }
109050503Sobrien	      }
109150503Sobrien	  LABEL_TO_ALIGNMENT (insn) = max_log;
109250503Sobrien	  LABEL_TO_MAX_SKIP (insn) = max_skip;
109350503Sobrien	  max_log = 0;
109450503Sobrien	  max_skip = 0;
109550503Sobrien	}
109650503Sobrien      else if (GET_CODE (insn) == BARRIER)
109750503Sobrien	{
109850503Sobrien	  rtx label;
109950503Sobrien
110050503Sobrien	  for (label = insn; label && GET_RTX_CLASS (GET_CODE (label)) != 'i';
110150503Sobrien	       label = NEXT_INSN (label))
110250503Sobrien	    if (GET_CODE (label) == CODE_LABEL)
110350503Sobrien	      {
110450503Sobrien		log = LABEL_ALIGN_AFTER_BARRIER (insn);
110550503Sobrien		if (max_log < log)
110650503Sobrien		  {
110750503Sobrien		    max_log = log;
110850503Sobrien		    max_skip = LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP;
110950503Sobrien		  }
111050503Sobrien		break;
111150503Sobrien	      }
111250503Sobrien	}
111350503Sobrien      /* Again, we allow NOTE_INSN_LOOP_BEG - INSN - CODE_LABEL
111450503Sobrien	 sequences in order to handle reorg output efficiently.  */
111550503Sobrien      else if (GET_CODE (insn) == NOTE
111650503Sobrien	       && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
111750503Sobrien	{
111850503Sobrien	  rtx label;
111950503Sobrien
112050503Sobrien	  for (label = insn; label; label = NEXT_INSN (label))
112150503Sobrien	    if (GET_CODE (label) == CODE_LABEL)
112250503Sobrien	      {
112350503Sobrien		log = LOOP_ALIGN (insn);
112450503Sobrien		if (max_log < log)
112550503Sobrien		  {
112650503Sobrien		    max_log = log;
112750503Sobrien		    max_skip = LOOP_ALIGN_MAX_SKIP;
112850503Sobrien		  }
112950503Sobrien		break;
113050503Sobrien	      }
113150503Sobrien	}
113250503Sobrien      else
113350503Sobrien	continue;
113450503Sobrien    }
113550503Sobrien#ifdef HAVE_ATTR_length
113650503Sobrien
113750503Sobrien  /* Allocate the rest of the arrays.  */
113850503Sobrien  insn_lengths = (short *) xmalloc (max_uid * sizeof (short));
113950503Sobrien  insn_addresses = (int *) xmalloc (max_uid * sizeof (int));
114050503Sobrien  /* Syntax errors can lead to labels being outside of the main insn stream.
114150503Sobrien     Initialize insn_addresses, so that we get reproducible results.  */
114250503Sobrien  bzero ((char *)insn_addresses, max_uid * sizeof *insn_addresses);
114350503Sobrien  uid_align = (rtx *) xmalloc (max_uid * sizeof *uid_align);
114450503Sobrien
114550503Sobrien  varying_length = (char *) xmalloc (max_uid * sizeof (char));
114650503Sobrien
114750503Sobrien  bzero (varying_length, max_uid);
114850503Sobrien
114950503Sobrien  /* Initialize uid_align.  We scan instructions
115050503Sobrien     from end to start, and keep in align_tab[n] the last seen insn
115150503Sobrien     that does an alignment of at least n+1, i.e. the successor
115250503Sobrien     in the alignment chain for an insn that does / has a known
115350503Sobrien     alignment of n.  */
115450503Sobrien
115550503Sobrien  bzero ((char *) uid_align, max_uid * sizeof *uid_align);
115650503Sobrien
115750503Sobrien  for (i = MAX_CODE_ALIGN; --i >= 0; )
115850503Sobrien    align_tab[i] = NULL_RTX;
115950503Sobrien  seq = get_last_insn ();
116050503Sobrien  for (; seq; seq = PREV_INSN (seq))
116150503Sobrien    {
116250503Sobrien      int uid = INSN_UID (seq);
116350503Sobrien      int log;
116450503Sobrien      log = (GET_CODE (seq) == CODE_LABEL ? LABEL_TO_ALIGNMENT (seq) : 0);
116550503Sobrien      uid_align[uid] = align_tab[0];
116650503Sobrien      if (log)
116750503Sobrien	{
116850503Sobrien	  /* Found an alignment label.  */
116950503Sobrien	  uid_align[uid] = align_tab[log];
117050503Sobrien	  for (i = log - 1; i >= 0; i--)
117150503Sobrien	    align_tab[i] = seq;
117250503Sobrien	}
117350503Sobrien    }
117450503Sobrien#ifdef CASE_VECTOR_SHORTEN_MODE
117550503Sobrien  if (optimize)
117650503Sobrien    {
117750503Sobrien      /* Look for ADDR_DIFF_VECs, and initialize their minimum and maximum
117850503Sobrien         label fields.  */
117950503Sobrien
118050503Sobrien      int min_shuid = INSN_SHUID (get_insns ()) - 1;
118150503Sobrien      int max_shuid = INSN_SHUID (get_last_insn ()) + 1;
118250503Sobrien      int rel;
118350503Sobrien
118450503Sobrien      for (insn = first; insn != 0; insn = NEXT_INSN (insn))
118550503Sobrien	{
118650503Sobrien	  rtx min_lab = NULL_RTX, max_lab = NULL_RTX, pat;
118750503Sobrien	  int len, i, min, max, insn_shuid;
118850503Sobrien	  int min_align;
118950503Sobrien	  addr_diff_vec_flags flags;
119050503Sobrien
119150503Sobrien	  if (GET_CODE (insn) != JUMP_INSN
119250503Sobrien	      || GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC)
119350503Sobrien	    continue;
119450503Sobrien	  pat = PATTERN (insn);
119550503Sobrien	  len = XVECLEN (pat, 1);
119650503Sobrien	  if (len <= 0)
119750503Sobrien	    abort ();
119850503Sobrien	  min_align = MAX_CODE_ALIGN;
119950503Sobrien	  for (min = max_shuid, max = min_shuid, i = len - 1; i >= 0; i--)
120050503Sobrien	    {
120150503Sobrien	      rtx lab = XEXP (XVECEXP (pat, 1, i), 0);
120250503Sobrien	      int shuid = INSN_SHUID (lab);
120350503Sobrien	      if (shuid < min)
120450503Sobrien		{
120550503Sobrien		  min = shuid;
120650503Sobrien		  min_lab = lab;
120750503Sobrien		}
120850503Sobrien	      if (shuid > max)
120950503Sobrien		{
121050503Sobrien		  max = shuid;
121150503Sobrien		  max_lab = lab;
121250503Sobrien		}
121350503Sobrien	      if (min_align > LABEL_TO_ALIGNMENT (lab))
121450503Sobrien		min_align = LABEL_TO_ALIGNMENT (lab);
121550503Sobrien	    }
121650503Sobrien	  XEXP (pat, 2) = gen_rtx_LABEL_REF (VOIDmode, min_lab);
121750503Sobrien	  XEXP (pat, 3) = gen_rtx_LABEL_REF (VOIDmode, max_lab);
121850503Sobrien	  insn_shuid = INSN_SHUID (insn);
121950503Sobrien	  rel = INSN_SHUID (XEXP (XEXP (pat, 0), 0));
122050503Sobrien	  flags.min_align = min_align;
122150503Sobrien	  flags.base_after_vec = rel > insn_shuid;
122250503Sobrien	  flags.min_after_vec  = min > insn_shuid;
122350503Sobrien	  flags.max_after_vec  = max > insn_shuid;
122450503Sobrien	  flags.min_after_base = min > rel;
122550503Sobrien	  flags.max_after_base = max > rel;
122650503Sobrien	  ADDR_DIFF_VEC_FLAGS (pat) = flags;
122750503Sobrien	}
122850503Sobrien    }
122950503Sobrien#endif /* CASE_VECTOR_SHORTEN_MODE */
123050503Sobrien
123150503Sobrien
123218334Speter  /* Compute initial lengths, addresses, and varying flags for each insn.  */
123318334Speter  for (insn_current_address = FIRST_INSN_ADDRESS, insn = first;
123418334Speter       insn != 0;
123518334Speter       insn_current_address += insn_lengths[uid], insn = NEXT_INSN (insn))
123618334Speter    {
123718334Speter      uid = INSN_UID (insn);
123850503Sobrien
123950503Sobrien      insn_lengths[uid] = 0;
124050503Sobrien
124150503Sobrien      if (GET_CODE (insn) == CODE_LABEL)
124250503Sobrien	{
124350503Sobrien	  int log = LABEL_TO_ALIGNMENT (insn);
124450503Sobrien	  if (log)
124550503Sobrien	    {
124650503Sobrien	      int align = 1 << log;
124750503Sobrien	      int new_address = (insn_current_address + align - 1) & -align;
124850503Sobrien	      insn_lengths[uid] = new_address - insn_current_address;
124950503Sobrien	      insn_current_address = new_address;
125050503Sobrien	    }
125150503Sobrien	}
125250503Sobrien
125318334Speter      insn_addresses[uid] = insn_current_address;
125418334Speter
125518334Speter      if (GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER
125618334Speter	  || GET_CODE (insn) == CODE_LABEL)
125718334Speter	continue;
125850503Sobrien      if (INSN_DELETED_P (insn))
125950503Sobrien	continue;
126018334Speter
126118334Speter      body = PATTERN (insn);
126218334Speter      if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
126318334Speter	{
126418334Speter	  /* This only takes room if read-only data goes into the text
126518334Speter	     section.  */
126650503Sobrien	  if (JUMP_TABLES_IN_TEXT_SECTION
126750503Sobrien#if !defined(READONLY_DATA_SECTION)
126850503Sobrien	      || 1
126918334Speter#endif
127050503Sobrien	      )
127150503Sobrien	    insn_lengths[uid] = (XVECLEN (body,
127250503Sobrien					  GET_CODE (body) == ADDR_DIFF_VEC)
127350503Sobrien				 * GET_MODE_SIZE (GET_MODE (body)));
127450503Sobrien	  /* Alignment is handled by ADDR_VEC_ALIGN.  */
127518334Speter	}
127618334Speter      else if (asm_noperands (body) >= 0)
127718334Speter	insn_lengths[uid] = asm_insn_count (body) * insn_default_length (insn);
127818334Speter      else if (GET_CODE (body) == SEQUENCE)
127918334Speter	{
128018334Speter	  int i;
128118334Speter	  int const_delay_slots;
128218334Speter#ifdef DELAY_SLOTS
128318334Speter	  const_delay_slots = const_num_delay_slots (XVECEXP (body, 0, 0));
128418334Speter#else
128518334Speter	  const_delay_slots = 0;
128618334Speter#endif
128718334Speter	  /* Inside a delay slot sequence, we do not do any branch shortening
128818334Speter	     if the shortening could change the number of delay slots
128950503Sobrien	     of the branch.  */
129018334Speter	  for (i = 0; i < XVECLEN (body, 0); i++)
129118334Speter	    {
129218334Speter	      rtx inner_insn = XVECEXP (body, 0, i);
129318334Speter	      int inner_uid = INSN_UID (inner_insn);
129418334Speter	      int inner_length;
129518334Speter
129618334Speter	      if (asm_noperands (PATTERN (XVECEXP (body, 0, i))) >= 0)
129718334Speter		inner_length = (asm_insn_count (PATTERN (inner_insn))
129818334Speter				* insn_default_length (inner_insn));
129918334Speter	      else
130018334Speter		inner_length = insn_default_length (inner_insn);
130118334Speter
130218334Speter	      insn_lengths[inner_uid] = inner_length;
130318334Speter	      if (const_delay_slots)
130418334Speter		{
130518334Speter		  if ((varying_length[inner_uid]
130618334Speter		       = insn_variable_length_p (inner_insn)) != 0)
130718334Speter		    varying_length[uid] = 1;
130818334Speter		  insn_addresses[inner_uid] = (insn_current_address +
130918334Speter					       insn_lengths[uid]);
131018334Speter		}
131118334Speter	      else
131218334Speter		varying_length[inner_uid] = 0;
131318334Speter	      insn_lengths[uid] += inner_length;
131418334Speter	    }
131518334Speter	}
131618334Speter      else if (GET_CODE (body) != USE && GET_CODE (body) != CLOBBER)
131718334Speter	{
131818334Speter	  insn_lengths[uid] = insn_default_length (insn);
131918334Speter	  varying_length[uid] = insn_variable_length_p (insn);
132018334Speter	}
132118334Speter
132218334Speter      /* If needed, do any adjustment.  */
132318334Speter#ifdef ADJUST_INSN_LENGTH
132418334Speter      ADJUST_INSN_LENGTH (insn, insn_lengths[uid]);
132518334Speter#endif
132618334Speter    }
132718334Speter
132818334Speter  /* Now loop over all the insns finding varying length insns.  For each,
132918334Speter     get the current insn length.  If it has changed, reflect the change.
133018334Speter     When nothing changes for a full pass, we are done.  */
133118334Speter
133218334Speter  while (something_changed)
133318334Speter    {
133418334Speter      something_changed = 0;
133550503Sobrien      insn_current_align = MAX_CODE_ALIGN - 1;
133618334Speter      for (insn_current_address = FIRST_INSN_ADDRESS, insn = first;
133718334Speter	   insn != 0;
133818334Speter	   insn = NEXT_INSN (insn))
133918334Speter	{
134018334Speter	  int new_length;
134150503Sobrien#ifdef ADJUST_INSN_LENGTH
134218334Speter	  int tmp_length;
134350503Sobrien#endif
134450503Sobrien	  int length_align;
134518334Speter
134618334Speter	  uid = INSN_UID (insn);
134750503Sobrien
134850503Sobrien	  if (GET_CODE (insn) == CODE_LABEL)
134950503Sobrien	    {
135050503Sobrien	      int log = LABEL_TO_ALIGNMENT (insn);
135150503Sobrien	      if (log > insn_current_align)
135250503Sobrien		{
135350503Sobrien		  int align = 1 << log;
135450503Sobrien		  int new_address= (insn_current_address + align - 1) & -align;
135550503Sobrien		  insn_lengths[uid] = new_address - insn_current_address;
135650503Sobrien		  insn_current_align = log;
135750503Sobrien		  insn_current_address = new_address;
135850503Sobrien		}
135950503Sobrien	      else
136050503Sobrien		insn_lengths[uid] = 0;
136150503Sobrien	      insn_addresses[uid] = insn_current_address;
136250503Sobrien	      continue;
136350503Sobrien	    }
136450503Sobrien
136550503Sobrien	  length_align = INSN_LENGTH_ALIGNMENT (insn);
136650503Sobrien	  if (length_align < insn_current_align)
136750503Sobrien	    insn_current_align = length_align;
136850503Sobrien
136950503Sobrien	  insn_last_address = insn_addresses[uid];
137018334Speter	  insn_addresses[uid] = insn_current_address;
137150503Sobrien
137250503Sobrien#ifdef CASE_VECTOR_SHORTEN_MODE
137350503Sobrien	  if (optimize && GET_CODE (insn) == JUMP_INSN
137450503Sobrien	      && GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
137518334Speter	    {
137650503Sobrien	      rtx body = PATTERN (insn);
137750503Sobrien	      int old_length = insn_lengths[uid];
137850503Sobrien	      rtx rel_lab = XEXP (XEXP (body, 0), 0);
137950503Sobrien	      rtx min_lab = XEXP (XEXP (body, 2), 0);
138050503Sobrien	      rtx max_lab = XEXP (XEXP (body, 3), 0);
138150503Sobrien	      addr_diff_vec_flags flags = ADDR_DIFF_VEC_FLAGS (body);
138250503Sobrien	      int rel_addr = insn_addresses[INSN_UID (rel_lab)];
138350503Sobrien	      int min_addr = insn_addresses[INSN_UID (min_lab)];
138450503Sobrien	      int max_addr = insn_addresses[INSN_UID (max_lab)];
138550503Sobrien	      rtx prev;
138650503Sobrien	      int rel_align = 0;
138750503Sobrien
138850503Sobrien	      /* Try to find a known alignment for rel_lab.  */
138950503Sobrien	      for (prev = rel_lab;
139050503Sobrien		   prev
139150503Sobrien		   && ! insn_lengths[INSN_UID (prev)]
139250503Sobrien		   && ! (varying_length[INSN_UID (prev)] & 1);
139350503Sobrien		   prev = PREV_INSN (prev))
139450503Sobrien		if (varying_length[INSN_UID (prev)] & 2)
139550503Sobrien		  {
139650503Sobrien		    rel_align = LABEL_TO_ALIGNMENT (prev);
139750503Sobrien		    break;
139850503Sobrien		  }
139950503Sobrien
140050503Sobrien	      /* See the comment on addr_diff_vec_flags in rtl.h for the
140150503Sobrien		 meaning of the flags values.  base: REL_LAB   vec: INSN  */
140250503Sobrien	      /* Anything after INSN has still addresses from the last
140350503Sobrien		 pass; adjust these so that they reflect our current
140450503Sobrien		 estimate for this pass.  */
140550503Sobrien	      if (flags.base_after_vec)
140650503Sobrien		rel_addr += insn_current_address - insn_last_address;
140750503Sobrien	      if (flags.min_after_vec)
140850503Sobrien		min_addr += insn_current_address - insn_last_address;
140950503Sobrien	      if (flags.max_after_vec)
141050503Sobrien		max_addr += insn_current_address - insn_last_address;
141150503Sobrien	      /* We want to know the worst case, i.e. lowest possible value
141250503Sobrien		 for the offset of MIN_LAB.  If MIN_LAB is after REL_LAB,
141350503Sobrien		 its offset is positive, and we have to be wary of code shrink;
141450503Sobrien		 otherwise, it is negative, and we have to be vary of code
141550503Sobrien		 size increase.  */
141650503Sobrien	      if (flags.min_after_base)
141750503Sobrien		{
141850503Sobrien		  /* If INSN is between REL_LAB and MIN_LAB, the size
141950503Sobrien		     changes we are about to make can change the alignment
142050503Sobrien		     within the observed offset, therefore we have to break
142150503Sobrien		     it up into two parts that are independent.  */
142250503Sobrien		  if (! flags.base_after_vec && flags.min_after_vec)
142350503Sobrien		    {
142450503Sobrien		      min_addr -= align_fuzz (rel_lab, insn, rel_align, 0);
142550503Sobrien		      min_addr -= align_fuzz (insn, min_lab, 0, 0);
142650503Sobrien		    }
142750503Sobrien		  else
142850503Sobrien		    min_addr -= align_fuzz (rel_lab, min_lab, rel_align, 0);
142950503Sobrien		}
143050503Sobrien	      else
143150503Sobrien		{
143250503Sobrien		  if (flags.base_after_vec && ! flags.min_after_vec)
143350503Sobrien		    {
143450503Sobrien		      min_addr -= align_fuzz (min_lab, insn, 0, ~0);
143550503Sobrien		      min_addr -= align_fuzz (insn, rel_lab, 0, ~0);
143650503Sobrien		    }
143750503Sobrien		  else
143850503Sobrien		    min_addr -= align_fuzz (min_lab, rel_lab, 0, ~0);
143950503Sobrien		}
144050503Sobrien	      /* Likewise, determine the highest lowest possible value
144150503Sobrien		 for the offset of MAX_LAB.  */
144250503Sobrien	      if (flags.max_after_base)
144350503Sobrien		{
144450503Sobrien		  if (! flags.base_after_vec && flags.max_after_vec)
144550503Sobrien		    {
144650503Sobrien		      max_addr += align_fuzz (rel_lab, insn, rel_align, ~0);
144750503Sobrien		      max_addr += align_fuzz (insn, max_lab, 0, ~0);
144850503Sobrien		    }
144950503Sobrien		  else
145050503Sobrien		    max_addr += align_fuzz (rel_lab, max_lab, rel_align, ~0);
145150503Sobrien		}
145250503Sobrien	      else
145350503Sobrien		{
145450503Sobrien		  if (flags.base_after_vec && ! flags.max_after_vec)
145550503Sobrien		    {
145650503Sobrien		      max_addr += align_fuzz (max_lab, insn, 0, 0);
145750503Sobrien		      max_addr += align_fuzz (insn, rel_lab, 0, 0);
145850503Sobrien		    }
145950503Sobrien		  else
146050503Sobrien		    max_addr += align_fuzz (max_lab, rel_lab, 0, 0);
146150503Sobrien		}
146250503Sobrien	      PUT_MODE (body, CASE_VECTOR_SHORTEN_MODE (min_addr - rel_addr,
146350503Sobrien							max_addr - rel_addr,
146450503Sobrien							body));
146550503Sobrien	      if (JUMP_TABLES_IN_TEXT_SECTION
146650503Sobrien#if !defined(READONLY_DATA_SECTION)
146750503Sobrien		  || 1
146850503Sobrien#endif
146950503Sobrien		  )
147050503Sobrien		{
147150503Sobrien		  insn_lengths[uid]
147250503Sobrien		    = (XVECLEN (body, 1) * GET_MODE_SIZE (GET_MODE (body)));
147350503Sobrien		  insn_current_address += insn_lengths[uid];
147450503Sobrien		  if (insn_lengths[uid] != old_length)
147550503Sobrien		    something_changed = 1;
147650503Sobrien		}
147750503Sobrien
147850503Sobrien	      continue;
147950503Sobrien	    }
148050503Sobrien#endif /* CASE_VECTOR_SHORTEN_MODE */
148150503Sobrien
148250503Sobrien	  if (! (varying_length[uid]))
148350503Sobrien	    {
148418334Speter	      insn_current_address += insn_lengths[uid];
148518334Speter	      continue;
148618334Speter	    }
148718334Speter	  if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE)
148818334Speter	    {
148918334Speter	      int i;
149018334Speter
149118334Speter	      body = PATTERN (insn);
149218334Speter	      new_length = 0;
149318334Speter	      for (i = 0; i < XVECLEN (body, 0); i++)
149418334Speter		{
149518334Speter		  rtx inner_insn = XVECEXP (body, 0, i);
149618334Speter		  int inner_uid = INSN_UID (inner_insn);
149718334Speter		  int inner_length;
149818334Speter
149918334Speter		  insn_addresses[inner_uid] = insn_current_address;
150018334Speter
150118334Speter		  /* insn_current_length returns 0 for insns with a
150218334Speter		     non-varying length.  */
150318334Speter		  if (! varying_length[inner_uid])
150418334Speter		    inner_length = insn_lengths[inner_uid];
150518334Speter		  else
150618334Speter		    inner_length = insn_current_length (inner_insn);
150718334Speter
150818334Speter		  if (inner_length != insn_lengths[inner_uid])
150918334Speter		    {
151018334Speter		      insn_lengths[inner_uid] = inner_length;
151118334Speter		      something_changed = 1;
151218334Speter		    }
151318334Speter		  insn_current_address += insn_lengths[inner_uid];
151418334Speter		  new_length += inner_length;
151518334Speter		}
151618334Speter	    }
151718334Speter	  else
151818334Speter	    {
151918334Speter	      new_length = insn_current_length (insn);
152018334Speter	      insn_current_address += new_length;
152118334Speter	    }
152218334Speter
152318334Speter#ifdef ADJUST_INSN_LENGTH
152418334Speter	  /* If needed, do any adjustment.  */
152518334Speter	  tmp_length = new_length;
152618334Speter	  ADJUST_INSN_LENGTH (insn, new_length);
152718334Speter	  insn_current_address += (new_length - tmp_length);
152818334Speter#endif
152918334Speter
153018334Speter	  if (new_length != insn_lengths[uid])
153118334Speter	    {
153218334Speter	      insn_lengths[uid] = new_length;
153318334Speter	      something_changed = 1;
153418334Speter	    }
153518334Speter	}
153618334Speter      /* For a non-optimizing compile, do only a single pass.  */
153718334Speter      if (!optimize)
153818334Speter	break;
153918334Speter    }
154050503Sobrien
154150503Sobrien  free (varying_length);
154250503Sobrien
154318334Speter#endif /* HAVE_ATTR_length */
154418334Speter}
154518334Speter
154618334Speter#ifdef HAVE_ATTR_length
154718334Speter/* Given the body of an INSN known to be generated by an ASM statement, return
154818334Speter   the number of machine instructions likely to be generated for this insn.
154918334Speter   This is used to compute its length.  */
155018334Speter
155118334Speterstatic int
155218334Speterasm_insn_count (body)
155318334Speter     rtx body;
155418334Speter{
155518334Speter  char *template;
155618334Speter  int count = 1;
155718334Speter
155818334Speter  if (GET_CODE (body) == ASM_INPUT)
155918334Speter    template = XSTR (body, 0);
156018334Speter  else
156118334Speter    template = decode_asm_operands (body, NULL_PTR, NULL_PTR,
156218334Speter				    NULL_PTR, NULL_PTR);
156318334Speter
156418334Speter  for ( ; *template; template++)
156518334Speter    if (IS_ASM_LOGICAL_LINE_SEPARATOR(*template) || *template == '\n')
156618334Speter      count++;
156718334Speter
156818334Speter  return count;
156918334Speter}
157018334Speter#endif
157118334Speter
157218334Speter/* Output assembler code for the start of a function,
157318334Speter   and initialize some of the variables in this file
157418334Speter   for the new function.  The label for the function and associated
157518334Speter   assembler pseudo-ops have already been output in `assemble_start_function'.
157618334Speter
157718334Speter   FIRST is the first insn of the rtl for the function being compiled.
157818334Speter   FILE is the file to write assembler code to.
157918334Speter   OPTIMIZE is nonzero if we should eliminate redundant
158018334Speter     test and compare insns.  */
158118334Speter
158218334Spetervoid
158318334Speterfinal_start_function (first, file, optimize)
158418334Speter     rtx first;
158518334Speter     FILE *file;
158618334Speter     int optimize;
158718334Speter{
158818334Speter  block_depth = 0;
158918334Speter
159018334Speter  this_is_asm_operands = 0;
159118334Speter
159218334Speter#ifdef NON_SAVING_SETJMP
159318334Speter  /* A function that calls setjmp should save and restore all the
159418334Speter     call-saved registers on a system where longjmp clobbers them.  */
159518334Speter  if (NON_SAVING_SETJMP && current_function_calls_setjmp)
159618334Speter    {
159718334Speter      int i;
159818334Speter
159918334Speter      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
160018334Speter	if (!call_used_regs[i] && !call_fixed_regs[i])
160118334Speter	  regs_ever_live[i] = 1;
160218334Speter    }
160318334Speter#endif
160418334Speter
160518334Speter  /* Initial line number is supposed to be output
160618334Speter     before the function's prologue and label
160718334Speter     so that the function's address will not appear to be
160818334Speter     in the last statement of the preceding function.  */
160918334Speter  if (NOTE_LINE_NUMBER (first) != NOTE_INSN_DELETED)
161018334Speter    last_linenum = high_block_linenum = high_function_linenum
161118334Speter      = NOTE_LINE_NUMBER (first);
161218334Speter
161350503Sobrien#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
161450503Sobrien  /* Output DWARF definition of the function.  */
161550503Sobrien  if (dwarf2out_do_frame ())
161650503Sobrien    dwarf2out_begin_prologue ();
161750503Sobrien#endif
161850503Sobrien
161918334Speter  /* For SDB and XCOFF, the function beginning must be marked between
162018334Speter     the function label and the prologue.  We always need this, even when
162118334Speter     -g1 was used.  Defer on MIPS systems so that parameter descriptions
162250503Sobrien     follow function entry.  */
162318334Speter#if defined(SDB_DEBUGGING_INFO) && !defined(MIPS_DEBUGGING_INFO)
162418334Speter  if (write_symbols == SDB_DEBUG)
162518334Speter    sdbout_begin_function (last_linenum);
162618334Speter  else
162718334Speter#endif
162818334Speter#ifdef XCOFF_DEBUGGING_INFO
162918334Speter    if (write_symbols == XCOFF_DEBUG)
163018334Speter      xcoffout_begin_function (file, last_linenum);
163118334Speter    else
163218334Speter#endif
163318334Speter      /* But only output line number for other debug info types if -g2
163418334Speter	 or better.  */
163518334Speter      if (NOTE_LINE_NUMBER (first) != NOTE_INSN_DELETED)
163618334Speter	output_source_line (file, first);
163718334Speter
163818334Speter#ifdef LEAF_REG_REMAP
163918334Speter  if (leaf_function)
164018334Speter    leaf_renumber_regs (first);
164118334Speter#endif
164218334Speter
164318347Speter  if (profile_block_flag)
164418347Speter    add_bb (file);
164518347Speter
164618334Speter  /* The Sun386i and perhaps other machines don't work right
164718334Speter     if the profiling code comes after the prologue.  */
164818334Speter#ifdef PROFILE_BEFORE_PROLOGUE
164918334Speter  if (profile_flag)
165018334Speter    profile_function (file);
165118334Speter#endif /* PROFILE_BEFORE_PROLOGUE */
165218334Speter
165350503Sobrien#if defined (DWARF2_UNWIND_INFO) && defined (HAVE_prologue)
165450503Sobrien  if (dwarf2out_do_frame ())
165550503Sobrien    dwarf2out_frame_debug (NULL_RTX);
165650503Sobrien#endif
165750503Sobrien
165818334Speter#ifdef FUNCTION_PROLOGUE
165918334Speter  /* First output the function prologue: code to set up the stack frame.  */
166018334Speter  FUNCTION_PROLOGUE (file, get_frame_size ());
166118334Speter#endif
166218334Speter
166318334Speter#if defined (SDB_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
166418334Speter  if (write_symbols == SDB_DEBUG || write_symbols == XCOFF_DEBUG)
166518334Speter    next_block_index = 1;
166618334Speter#endif
166718334Speter
166818334Speter  /* If the machine represents the prologue as RTL, the profiling code must
166918334Speter     be emitted when NOTE_INSN_PROLOGUE_END is scanned.  */
167018334Speter#ifdef HAVE_prologue
167118334Speter  if (! HAVE_prologue)
167218334Speter#endif
167318334Speter    profile_after_prologue (file);
167418334Speter
167518334Speter  profile_label_no++;
167618334Speter
167718334Speter  /* If we are doing basic block profiling, remember a printable version
167818334Speter     of the function name.  */
167918334Speter  if (profile_block_flag)
168018334Speter    {
168150503Sobrien      bb_func_label_num
168250503Sobrien	= add_bb_string ((*decl_printable_name) (current_function_decl, 2), FALSE);
168318334Speter    }
168418334Speter}
168518334Speter
168618334Speterstatic void
168718334Speterprofile_after_prologue (file)
168818334Speter     FILE *file;
168918334Speter{
169018334Speter#ifdef FUNCTION_BLOCK_PROFILER
169118334Speter  if (profile_block_flag)
169218334Speter    {
169350503Sobrien      FUNCTION_BLOCK_PROFILER (file, count_basic_blocks);
169418334Speter    }
169518334Speter#endif /* FUNCTION_BLOCK_PROFILER */
169618334Speter
169718334Speter#ifndef PROFILE_BEFORE_PROLOGUE
169818334Speter  if (profile_flag)
169918334Speter    profile_function (file);
170018334Speter#endif /* not PROFILE_BEFORE_PROLOGUE */
170118334Speter}
170218334Speter
170318334Speterstatic void
170418334Speterprofile_function (file)
170518334Speter     FILE *file;
170618334Speter{
170718347Speter#ifndef NO_PROFILE_DATA
170850503Sobrien  int align = MIN (BIGGEST_ALIGNMENT, LONG_TYPE_SIZE);
170918347Speter#endif /* not NO_PROFILE_DATA */
171050503Sobrien#if defined(ASM_OUTPUT_REG_PUSH)
171150503Sobrien#if defined(STRUCT_VALUE_INCOMING_REGNUM) || defined(STRUCT_VALUE_REGNUM)
171218334Speter  int sval = current_function_returns_struct;
171350503Sobrien#endif
171450503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) || defined(STATIC_CHAIN_REGNUM)
171518334Speter  int cxt = current_function_needs_context;
171650503Sobrien#endif
171750503Sobrien#endif /* ASM_OUTPUT_REG_PUSH */
171818334Speter
171918347Speter#ifndef NO_PROFILE_DATA
172018334Speter  data_section ();
172118334Speter  ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
172218334Speter  ASM_OUTPUT_INTERNAL_LABEL (file, "LP", profile_label_no);
172350503Sobrien  assemble_integer (const0_rtx, LONG_TYPE_SIZE / BITS_PER_UNIT, 1);
172418347Speter#endif /* not NO_PROFILE_DATA */
172518334Speter
172650503Sobrien  function_section (current_function_decl);
172718334Speter
172850503Sobrien#if defined(STRUCT_VALUE_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
172918334Speter  if (sval)
173018334Speter    ASM_OUTPUT_REG_PUSH (file, STRUCT_VALUE_INCOMING_REGNUM);
173118334Speter#else
173250503Sobrien#if defined(STRUCT_VALUE_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
173318334Speter  if (sval)
173450503Sobrien    {
173550503Sobrien      ASM_OUTPUT_REG_PUSH (file, STRUCT_VALUE_REGNUM);
173650503Sobrien    }
173718334Speter#endif
173818334Speter#endif
173918334Speter
174050503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
174118334Speter  if (cxt)
174218334Speter    ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_INCOMING_REGNUM);
174318334Speter#else
174450503Sobrien#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
174518334Speter  if (cxt)
174650503Sobrien    {
174750503Sobrien      ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_REGNUM);
174850503Sobrien    }
174918334Speter#endif
175018334Speter#endif
175118334Speter
175218334Speter  FUNCTION_PROFILER (file, profile_label_no);
175318334Speter
175450503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
175518334Speter  if (cxt)
175618334Speter    ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_INCOMING_REGNUM);
175718334Speter#else
175850503Sobrien#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
175918334Speter  if (cxt)
176050503Sobrien    {
176150503Sobrien      ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_REGNUM);
176250503Sobrien    }
176318334Speter#endif
176418334Speter#endif
176518334Speter
176650503Sobrien#if defined(STRUCT_VALUE_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
176718334Speter  if (sval)
176818334Speter    ASM_OUTPUT_REG_POP (file, STRUCT_VALUE_INCOMING_REGNUM);
176918334Speter#else
177050503Sobrien#if defined(STRUCT_VALUE_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
177118334Speter  if (sval)
177250503Sobrien    {
177350503Sobrien      ASM_OUTPUT_REG_POP (file, STRUCT_VALUE_REGNUM);
177450503Sobrien    }
177518334Speter#endif
177618334Speter#endif
177718334Speter}
177818334Speter
177918334Speter/* Output assembler code for the end of a function.
178018334Speter   For clarity, args are same as those of `final_start_function'
178118334Speter   even though not all of them are needed.  */
178218334Speter
178318334Spetervoid
178418334Speterfinal_end_function (first, file, optimize)
178518334Speter     rtx first;
178618334Speter     FILE *file;
178718334Speter     int optimize;
178818334Speter{
178918334Speter  if (app_on)
179018334Speter    {
179150503Sobrien      fputs (ASM_APP_OFF, file);
179218334Speter      app_on = 0;
179318334Speter    }
179418334Speter
179518334Speter#ifdef SDB_DEBUGGING_INFO
179618334Speter  if (write_symbols == SDB_DEBUG)
179718334Speter    sdbout_end_function (high_function_linenum);
179818334Speter#endif
179918334Speter
180018334Speter#ifdef DWARF_DEBUGGING_INFO
180118334Speter  if (write_symbols == DWARF_DEBUG)
180218334Speter    dwarfout_end_function ();
180318334Speter#endif
180418334Speter
180518334Speter#ifdef XCOFF_DEBUGGING_INFO
180618334Speter  if (write_symbols == XCOFF_DEBUG)
180718334Speter    xcoffout_end_function (file, high_function_linenum);
180818334Speter#endif
180918334Speter
181018334Speter#ifdef FUNCTION_EPILOGUE
181118334Speter  /* Finally, output the function epilogue:
181218334Speter     code to restore the stack frame and return to the caller.  */
181318334Speter  FUNCTION_EPILOGUE (file, get_frame_size ());
181418334Speter#endif
181518334Speter
181618347Speter  if (profile_block_flag)
181718347Speter    add_bb (file);
181818347Speter
181918334Speter#ifdef SDB_DEBUGGING_INFO
182018334Speter  if (write_symbols == SDB_DEBUG)
182118334Speter    sdbout_end_epilogue ();
182218334Speter#endif
182318334Speter
182418334Speter#ifdef DWARF_DEBUGGING_INFO
182518334Speter  if (write_symbols == DWARF_DEBUG)
182618334Speter    dwarfout_end_epilogue ();
182718334Speter#endif
182818334Speter
182950503Sobrien#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
183050503Sobrien  if (dwarf2out_do_frame ())
183150503Sobrien    dwarf2out_end_epilogue ();
183250503Sobrien#endif
183350503Sobrien
183418334Speter#ifdef XCOFF_DEBUGGING_INFO
183518334Speter  if (write_symbols == XCOFF_DEBUG)
183618334Speter    xcoffout_end_epilogue (file);
183718334Speter#endif
183818334Speter
183918334Speter  bb_func_label_num = -1;	/* not in function, nuke label # */
184018334Speter
184118334Speter  /* If FUNCTION_EPILOGUE is not defined, then the function body
184218334Speter     itself contains return instructions wherever needed.  */
184318334Speter}
184418334Speter
184518334Speter/* Add a block to the linked list that remembers the current line/file/function
184618334Speter   for basic block profiling.  Emit the label in front of the basic block and
184718334Speter   the instructions that increment the count field.  */
184818334Speter
184918334Speterstatic void
185018334Speteradd_bb (file)
185118334Speter     FILE *file;
185218334Speter{
185318334Speter  struct bb_list *ptr = (struct bb_list *) permalloc (sizeof (struct bb_list));
185418334Speter
185518334Speter  /* Add basic block to linked list.  */
185618334Speter  ptr->next = 0;
185718334Speter  ptr->line_num = last_linenum;
185818334Speter  ptr->file_label_num = bb_file_label_num;
185918334Speter  ptr->func_label_num = bb_func_label_num;
186018334Speter  *bb_tail = ptr;
186118334Speter  bb_tail = &ptr->next;
186218334Speter
186318334Speter  /* Enable the table of basic-block use counts
186418334Speter     to point at the code it applies to.  */
186518334Speter  ASM_OUTPUT_INTERNAL_LABEL (file, "LPB", count_basic_blocks);
186618334Speter
186718334Speter  /* Before first insn of this basic block, increment the
186818334Speter     count of times it was entered.  */
186918334Speter#ifdef BLOCK_PROFILER
187018334Speter  BLOCK_PROFILER (file, count_basic_blocks);
187150503Sobrien#endif
187250503Sobrien#ifdef HAVE_cc0
187318334Speter  CC_STATUS_INIT;
187418334Speter#endif
187518334Speter
187618334Speter  new_block = 0;
187718334Speter  count_basic_blocks++;
187818334Speter}
187918334Speter
188018334Speter/* Add a string to be used for basic block profiling.  */
188118334Speter
188218334Speterstatic int
188318334Speteradd_bb_string (string, perm_p)
188418334Speter     char *string;
188518334Speter     int perm_p;
188618334Speter{
188718334Speter  int len;
188818334Speter  struct bb_str *ptr = 0;
188918334Speter
189018334Speter  if (!string)
189118334Speter    {
189218334Speter      string = "<unknown>";
189318334Speter      perm_p = TRUE;
189418334Speter    }
189518334Speter
189618334Speter  /* Allocate a new string if the current string isn't permanent.  If
189718334Speter     the string is permanent search for the same string in other
189818334Speter     allocations.  */
189918334Speter
190018334Speter  len = strlen (string) + 1;
190118334Speter  if (!perm_p)
190218334Speter    {
190318334Speter      char *p = (char *) permalloc (len);
190418334Speter      bcopy (string, p, len);
190518334Speter      string = p;
190618334Speter    }
190718334Speter  else
190850503Sobrien    for (ptr = sbb_head; ptr != (struct bb_str *) 0; ptr = ptr->next)
190918334Speter      if (ptr->string == string)
191018334Speter	break;
191118334Speter
191218334Speter  /* Allocate a new string block if we need to.  */
191318334Speter  if (!ptr)
191418334Speter    {
191518334Speter      ptr = (struct bb_str *) permalloc (sizeof (*ptr));
191618334Speter      ptr->next = 0;
191718334Speter      ptr->length = len;
191818334Speter      ptr->label_num = sbb_label_num++;
191918334Speter      ptr->string = string;
192018334Speter      *sbb_tail = ptr;
192118334Speter      sbb_tail = &ptr->next;
192218334Speter    }
192318334Speter
192418334Speter  return ptr->label_num;
192518334Speter}
192618334Speter
192718334Speter
192818334Speter/* Output assembler code for some insns: all or part of a function.
192918334Speter   For description of args, see `final_start_function', above.
193018334Speter
193118334Speter   PRESCAN is 1 if we are not really outputting,
193218334Speter     just scanning as if we were outputting.
193318334Speter   Prescanning deletes and rearranges insns just like ordinary output.
193418334Speter   PRESCAN is -2 if we are outputting after having prescanned.
193518334Speter   In this case, don't try to delete or rearrange insns
193618334Speter   because that has already been done.
193718334Speter   Prescanning is done only on certain machines.  */
193818334Speter
193918334Spetervoid
194018334Speterfinal (first, file, optimize, prescan)
194118334Speter     rtx first;
194218334Speter     FILE *file;
194318334Speter     int optimize;
194418334Speter     int prescan;
194518334Speter{
194618334Speter  register rtx insn;
194718334Speter  int max_line = 0;
194850503Sobrien  int max_uid = 0;
194918334Speter
195018334Speter  last_ignored_compare = 0;
195118334Speter  new_block = 1;
195218334Speter
195350503Sobrien  check_exception_handler_labels ();
195450503Sobrien
195518334Speter  /* Make a map indicating which line numbers appear in this function.
195618334Speter     When producing SDB debugging info, delete troublesome line number
195718334Speter     notes from inlined functions in other files as well as duplicate
195818334Speter     line number notes.  */
195918334Speter#ifdef SDB_DEBUGGING_INFO
196018334Speter  if (write_symbols == SDB_DEBUG)
196118334Speter    {
196218334Speter      rtx last = 0;
196318334Speter      for (insn = first; insn; insn = NEXT_INSN (insn))
196418334Speter	if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
196518334Speter	  {
196618334Speter	    if ((RTX_INTEGRATED_P (insn)
196718334Speter		 && strcmp (NOTE_SOURCE_FILE (insn), main_input_filename) != 0)
196818334Speter		 || (last != 0
196918334Speter		     && NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last)
197018334Speter		     && NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last)))
197118334Speter	      {
197218334Speter		NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
197318334Speter		NOTE_SOURCE_FILE (insn) = 0;
197418334Speter		continue;
197518334Speter	      }
197618334Speter	    last = insn;
197718334Speter	    if (NOTE_LINE_NUMBER (insn) > max_line)
197818334Speter	      max_line = NOTE_LINE_NUMBER (insn);
197918334Speter	  }
198018334Speter    }
198118334Speter  else
198218334Speter#endif
198318334Speter    {
198418334Speter      for (insn = first; insn; insn = NEXT_INSN (insn))
198518334Speter	if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > max_line)
198618334Speter	  max_line = NOTE_LINE_NUMBER (insn);
198718334Speter    }
198818334Speter
198918334Speter  line_note_exists = (char *) oballoc (max_line + 1);
199018334Speter  bzero (line_note_exists, max_line + 1);
199118334Speter
199218334Speter  for (insn = first; insn; insn = NEXT_INSN (insn))
199350503Sobrien    {
199450503Sobrien      if (INSN_UID (insn) > max_uid)       /* find largest UID */
199550503Sobrien        max_uid = INSN_UID (insn);
199650503Sobrien      if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
199750503Sobrien        line_note_exists[NOTE_LINE_NUMBER (insn)] = 1;
199850503Sobrien    }
199918334Speter
200050503Sobrien  /* Initialize insn_eh_region table if eh is being used. */
200150503Sobrien
200250503Sobrien  init_insn_eh_region (first, max_uid);
200350503Sobrien
200418334Speter  init_recog ();
200518334Speter
200618334Speter  CC_STATUS_INIT;
200718334Speter
200818334Speter  /* Output the insns.  */
200918334Speter  for (insn = NEXT_INSN (first); insn;)
201050503Sobrien    {
201150503Sobrien#ifdef HAVE_ATTR_length
201250503Sobrien      insn_current_address = insn_addresses[INSN_UID (insn)];
201350503Sobrien#endif
201450503Sobrien      insn = final_scan_insn (insn, file, optimize, prescan, 0);
201550503Sobrien    }
201618334Speter
201718334Speter  /* Do basic-block profiling here
201818334Speter     if the last insn was a conditional branch.  */
201918334Speter  if (profile_block_flag && new_block)
202018334Speter    add_bb (file);
202150503Sobrien
202250503Sobrien  free_insn_eh_region ();
202318334Speter}
202418334Speter
202518334Speter/* The final scan for one insn, INSN.
202618334Speter   Args are same as in `final', except that INSN
202718334Speter   is the insn being scanned.
202818334Speter   Value returned is the next insn to be scanned.
202918334Speter
203018334Speter   NOPEEPHOLES is the flag to disallow peephole processing (currently
203118334Speter   used for within delayed branch sequence output).  */
203218334Speter
203318334Speterrtx
203418334Speterfinal_scan_insn (insn, file, optimize, prescan, nopeepholes)
203518334Speter     rtx insn;
203618334Speter     FILE *file;
203718334Speter     int optimize;
203818334Speter     int prescan;
203918334Speter     int nopeepholes;
204018334Speter{
204118334Speter  register int i;
204250503Sobrien#ifdef HAVE_cc0
204350503Sobrien  rtx set;
204450503Sobrien#endif
204550503Sobrien
204618334Speter  insn_counter++;
204718334Speter
204818334Speter  /* Ignore deleted insns.  These can occur when we split insns (due to a
204918334Speter     template of "#") while not optimizing.  */
205018334Speter  if (INSN_DELETED_P (insn))
205118334Speter    return NEXT_INSN (insn);
205218334Speter
205318334Speter  switch (GET_CODE (insn))
205418334Speter    {
205518334Speter    case NOTE:
205618334Speter      if (prescan > 0)
205718334Speter	break;
205818334Speter
205918334Speter      /* Align the beginning of a loop, for higher speed
206018334Speter	 on certain machines.  */
206118334Speter
206250503Sobrien      if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
206350503Sobrien	break; /* This used to depend on optimize, but that was bogus.  */
206450503Sobrien      if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
206550503Sobrien	break;
206650503Sobrien
206750503Sobrien      if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG
206850503Sobrien	  && ! exceptions_via_longjmp)
206918334Speter	{
207050503Sobrien	  ASM_OUTPUT_INTERNAL_LABEL (file, "LEHB", NOTE_BLOCK_NUMBER (insn));
207150503Sobrien          if (! flag_new_exceptions)
207250503Sobrien            add_eh_table_entry (NOTE_BLOCK_NUMBER (insn));
207350503Sobrien#ifdef ASM_OUTPUT_EH_REGION_BEG
207450503Sobrien	  ASM_OUTPUT_EH_REGION_BEG (file, NOTE_BLOCK_NUMBER (insn));
207518334Speter#endif
207618334Speter	  break;
207718334Speter	}
207818334Speter
207950503Sobrien      if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END
208050503Sobrien	  && ! exceptions_via_longjmp)
208150503Sobrien	{
208250503Sobrien	  ASM_OUTPUT_INTERNAL_LABEL (file, "LEHE", NOTE_BLOCK_NUMBER (insn));
208350503Sobrien          if (flag_new_exceptions)
208450503Sobrien            add_eh_table_entry (NOTE_BLOCK_NUMBER (insn));
208550503Sobrien#ifdef ASM_OUTPUT_EH_REGION_END
208650503Sobrien	  ASM_OUTPUT_EH_REGION_END (file, NOTE_BLOCK_NUMBER (insn));
208750503Sobrien#endif
208850503Sobrien	  break;
208950503Sobrien	}
209050503Sobrien
209118334Speter      if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_PROLOGUE_END)
209218334Speter	{
209318334Speter#ifdef FUNCTION_END_PROLOGUE
209418334Speter	  FUNCTION_END_PROLOGUE (file);
209518334Speter#endif
209618334Speter	  profile_after_prologue (file);
209718334Speter	  break;
209818334Speter	}
209918334Speter
210018334Speter#ifdef FUNCTION_BEGIN_EPILOGUE
210118334Speter      if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EPILOGUE_BEG)
210218334Speter	{
210318334Speter	  FUNCTION_BEGIN_EPILOGUE (file);
210418334Speter	  break;
210518334Speter	}
210618334Speter#endif
210718334Speter
210818334Speter      if (write_symbols == NO_DEBUG)
210918334Speter	break;
211018334Speter      if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG)
211118334Speter	{
211218334Speter#if defined(SDB_DEBUGGING_INFO) && defined(MIPS_DEBUGGING_INFO)
211318334Speter	  /* MIPS stabs require the parameter descriptions to be after the
211450503Sobrien	     function entry point rather than before.  */
211518334Speter	  if (write_symbols == SDB_DEBUG)
211618334Speter	    sdbout_begin_function (last_linenum);
211718334Speter	  else
211818334Speter#endif
211918334Speter#ifdef DWARF_DEBUGGING_INFO
212018334Speter	  /* This outputs a marker where the function body starts, so it
212118334Speter	     must be after the prologue.  */
212218334Speter	  if (write_symbols == DWARF_DEBUG)
212318334Speter	    dwarfout_begin_function ();
212418334Speter#endif
212518334Speter	  break;
212618334Speter	}
212718334Speter      if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED)
212818334Speter	break;			/* An insn that was "deleted" */
212918334Speter      if (app_on)
213018334Speter	{
213150503Sobrien	  fputs (ASM_APP_OFF, file);
213218334Speter	  app_on = 0;
213318334Speter	}
213418334Speter      if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
213518334Speter	  && (debug_info_level == DINFO_LEVEL_NORMAL
213618334Speter	      || debug_info_level == DINFO_LEVEL_VERBOSE
213718334Speter	      || write_symbols == DWARF_DEBUG
213850503Sobrien	      || write_symbols == DWARF2_DEBUG))
213918334Speter	{
214018334Speter	  /* Beginning of a symbol-block.  Assign it a sequence number
214118334Speter	     and push the number onto the stack PENDING_BLOCKS.  */
214218334Speter
214318334Speter	  if (block_depth == max_block_depth)
214418334Speter	    {
214518334Speter	      /* PENDING_BLOCKS is full; make it longer.  */
214618334Speter	      max_block_depth *= 2;
214718334Speter	      pending_blocks
214818334Speter		= (int *) xrealloc (pending_blocks,
214918334Speter				    max_block_depth * sizeof (int));
215018334Speter	    }
215118334Speter	  pending_blocks[block_depth++] = next_block_index;
215218334Speter
215318334Speter	  high_block_linenum = last_linenum;
215418334Speter
215518334Speter	  /* Output debugging info about the symbol-block beginning.  */
215618334Speter
215718334Speter#ifdef SDB_DEBUGGING_INFO
215818334Speter	  if (write_symbols == SDB_DEBUG)
215918334Speter	    sdbout_begin_block (file, last_linenum, next_block_index);
216018334Speter#endif
216118334Speter#ifdef XCOFF_DEBUGGING_INFO
216218334Speter	  if (write_symbols == XCOFF_DEBUG)
216318334Speter	    xcoffout_begin_block (file, last_linenum, next_block_index);
216418334Speter#endif
216518334Speter#ifdef DBX_DEBUGGING_INFO
216618334Speter	  if (write_symbols == DBX_DEBUG)
216718334Speter	    ASM_OUTPUT_INTERNAL_LABEL (file, "LBB", next_block_index);
216818334Speter#endif
216918334Speter#ifdef DWARF_DEBUGGING_INFO
217050503Sobrien	  if (write_symbols == DWARF_DEBUG)
217118334Speter	    dwarfout_begin_block (next_block_index);
217218334Speter#endif
217350503Sobrien#ifdef DWARF2_DEBUGGING_INFO
217450503Sobrien	  if (write_symbols == DWARF2_DEBUG)
217550503Sobrien	    dwarf2out_begin_block (next_block_index);
217650503Sobrien#endif
217718334Speter
217818334Speter	  next_block_index++;
217918334Speter	}
218018334Speter      else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END
218118334Speter	       && (debug_info_level == DINFO_LEVEL_NORMAL
218218334Speter		   || debug_info_level == DINFO_LEVEL_VERBOSE
218318334Speter	           || write_symbols == DWARF_DEBUG
218450503Sobrien	           || write_symbols == DWARF2_DEBUG))
218518334Speter	{
218618334Speter	  /* End of a symbol-block.  Pop its sequence number off
218718334Speter	     PENDING_BLOCKS and output debugging info based on that.  */
218818334Speter
218918334Speter	  --block_depth;
219018334Speter
219118334Speter#ifdef XCOFF_DEBUGGING_INFO
219218334Speter	  if (write_symbols == XCOFF_DEBUG && block_depth >= 0)
219318334Speter	    xcoffout_end_block (file, high_block_linenum,
219418334Speter				pending_blocks[block_depth]);
219518334Speter#endif
219618334Speter#ifdef DBX_DEBUGGING_INFO
219718334Speter	  if (write_symbols == DBX_DEBUG && block_depth >= 0)
219818334Speter	    ASM_OUTPUT_INTERNAL_LABEL (file, "LBE",
219918334Speter				       pending_blocks[block_depth]);
220018334Speter#endif
220118334Speter#ifdef SDB_DEBUGGING_INFO
220218334Speter	  if (write_symbols == SDB_DEBUG && block_depth >= 0)
220318334Speter	    sdbout_end_block (file, high_block_linenum,
220418334Speter			      pending_blocks[block_depth]);
220518334Speter#endif
220618334Speter#ifdef DWARF_DEBUGGING_INFO
220750503Sobrien	  if (write_symbols == DWARF_DEBUG && block_depth >= 0)
220818334Speter	    dwarfout_end_block (pending_blocks[block_depth]);
220918334Speter#endif
221050503Sobrien#ifdef DWARF2_DEBUGGING_INFO
221150503Sobrien	  if (write_symbols == DWARF2_DEBUG && block_depth >= 0)
221250503Sobrien	    dwarf2out_end_block (pending_blocks[block_depth]);
221350503Sobrien#endif
221418334Speter	}
221518334Speter      else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL
221618334Speter	       && (debug_info_level == DINFO_LEVEL_NORMAL
221718334Speter		   || debug_info_level == DINFO_LEVEL_VERBOSE))
221818334Speter	{
221918334Speter#ifdef DWARF_DEBUGGING_INFO
222018334Speter          if (write_symbols == DWARF_DEBUG)
222118334Speter            dwarfout_label (insn);
222218334Speter#endif
222350503Sobrien#ifdef DWARF2_DEBUGGING_INFO
222450503Sobrien          if (write_symbols == DWARF2_DEBUG)
222550503Sobrien            dwarf2out_label (insn);
222650503Sobrien#endif
222718334Speter	}
222818334Speter      else if (NOTE_LINE_NUMBER (insn) > 0)
222918334Speter	/* This note is a line-number.  */
223018334Speter	{
223118334Speter	  register rtx note;
223218334Speter
223318334Speter#if 0 /* This is what we used to do.  */
223418334Speter	  output_source_line (file, insn);
223518334Speter#endif
223618334Speter	  int note_after = 0;
223718334Speter
223818334Speter	  /* If there is anything real after this note,
223918334Speter	     output it.  If another line note follows, omit this one.  */
224018334Speter	  for (note = NEXT_INSN (insn); note; note = NEXT_INSN (note))
224118334Speter	    {
224218334Speter	      if (GET_CODE (note) != NOTE && GET_CODE (note) != CODE_LABEL)
224318334Speter		break;
224418334Speter	      /* These types of notes can be significant
224518334Speter		 so make sure the preceding line number stays.  */
224618334Speter	      else if (GET_CODE (note) == NOTE
224718334Speter		       && (NOTE_LINE_NUMBER (note) == NOTE_INSN_BLOCK_BEG
224818334Speter			   || NOTE_LINE_NUMBER (note) == NOTE_INSN_BLOCK_END
224918334Speter			   || NOTE_LINE_NUMBER (note) == NOTE_INSN_FUNCTION_BEG))
225018334Speter  		break;
225118334Speter	      else if (GET_CODE (note) == NOTE && NOTE_LINE_NUMBER (note) > 0)
225218334Speter		{
225318334Speter		  /* Another line note follows; we can delete this note
225418334Speter		     if no intervening line numbers have notes elsewhere.  */
225518334Speter		  int num;
225618334Speter		  for (num = NOTE_LINE_NUMBER (insn) + 1;
225718334Speter		       num < NOTE_LINE_NUMBER (note);
225818334Speter		       num++)
225918334Speter		    if (line_note_exists[num])
226018334Speter		      break;
226118334Speter
226218334Speter		  if (num >= NOTE_LINE_NUMBER (note))
226318334Speter		    note_after = 1;
226418334Speter		  break;
226518334Speter		}
226618334Speter	    }
226718334Speter
226818334Speter	  /* Output this line note
226918334Speter	     if it is the first or the last line note in a row.  */
227018334Speter	  if (!note_after)
227118334Speter	    output_source_line (file, insn);
227218334Speter	}
227318334Speter      break;
227418334Speter
227518334Speter    case BARRIER:
227650503Sobrien#if defined (DWARF2_UNWIND_INFO) && !defined (ACCUMULATE_OUTGOING_ARGS)
227750503Sobrien	/* If we push arguments, we need to check all insns for stack
227850503Sobrien	   adjustments.  */
227950503Sobrien	if (dwarf2out_do_frame ())
228050503Sobrien	  dwarf2out_frame_debug (insn);
228118334Speter#endif
228218334Speter      break;
228318334Speter
228418334Speter    case CODE_LABEL:
228550503Sobrien      /* The target port might emit labels in the output function for
228650503Sobrien	 some insn, e.g. sh.c output_branchy_insn.  */
228750503Sobrien      if (CODE_LABEL_NUMBER (insn) <= max_labelno)
228850503Sobrien	{
228950503Sobrien	  int align = LABEL_TO_ALIGNMENT (insn);
229050503Sobrien#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
229150503Sobrien	  int max_skip = LABEL_TO_MAX_SKIP (insn);
229250503Sobrien#endif
229350503Sobrien
229450503Sobrien	  if (align && NEXT_INSN (insn))
229550503Sobrien#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
229650503Sobrien	    ASM_OUTPUT_MAX_SKIP_ALIGN (file, align, max_skip);
229750503Sobrien#else
229850503Sobrien	    ASM_OUTPUT_ALIGN (file, align);
229950503Sobrien#endif
230050503Sobrien	}
230118334Speter      CC_STATUS_INIT;
230218334Speter      if (prescan > 0)
230318334Speter	break;
230418334Speter      new_block = 1;
230550503Sobrien
230650503Sobrien#ifdef FINAL_PRESCAN_LABEL
230750503Sobrien      FINAL_PRESCAN_INSN (insn, NULL_PTR, 0);
230850503Sobrien#endif
230950503Sobrien
231018334Speter#ifdef SDB_DEBUGGING_INFO
231118334Speter      if (write_symbols == SDB_DEBUG && LABEL_NAME (insn))
231218334Speter	sdbout_label (insn);
231318334Speter#endif
231418334Speter#ifdef DWARF_DEBUGGING_INFO
231518334Speter      if (write_symbols == DWARF_DEBUG && LABEL_NAME (insn))
231618334Speter	dwarfout_label (insn);
231718334Speter#endif
231850503Sobrien#ifdef DWARF2_DEBUGGING_INFO
231950503Sobrien      if (write_symbols == DWARF2_DEBUG && LABEL_NAME (insn))
232050503Sobrien	dwarf2out_label (insn);
232150503Sobrien#endif
232218334Speter      if (app_on)
232318334Speter	{
232450503Sobrien	  fputs (ASM_APP_OFF, file);
232518334Speter	  app_on = 0;
232618334Speter	}
232718334Speter      if (NEXT_INSN (insn) != 0
232818334Speter	  && GET_CODE (NEXT_INSN (insn)) == JUMP_INSN)
232918334Speter	{
233018334Speter	  rtx nextbody = PATTERN (NEXT_INSN (insn));
233118334Speter
233218334Speter	  /* If this label is followed by a jump-table,
233318334Speter	     make sure we put the label in the read-only section.  Also
233418334Speter	     possibly write the label and jump table together.  */
233518334Speter
233618334Speter	  if (GET_CODE (nextbody) == ADDR_VEC
233718334Speter	      || GET_CODE (nextbody) == ADDR_DIFF_VEC)
233818334Speter	    {
233950503Sobrien	      if (! JUMP_TABLES_IN_TEXT_SECTION)
234050503Sobrien		{
234150503Sobrien		  readonly_data_section ();
234218334Speter#ifdef READONLY_DATA_SECTION
234350503Sobrien		  ASM_OUTPUT_ALIGN (file,
234450503Sobrien				    exact_log2 (BIGGEST_ALIGNMENT
234550503Sobrien						/ BITS_PER_UNIT));
234618334Speter#endif /* READONLY_DATA_SECTION */
234750503Sobrien		}
234850503Sobrien	      else
234950503Sobrien		function_section (current_function_decl);
235050503Sobrien
235118334Speter#ifdef ASM_OUTPUT_CASE_LABEL
235218334Speter	      ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn),
235318334Speter				     NEXT_INSN (insn));
235418334Speter#else
235518334Speter	      ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
235618334Speter#endif
235718334Speter	      break;
235818334Speter	    }
235918334Speter	}
236018334Speter
236118334Speter      ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
236218334Speter      break;
236318334Speter
236418334Speter    default:
236518334Speter      {
236618334Speter	register rtx body = PATTERN (insn);
236718334Speter	int insn_code_number;
236818334Speter	char *template;
236950503Sobrien#ifdef HAVE_cc0
237018334Speter	rtx note;
237150503Sobrien#endif
237218334Speter
237318334Speter	/* An INSN, JUMP_INSN or CALL_INSN.
237418334Speter	   First check for special kinds that recog doesn't recognize.  */
237518334Speter
237618334Speter	if (GET_CODE (body) == USE /* These are just declarations */
237718334Speter	    || GET_CODE (body) == CLOBBER)
237818334Speter	  break;
237918334Speter
238018334Speter#ifdef HAVE_cc0
238118334Speter	/* If there is a REG_CC_SETTER note on this insn, it means that
238218334Speter	   the setting of the condition code was done in the delay slot
238318334Speter	   of the insn that branched here.  So recover the cc status
238418334Speter	   from the insn that set it.  */
238518334Speter
238618334Speter	note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX);
238718334Speter	if (note)
238818334Speter	  {
238918334Speter	    NOTICE_UPDATE_CC (PATTERN (XEXP (note, 0)), XEXP (note, 0));
239018334Speter	    cc_prev_status = cc_status;
239118334Speter	  }
239218334Speter#endif
239318334Speter
239418334Speter	/* Detect insns that are really jump-tables
239518334Speter	   and output them as such.  */
239618334Speter
239718334Speter	if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
239818334Speter	  {
239918334Speter	    register int vlen, idx;
240018334Speter
240118334Speter	    if (prescan > 0)
240218334Speter	      break;
240318334Speter
240418334Speter	    if (app_on)
240518334Speter	      {
240650503Sobrien		fputs (ASM_APP_OFF, file);
240718334Speter		app_on = 0;
240818334Speter	      }
240918334Speter
241018334Speter	    vlen = XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC);
241118334Speter	    for (idx = 0; idx < vlen; idx++)
241218334Speter	      {
241318334Speter		if (GET_CODE (body) == ADDR_VEC)
241418334Speter		  {
241518334Speter#ifdef ASM_OUTPUT_ADDR_VEC_ELT
241618334Speter		    ASM_OUTPUT_ADDR_VEC_ELT
241718334Speter		      (file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0)));
241818334Speter#else
241918334Speter		    abort ();
242018334Speter#endif
242118334Speter		  }
242218334Speter		else
242318334Speter		  {
242418334Speter#ifdef ASM_OUTPUT_ADDR_DIFF_ELT
242518334Speter		    ASM_OUTPUT_ADDR_DIFF_ELT
242618334Speter		      (file,
242750503Sobrien		       body,
242818334Speter		       CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)),
242918334Speter		       CODE_LABEL_NUMBER (XEXP (XEXP (body, 0), 0)));
243018334Speter#else
243118334Speter		    abort ();
243218334Speter#endif
243318334Speter		  }
243418334Speter	      }
243518334Speter#ifdef ASM_OUTPUT_CASE_END
243618334Speter	    ASM_OUTPUT_CASE_END (file,
243718334Speter				 CODE_LABEL_NUMBER (PREV_INSN (insn)),
243818334Speter				 insn);
243918334Speter#endif
244018334Speter
244118334Speter	    function_section (current_function_decl);
244218334Speter
244318334Speter	    break;
244418334Speter	  }
244518334Speter
244618334Speter	/* Do basic-block profiling when we reach a new block.
244718334Speter	   Done here to avoid jump tables.  */
244818334Speter	if (profile_block_flag && new_block)
244918334Speter	  add_bb (file);
245018334Speter
245118334Speter	if (GET_CODE (body) == ASM_INPUT)
245218334Speter	  {
245318334Speter	    /* There's no telling what that did to the condition codes.  */
245418334Speter	    CC_STATUS_INIT;
245518334Speter	    if (prescan > 0)
245618334Speter	      break;
245718334Speter	    if (! app_on)
245818334Speter	      {
245950503Sobrien		fputs (ASM_APP_ON, file);
246018334Speter		app_on = 1;
246118334Speter	      }
246218334Speter	    fprintf (asm_out_file, "\t%s\n", XSTR (body, 0));
246318334Speter	    break;
246418334Speter	  }
246518334Speter
246618334Speter	/* Detect `asm' construct with operands.  */
246718334Speter	if (asm_noperands (body) >= 0)
246818334Speter	  {
246950503Sobrien	    unsigned int noperands = asm_noperands (body);
247018334Speter	    rtx *ops = (rtx *) alloca (noperands * sizeof (rtx));
247118334Speter	    char *string;
247218334Speter
247318334Speter	    /* There's no telling what that did to the condition codes.  */
247418334Speter	    CC_STATUS_INIT;
247518334Speter	    if (prescan > 0)
247618334Speter	      break;
247718334Speter
247818334Speter	    if (! app_on)
247918334Speter	      {
248050503Sobrien		fputs (ASM_APP_ON, file);
248118334Speter		app_on = 1;
248218334Speter	      }
248318334Speter
248418334Speter	    /* Get out the operand values.  */
248518334Speter	    string = decode_asm_operands (body, ops, NULL_PTR,
248618334Speter					  NULL_PTR, NULL_PTR);
248718334Speter	    /* Inhibit aborts on what would otherwise be compiler bugs.  */
248818334Speter	    insn_noperands = noperands;
248918334Speter	    this_is_asm_operands = insn;
249018334Speter
249118334Speter	    /* Output the insn using them.  */
249218334Speter	    output_asm_insn (string, ops);
249318334Speter	    this_is_asm_operands = 0;
249418334Speter	    break;
249518334Speter	  }
249618334Speter
249718334Speter	if (prescan <= 0 && app_on)
249818334Speter	  {
249950503Sobrien	    fputs (ASM_APP_OFF, file);
250018334Speter	    app_on = 0;
250118334Speter	  }
250218334Speter
250318334Speter	if (GET_CODE (body) == SEQUENCE)
250418334Speter	  {
250518334Speter	    /* A delayed-branch sequence */
250618334Speter	    register int i;
250718334Speter	    rtx next;
250818334Speter
250918334Speter	    if (prescan > 0)
251018334Speter	      break;
251118334Speter	    final_sequence = body;
251218334Speter
251318334Speter	    /* The first insn in this SEQUENCE might be a JUMP_INSN that will
251418334Speter	       force the restoration of a comparison that was previously
251518334Speter	       thought unnecessary.  If that happens, cancel this sequence
251618334Speter	       and cause that insn to be restored.  */
251718334Speter
251818334Speter	    next = final_scan_insn (XVECEXP (body, 0, 0), file, 0, prescan, 1);
251918334Speter	    if (next != XVECEXP (body, 0, 1))
252018334Speter	      {
252118334Speter		final_sequence = 0;
252218334Speter		return next;
252318334Speter	      }
252418334Speter
252518334Speter	    for (i = 1; i < XVECLEN (body, 0); i++)
252618334Speter	      {
252718334Speter		rtx insn = XVECEXP (body, 0, i);
252818334Speter		rtx next = NEXT_INSN (insn);
252918334Speter		/* We loop in case any instruction in a delay slot gets
253018334Speter		   split.  */
253118334Speter		do
253218334Speter		  insn = final_scan_insn (insn, file, 0, prescan, 1);
253318334Speter		while (insn != next);
253418334Speter	      }
253518334Speter#ifdef DBR_OUTPUT_SEQEND
253618334Speter	    DBR_OUTPUT_SEQEND (file);
253718334Speter#endif
253818334Speter	    final_sequence = 0;
253918334Speter
254018334Speter	    /* If the insn requiring the delay slot was a CALL_INSN, the
254118334Speter	       insns in the delay slot are actually executed before the
254218334Speter	       called function.  Hence we don't preserve any CC-setting
254318334Speter	       actions in these insns and the CC must be marked as being
254418334Speter	       clobbered by the function.  */
254518334Speter	    if (GET_CODE (XVECEXP (body, 0, 0)) == CALL_INSN)
254650503Sobrien	      {
254750503Sobrien		CC_STATUS_INIT;
254850503Sobrien	      }
254918334Speter
255018334Speter	    /* Following a conditional branch sequence, we have a new basic
255118334Speter	       block.  */
255218334Speter	    if (profile_block_flag)
255318334Speter	      {
255418334Speter		rtx insn = XVECEXP (body, 0, 0);
255518334Speter		rtx body = PATTERN (insn);
255618334Speter
255718334Speter		if ((GET_CODE (insn) == JUMP_INSN && GET_CODE (body) == SET
255818334Speter		     && GET_CODE (SET_SRC (body)) != LABEL_REF)
255918334Speter		    || (GET_CODE (insn) == JUMP_INSN
256018334Speter			&& GET_CODE (body) == PARALLEL
256118334Speter			&& GET_CODE (XVECEXP (body, 0, 0)) == SET
256218334Speter			&& GET_CODE (SET_SRC (XVECEXP (body, 0, 0))) != LABEL_REF))
256318334Speter		  new_block = 1;
256418334Speter	      }
256518334Speter	    break;
256618334Speter	  }
256718334Speter
256818334Speter	/* We have a real machine instruction as rtl.  */
256918334Speter
257018334Speter	body = PATTERN (insn);
257118334Speter
257218334Speter#ifdef HAVE_cc0
257350503Sobrien	set = single_set(insn);
257450503Sobrien
257518334Speter	/* Check for redundant test and compare instructions
257618334Speter	   (when the condition codes are already set up as desired).
257718334Speter	   This is done only when optimizing; if not optimizing,
257818334Speter	   it should be possible for the user to alter a variable
257918334Speter	   with the debugger in between statements
258018334Speter	   and the next statement should reexamine the variable
258118334Speter	   to compute the condition codes.  */
258218334Speter
258350503Sobrien	if (optimize)
258418334Speter	  {
258550503Sobrien#if 0
258650503Sobrien	    rtx set = single_set(insn);
258750503Sobrien#endif
258850503Sobrien
258950503Sobrien	    if (set
259050503Sobrien		&& GET_CODE (SET_DEST (set)) == CC0
259150503Sobrien		&& insn != last_ignored_compare)
259218334Speter	      {
259350503Sobrien		if (GET_CODE (SET_SRC (set)) == SUBREG)
259450503Sobrien		  SET_SRC (set) = alter_subreg (SET_SRC (set));
259550503Sobrien		else if (GET_CODE (SET_SRC (set)) == COMPARE)
259618334Speter		  {
259750503Sobrien		    if (GET_CODE (XEXP (SET_SRC (set), 0)) == SUBREG)
259850503Sobrien		      XEXP (SET_SRC (set), 0)
259950503Sobrien			= alter_subreg (XEXP (SET_SRC (set), 0));
260050503Sobrien		    if (GET_CODE (XEXP (SET_SRC (set), 1)) == SUBREG)
260150503Sobrien		      XEXP (SET_SRC (set), 1)
260250503Sobrien			= alter_subreg (XEXP (SET_SRC (set), 1));
260318334Speter		  }
260450503Sobrien		if ((cc_status.value1 != 0
260550503Sobrien		     && rtx_equal_p (SET_SRC (set), cc_status.value1))
260650503Sobrien		    || (cc_status.value2 != 0
260750503Sobrien			&& rtx_equal_p (SET_SRC (set), cc_status.value2)))
260850503Sobrien		  {
260950503Sobrien		    /* Don't delete insn if it has an addressing side-effect.  */
261050503Sobrien		    if (! FIND_REG_INC_NOTE (insn, 0)
261150503Sobrien			/* or if anything in it is volatile.  */
261250503Sobrien			&& ! volatile_refs_p (PATTERN (insn)))
261350503Sobrien		      {
261450503Sobrien			/* We don't really delete the insn; just ignore it.  */
261550503Sobrien			last_ignored_compare = insn;
261650503Sobrien			break;
261750503Sobrien		      }
261850503Sobrien		  }
261918334Speter	      }
262018334Speter	  }
262118334Speter#endif
262218334Speter
262318334Speter	/* Following a conditional branch, we have a new basic block.
262418334Speter	   But if we are inside a sequence, the new block starts after the
262518334Speter	   last insn of the sequence.  */
262618334Speter	if (profile_block_flag && final_sequence == 0
262718334Speter	    && ((GET_CODE (insn) == JUMP_INSN && GET_CODE (body) == SET
262818334Speter		 && GET_CODE (SET_SRC (body)) != LABEL_REF)
262918334Speter		|| (GET_CODE (insn) == JUMP_INSN && GET_CODE (body) == PARALLEL
263018334Speter		    && GET_CODE (XVECEXP (body, 0, 0)) == SET
263118334Speter		    && GET_CODE (SET_SRC (XVECEXP (body, 0, 0))) != LABEL_REF)))
263218334Speter	  new_block = 1;
263318334Speter
263418334Speter#ifndef STACK_REGS
263518334Speter	/* Don't bother outputting obvious no-ops, even without -O.
263618334Speter	   This optimization is fast and doesn't interfere with debugging.
263718334Speter	   Don't do this if the insn is in a delay slot, since this
263818334Speter	   will cause an improper number of delay insns to be written.  */
263918334Speter	if (final_sequence == 0
264018334Speter	    && prescan >= 0
264118334Speter	    && GET_CODE (insn) == INSN && GET_CODE (body) == SET
264218334Speter	    && GET_CODE (SET_SRC (body)) == REG
264318334Speter	    && GET_CODE (SET_DEST (body)) == REG
264418334Speter	    && REGNO (SET_SRC (body)) == REGNO (SET_DEST (body)))
264518334Speter	  break;
264618334Speter#endif
264718334Speter
264818334Speter#ifdef HAVE_cc0
264918334Speter	/* If this is a conditional branch, maybe modify it
265018334Speter	   if the cc's are in a nonstandard state
265118334Speter	   so that it accomplishes the same thing that it would
265218334Speter	   do straightforwardly if the cc's were set up normally.  */
265318334Speter
265418334Speter	if (cc_status.flags != 0
265518334Speter	    && GET_CODE (insn) == JUMP_INSN
265618334Speter	    && GET_CODE (body) == SET
265718334Speter	    && SET_DEST (body) == pc_rtx
265818334Speter	    && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE
265918334Speter	    && GET_RTX_CLASS (GET_CODE (XEXP (SET_SRC (body), 0))) == '<'
266018334Speter	    && XEXP (XEXP (SET_SRC (body), 0), 0) == cc0_rtx
266118334Speter	    /* This is done during prescan; it is not done again
266218334Speter	       in final scan when prescan has been done.  */
266318334Speter	    && prescan >= 0)
266418334Speter	  {
266518334Speter	    /* This function may alter the contents of its argument
266618334Speter	       and clear some of the cc_status.flags bits.
266718334Speter	       It may also return 1 meaning condition now always true
266818334Speter	       or -1 meaning condition now always false
266918334Speter	       or 2 meaning condition nontrivial but altered.  */
267018334Speter	    register int result = alter_cond (XEXP (SET_SRC (body), 0));
267118334Speter	    /* If condition now has fixed value, replace the IF_THEN_ELSE
267218334Speter	       with its then-operand or its else-operand.  */
267318334Speter	    if (result == 1)
267418334Speter	      SET_SRC (body) = XEXP (SET_SRC (body), 1);
267518334Speter	    if (result == -1)
267618334Speter	      SET_SRC (body) = XEXP (SET_SRC (body), 2);
267718334Speter
267818334Speter	    /* The jump is now either unconditional or a no-op.
267918334Speter	       If it has become a no-op, don't try to output it.
268018334Speter	       (It would not be recognized.)  */
268118334Speter	    if (SET_SRC (body) == pc_rtx)
268218334Speter	      {
268318334Speter		PUT_CODE (insn, NOTE);
268418334Speter		NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
268518334Speter		NOTE_SOURCE_FILE (insn) = 0;
268618334Speter		break;
268718334Speter	      }
268818334Speter	    else if (GET_CODE (SET_SRC (body)) == RETURN)
268918334Speter	      /* Replace (set (pc) (return)) with (return).  */
269018334Speter	      PATTERN (insn) = body = SET_SRC (body);
269118334Speter
269218334Speter	    /* Rerecognize the instruction if it has changed.  */
269318334Speter	    if (result != 0)
269418334Speter	      INSN_CODE (insn) = -1;
269518334Speter	  }
269618334Speter
269718334Speter	/* Make same adjustments to instructions that examine the
269850503Sobrien	   condition codes without jumping and instructions that
269950503Sobrien	   handle conditional moves (if this machine has either one).  */
270018334Speter
270118334Speter	if (cc_status.flags != 0
270250503Sobrien	    && set != 0)
270318334Speter	  {
270450503Sobrien	    rtx cond_rtx, then_rtx, else_rtx;
270550503Sobrien
270650503Sobrien	    if (GET_CODE (insn) != JUMP_INSN
270750503Sobrien		&& GET_CODE (SET_SRC (set)) == IF_THEN_ELSE)
270818334Speter	      {
270950503Sobrien		cond_rtx = XEXP (SET_SRC (set), 0);
271050503Sobrien		then_rtx = XEXP (SET_SRC (set), 1);
271150503Sobrien		else_rtx = XEXP (SET_SRC (set), 2);
271250503Sobrien	      }
271350503Sobrien	    else
271450503Sobrien	      {
271550503Sobrien		cond_rtx = SET_SRC (set);
271650503Sobrien		then_rtx = const_true_rtx;
271750503Sobrien		else_rtx = const0_rtx;
271850503Sobrien	      }
271950503Sobrien
272050503Sobrien	    switch (GET_CODE (cond_rtx))
272150503Sobrien	      {
272218334Speter	      case GTU:
272318334Speter	      case GT:
272418334Speter	      case LTU:
272518334Speter	      case LT:
272618334Speter	      case GEU:
272718334Speter	      case GE:
272818334Speter	      case LEU:
272918334Speter	      case LE:
273018334Speter	      case EQ:
273118334Speter	      case NE:
273218334Speter		{
273318334Speter		  register int result;
273450503Sobrien		  if (XEXP (cond_rtx, 0) != cc0_rtx)
273518334Speter		    break;
273650503Sobrien		  result = alter_cond (cond_rtx);
273718334Speter		  if (result == 1)
273850503Sobrien		    validate_change (insn, &SET_SRC (set), then_rtx, 0);
273918334Speter		  else if (result == -1)
274050503Sobrien		    validate_change (insn, &SET_SRC (set), else_rtx, 0);
274118334Speter		  else if (result == 2)
274218334Speter		    INSN_CODE (insn) = -1;
274350503Sobrien		  if (SET_DEST (set) == SET_SRC (set))
274450503Sobrien		    {
274550503Sobrien		      PUT_CODE (insn, NOTE);
274650503Sobrien		      NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
274750503Sobrien		      NOTE_SOURCE_FILE (insn) = 0;
274850503Sobrien		    }
274918334Speter		}
275050503Sobrien		break;
275150503Sobrien
275250503Sobrien	      default:
275350503Sobrien		break;
275418334Speter	      }
275518334Speter	  }
275650503Sobrien
275718334Speter#endif
275818334Speter
275918334Speter	/* Do machine-specific peephole optimizations if desired.  */
276018334Speter
276118334Speter	if (optimize && !flag_no_peephole && !nopeepholes)
276218334Speter	  {
276318334Speter	    rtx next = peephole (insn);
276418334Speter	    /* When peepholing, if there were notes within the peephole,
276518334Speter	       emit them before the peephole.  */
276618334Speter	    if (next != 0 && next != NEXT_INSN (insn))
276718334Speter	      {
276818334Speter		rtx prev = PREV_INSN (insn);
276918334Speter		rtx note;
277018334Speter
277118334Speter		for (note = NEXT_INSN (insn); note != next;
277218334Speter		     note = NEXT_INSN (note))
277318334Speter		  final_scan_insn (note, file, optimize, prescan, nopeepholes);
277418334Speter
277518334Speter		/* In case this is prescan, put the notes
277618334Speter		   in proper position for later rescan.  */
277718334Speter		note = NEXT_INSN (insn);
277818334Speter		PREV_INSN (note) = prev;
277918334Speter		NEXT_INSN (prev) = note;
278018334Speter		NEXT_INSN (PREV_INSN (next)) = insn;
278118334Speter		PREV_INSN (insn) = PREV_INSN (next);
278218334Speter		NEXT_INSN (insn) = next;
278318334Speter		PREV_INSN (next) = insn;
278418334Speter	      }
278518334Speter
278618334Speter	    /* PEEPHOLE might have changed this.  */
278718334Speter	    body = PATTERN (insn);
278818334Speter	  }
278918334Speter
279018334Speter	/* Try to recognize the instruction.
279118334Speter	   If successful, verify that the operands satisfy the
279218334Speter	   constraints for the instruction.  Crash if they don't,
279318334Speter	   since `reload' should have changed them so that they do.  */
279418334Speter
279518334Speter	insn_code_number = recog_memoized (insn);
279618334Speter	insn_extract (insn);
279718334Speter	for (i = 0; i < insn_n_operands[insn_code_number]; i++)
279818334Speter	  {
279918334Speter	    if (GET_CODE (recog_operand[i]) == SUBREG)
280018334Speter	      recog_operand[i] = alter_subreg (recog_operand[i]);
280118334Speter	    else if (GET_CODE (recog_operand[i]) == PLUS
280218334Speter		     || GET_CODE (recog_operand[i]) == MULT)
280318334Speter	      recog_operand[i] = walk_alter_subreg (recog_operand[i]);
280418334Speter	  }
280518334Speter
280618334Speter	for (i = 0; i < insn_n_dups[insn_code_number]; i++)
280718334Speter	  {
280818334Speter	    if (GET_CODE (*recog_dup_loc[i]) == SUBREG)
280918334Speter	      *recog_dup_loc[i] = alter_subreg (*recog_dup_loc[i]);
281018334Speter	    else if (GET_CODE (*recog_dup_loc[i]) == PLUS
281118334Speter		     || GET_CODE (*recog_dup_loc[i]) == MULT)
281218334Speter	      *recog_dup_loc[i] = walk_alter_subreg (*recog_dup_loc[i]);
281318334Speter	  }
281418334Speter
281518334Speter#ifdef REGISTER_CONSTRAINTS
281618334Speter	if (! constrain_operands (insn_code_number, 1))
281718334Speter	  fatal_insn_not_found (insn);
281818334Speter#endif
281918334Speter
282018334Speter	/* Some target machines need to prescan each insn before
282118334Speter	   it is output.  */
282218334Speter
282318334Speter#ifdef FINAL_PRESCAN_INSN
282418334Speter	FINAL_PRESCAN_INSN (insn, recog_operand,
282518334Speter			    insn_n_operands[insn_code_number]);
282618334Speter#endif
282718334Speter
282818334Speter#ifdef HAVE_cc0
282918334Speter	cc_prev_status = cc_status;
283018334Speter
283118334Speter	/* Update `cc_status' for this instruction.
283218334Speter	   The instruction's output routine may change it further.
283318334Speter	   If the output routine for a jump insn needs to depend
283418334Speter	   on the cc status, it should look at cc_prev_status.  */
283518334Speter
283618334Speter	NOTICE_UPDATE_CC (body, insn);
283718334Speter#endif
283818334Speter
283918334Speter	debug_insn = insn;
284018334Speter
284150503Sobrien#if defined (DWARF2_UNWIND_INFO) && !defined (ACCUMULATE_OUTGOING_ARGS)
284250503Sobrien	/* If we push arguments, we want to know where the calls are.  */
284350503Sobrien	if (GET_CODE (insn) == CALL_INSN && dwarf2out_do_frame ())
284450503Sobrien	  dwarf2out_frame_debug (insn);
284550503Sobrien#endif
284650503Sobrien
284718334Speter	/* If the proper template needs to be chosen by some C code,
284818334Speter	   run that code and get the real template.  */
284918334Speter
285018334Speter	template = insn_template[insn_code_number];
285118334Speter	if (template == 0)
285218334Speter	  {
285318334Speter	    template = (*insn_outfun[insn_code_number]) (recog_operand, insn);
285418334Speter
285518334Speter	    /* If the C code returns 0, it means that it is a jump insn
285618334Speter	       which follows a deleted test insn, and that test insn
285718334Speter	       needs to be reinserted.  */
285818334Speter	    if (template == 0)
285918334Speter	      {
286018334Speter		if (prev_nonnote_insn (insn) != last_ignored_compare)
286118334Speter		  abort ();
286218334Speter		new_block = 0;
286318334Speter		return prev_nonnote_insn (insn);
286418334Speter	      }
286518334Speter	  }
286618334Speter
286718334Speter	/* If the template is the string "#", it means that this insn must
286818334Speter	   be split.  */
286918334Speter	if (template[0] == '#' && template[1] == '\0')
287018334Speter	  {
287118334Speter	    rtx new = try_split (body, insn, 0);
287218334Speter
287318334Speter	    /* If we didn't split the insn, go away.  */
287418334Speter	    if (new == insn && PATTERN (new) == body)
287550503Sobrien	      fatal_insn ("Could not split insn", insn);
287618334Speter
287750503Sobrien#ifdef HAVE_ATTR_length
287850503Sobrien	    /* This instruction should have been split in shorten_branches,
287950503Sobrien	       to ensure that we would have valid length info for the
288050503Sobrien	       splitees.  */
288150503Sobrien	    abort ();
288250503Sobrien#endif
288350503Sobrien
288418334Speter	    new_block = 0;
288518334Speter	    return new;
288618334Speter	  }
288718334Speter
288818334Speter	if (prescan > 0)
288918334Speter	  break;
289018334Speter
289118334Speter	/* Output assembler code from the template.  */
289218334Speter
289318334Speter	output_asm_insn (template, recog_operand);
289418334Speter
289550503Sobrien#if defined (DWARF2_UNWIND_INFO)
289650503Sobrien#if !defined (ACCUMULATE_OUTGOING_ARGS)
289750503Sobrien	/* If we push arguments, we need to check all insns for stack
289850503Sobrien	   adjustments.  */
289950503Sobrien	if (GET_CODE (insn) == INSN && dwarf2out_do_frame ())
290050503Sobrien	  dwarf2out_frame_debug (insn);
290150503Sobrien#else
290250503Sobrien#if defined (HAVE_prologue)
290350503Sobrien	/* If this insn is part of the prologue, emit DWARF v2
290450503Sobrien	   call frame info.  */
290550503Sobrien	if (RTX_FRAME_RELATED_P (insn) && dwarf2out_do_frame ())
290650503Sobrien	  dwarf2out_frame_debug (insn);
290750503Sobrien#endif
290850503Sobrien#endif
290950503Sobrien#endif
291050503Sobrien
291118334Speter#if 0
291218334Speter	/* It's not at all clear why we did this and doing so interferes
291318334Speter	   with tests we'd like to do to use REG_WAS_0 notes, so let's try
291418334Speter	   with this out.  */
291518334Speter
291618334Speter	/* Mark this insn as having been output.  */
291718334Speter	INSN_DELETED_P (insn) = 1;
291818334Speter#endif
291918334Speter
292018334Speter	debug_insn = 0;
292118334Speter      }
292218334Speter    }
292318334Speter  return NEXT_INSN (insn);
292418334Speter}
292518334Speter
292618334Speter/* Output debugging info to the assembler file FILE
292718334Speter   based on the NOTE-insn INSN, assumed to be a line number.  */
292818334Speter
292918334Speterstatic void
293018334Speteroutput_source_line (file, insn)
293118334Speter     FILE *file;
293218334Speter     rtx insn;
293318334Speter{
293418334Speter  register char *filename = NOTE_SOURCE_FILE (insn);
293518334Speter
293618334Speter  /* Remember filename for basic block profiling.
293718334Speter     Filenames are allocated on the permanent obstack
293818334Speter     or are passed in ARGV, so we don't have to save
293918334Speter     the string.  */
294018334Speter
294118334Speter  if (profile_block_flag && last_filename != filename)
294218334Speter    bb_file_label_num = add_bb_string (filename, TRUE);
294318334Speter
294418334Speter  last_filename = filename;
294518334Speter  last_linenum = NOTE_LINE_NUMBER (insn);
294618334Speter  high_block_linenum = MAX (last_linenum, high_block_linenum);
294718334Speter  high_function_linenum = MAX (last_linenum, high_function_linenum);
294818334Speter
294918334Speter  if (write_symbols != NO_DEBUG)
295018334Speter    {
295118334Speter#ifdef SDB_DEBUGGING_INFO
295218334Speter      if (write_symbols == SDB_DEBUG
295318334Speter#if 0 /* People like having line numbers even in wrong file!  */
295418334Speter	  /* COFF can't handle multiple source files--lose, lose.  */
295518334Speter	  && !strcmp (filename, main_input_filename)
295618334Speter#endif
295718334Speter	  /* COFF relative line numbers must be positive.  */
295818334Speter	  && last_linenum > sdb_begin_function_line)
295918334Speter	{
296018334Speter#ifdef ASM_OUTPUT_SOURCE_LINE
296118334Speter	  ASM_OUTPUT_SOURCE_LINE (file, last_linenum);
296218334Speter#else
296318334Speter	  fprintf (file, "\t.ln\t%d\n",
296418334Speter		   ((sdb_begin_function_line > -1)
296518334Speter		    ? last_linenum - sdb_begin_function_line : 1));
296618334Speter#endif
296718334Speter	}
296818334Speter#endif
296918334Speter
297018334Speter#if defined (DBX_DEBUGGING_INFO)
297118334Speter      if (write_symbols == DBX_DEBUG)
297218334Speter	dbxout_source_line (file, filename, NOTE_LINE_NUMBER (insn));
297318334Speter#endif
297418334Speter
297518334Speter#if defined (XCOFF_DEBUGGING_INFO)
297618334Speter      if (write_symbols == XCOFF_DEBUG)
297718334Speter	xcoffout_source_line (file, filename, insn);
297818334Speter#endif
297918334Speter
298018334Speter#ifdef DWARF_DEBUGGING_INFO
298118334Speter      if (write_symbols == DWARF_DEBUG)
298218334Speter	dwarfout_line (filename, NOTE_LINE_NUMBER (insn));
298318334Speter#endif
298450503Sobrien
298550503Sobrien#ifdef DWARF2_DEBUGGING_INFO
298650503Sobrien      if (write_symbols == DWARF2_DEBUG)
298750503Sobrien	dwarf2out_line (filename, NOTE_LINE_NUMBER (insn));
298850503Sobrien#endif
298918334Speter    }
299018334Speter}
299118334Speter
299218334Speter/* If X is a SUBREG, replace it with a REG or a MEM,
299318334Speter   based on the thing it is a subreg of.  */
299418334Speter
299518334Speterrtx
299618334Speteralter_subreg (x)
299718334Speter     register rtx x;
299818334Speter{
299918334Speter  register rtx y = SUBREG_REG (x);
300050503Sobrien
300118334Speter  if (GET_CODE (y) == SUBREG)
300218334Speter    y = alter_subreg (y);
300318334Speter
300450503Sobrien  /* If reload is operating, we may be replacing inside this SUBREG.
300550503Sobrien     Check for that and make a new one if so.  */
300650503Sobrien  if (reload_in_progress && find_replacement (&SUBREG_REG (x)) != 0)
300750503Sobrien    x = copy_rtx (x);
300850503Sobrien
300918334Speter  if (GET_CODE (y) == REG)
301018334Speter    {
301150503Sobrien      /* If the word size is larger than the size of this register,
301250503Sobrien	 adjust the register number to compensate.  */
301350503Sobrien      /* ??? Note that this just catches stragglers created by/for
301450503Sobrien	 integrate.  It would be better if we either caught these
301550503Sobrien	 earlier, or kept _all_ subregs until now and eliminate
301650503Sobrien	 gen_lowpart and friends.  */
301750503Sobrien
301818334Speter      PUT_CODE (x, REG);
301950503Sobrien#ifdef ALTER_HARD_SUBREG
302050503Sobrien      REGNO (x) = ALTER_HARD_SUBREG(GET_MODE (x), SUBREG_WORD (x),
302150503Sobrien				    GET_MODE (y), REGNO (y));
302250503Sobrien#else
302318334Speter      REGNO (x) = REGNO (y) + SUBREG_WORD (x);
302450503Sobrien#endif
302518334Speter    }
302618334Speter  else if (GET_CODE (y) == MEM)
302718334Speter    {
302818334Speter      register int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
302918334Speter      if (BYTES_BIG_ENDIAN)
303018334Speter	offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x)))
303118334Speter		   - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (y))));
303218334Speter      PUT_CODE (x, MEM);
303318334Speter      MEM_VOLATILE_P (x) = MEM_VOLATILE_P (y);
303450503Sobrien      MEM_IN_STRUCT_P (x) = MEM_IN_STRUCT_P (y);
303550503Sobrien      MEM_ALIAS_SET (x) = MEM_ALIAS_SET (y);
303618334Speter      XEXP (x, 0) = plus_constant (XEXP (y, 0), offset);
303718334Speter    }
303818334Speter
303918334Speter  return x;
304018334Speter}
304118334Speter
304218334Speter/* Do alter_subreg on all the SUBREGs contained in X.  */
304318334Speter
304418334Speterstatic rtx
304518334Speterwalk_alter_subreg (x)
304618334Speter     rtx x;
304718334Speter{
304818334Speter  switch (GET_CODE (x))
304918334Speter    {
305018334Speter    case PLUS:
305118334Speter    case MULT:
305218334Speter      XEXP (x, 0) = walk_alter_subreg (XEXP (x, 0));
305318334Speter      XEXP (x, 1) = walk_alter_subreg (XEXP (x, 1));
305418334Speter      break;
305518334Speter
305618334Speter    case MEM:
305718334Speter      XEXP (x, 0) = walk_alter_subreg (XEXP (x, 0));
305818334Speter      break;
305918334Speter
306018334Speter    case SUBREG:
306118334Speter      return alter_subreg (x);
306250503Sobrien
306350503Sobrien    default:
306450503Sobrien      break;
306518334Speter    }
306618334Speter
306718334Speter  return x;
306818334Speter}
306918334Speter
307018334Speter#ifdef HAVE_cc0
307118334Speter
307218334Speter/* Given BODY, the body of a jump instruction, alter the jump condition
307318334Speter   as required by the bits that are set in cc_status.flags.
307418334Speter   Not all of the bits there can be handled at this level in all cases.
307518334Speter
307618334Speter   The value is normally 0.
307718334Speter   1 means that the condition has become always true.
307818334Speter   -1 means that the condition has become always false.
307918334Speter   2 means that COND has been altered.  */
308018334Speter
308118334Speterstatic int
308218334Speteralter_cond (cond)
308318334Speter     register rtx cond;
308418334Speter{
308518334Speter  int value = 0;
308618334Speter
308718334Speter  if (cc_status.flags & CC_REVERSED)
308818334Speter    {
308918334Speter      value = 2;
309018334Speter      PUT_CODE (cond, swap_condition (GET_CODE (cond)));
309118334Speter    }
309218334Speter
309318334Speter  if (cc_status.flags & CC_INVERTED)
309418334Speter    {
309518334Speter      value = 2;
309618334Speter      PUT_CODE (cond, reverse_condition (GET_CODE (cond)));
309718334Speter    }
309818334Speter
309918334Speter  if (cc_status.flags & CC_NOT_POSITIVE)
310018334Speter    switch (GET_CODE (cond))
310118334Speter      {
310218334Speter      case LE:
310318334Speter      case LEU:
310418334Speter      case GEU:
310518334Speter	/* Jump becomes unconditional.  */
310618334Speter	return 1;
310718334Speter
310818334Speter      case GT:
310918334Speter      case GTU:
311018334Speter      case LTU:
311118334Speter	/* Jump becomes no-op.  */
311218334Speter	return -1;
311318334Speter
311418334Speter      case GE:
311518334Speter	PUT_CODE (cond, EQ);
311618334Speter	value = 2;
311718334Speter	break;
311818334Speter
311918334Speter      case LT:
312018334Speter	PUT_CODE (cond, NE);
312118334Speter	value = 2;
312218334Speter	break;
312350503Sobrien
312450503Sobrien      default:
312550503Sobrien	break;
312618334Speter      }
312718334Speter
312818334Speter  if (cc_status.flags & CC_NOT_NEGATIVE)
312918334Speter    switch (GET_CODE (cond))
313018334Speter      {
313118334Speter      case GE:
313218334Speter      case GEU:
313318334Speter	/* Jump becomes unconditional.  */
313418334Speter	return 1;
313518334Speter
313618334Speter      case LT:
313718334Speter      case LTU:
313818334Speter	/* Jump becomes no-op.  */
313918334Speter	return -1;
314018334Speter
314118334Speter      case LE:
314218334Speter      case LEU:
314318334Speter	PUT_CODE (cond, EQ);
314418334Speter	value = 2;
314518334Speter	break;
314618334Speter
314718334Speter      case GT:
314818334Speter      case GTU:
314918334Speter	PUT_CODE (cond, NE);
315018334Speter	value = 2;
315118334Speter	break;
315250503Sobrien
315350503Sobrien      default:
315450503Sobrien	break;
315518334Speter      }
315618334Speter
315718334Speter  if (cc_status.flags & CC_NO_OVERFLOW)
315818334Speter    switch (GET_CODE (cond))
315918334Speter      {
316018334Speter      case GEU:
316118334Speter	/* Jump becomes unconditional.  */
316218334Speter	return 1;
316318334Speter
316418334Speter      case LEU:
316518334Speter	PUT_CODE (cond, EQ);
316618334Speter	value = 2;
316718334Speter	break;
316818334Speter
316918334Speter      case GTU:
317018334Speter	PUT_CODE (cond, NE);
317118334Speter	value = 2;
317218334Speter	break;
317318334Speter
317418334Speter      case LTU:
317518334Speter	/* Jump becomes no-op.  */
317618334Speter	return -1;
317750503Sobrien
317850503Sobrien      default:
317950503Sobrien	break;
318018334Speter      }
318118334Speter
318218334Speter  if (cc_status.flags & (CC_Z_IN_NOT_N | CC_Z_IN_N))
318318334Speter    switch (GET_CODE (cond))
318418334Speter      {
318550503Sobrien      default:
318618334Speter	abort ();
318718334Speter
318818334Speter      case NE:
318918334Speter	PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? GE : LT);
319018334Speter	value = 2;
319118334Speter	break;
319218334Speter
319318334Speter      case EQ:
319418334Speter	PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? LT : GE);
319518334Speter	value = 2;
319618334Speter	break;
319718334Speter      }
319818334Speter
319918334Speter  if (cc_status.flags & CC_NOT_SIGNED)
320018334Speter    /* The flags are valid if signed condition operators are converted
320118334Speter       to unsigned.  */
320218334Speter    switch (GET_CODE (cond))
320318334Speter      {
320418334Speter      case LE:
320518334Speter	PUT_CODE (cond, LEU);
320618334Speter	value = 2;
320718334Speter	break;
320818334Speter
320918334Speter      case LT:
321018334Speter	PUT_CODE (cond, LTU);
321118334Speter	value = 2;
321218334Speter	break;
321318334Speter
321418334Speter      case GT:
321518334Speter	PUT_CODE (cond, GTU);
321618334Speter	value = 2;
321718334Speter	break;
321818334Speter
321918334Speter      case GE:
322018334Speter	PUT_CODE (cond, GEU);
322118334Speter	value = 2;
322218334Speter	break;
322350503Sobrien
322450503Sobrien      default:
322550503Sobrien	break;
322618334Speter      }
322718334Speter
322818334Speter  return value;
322918334Speter}
323018334Speter#endif
323118334Speter
323218334Speter/* Report inconsistency between the assembler template and the operands.
323318334Speter   In an `asm', it's the user's fault; otherwise, the compiler's fault.  */
323418334Speter
323518334Spetervoid
323618334Speteroutput_operand_lossage (str)
323718334Speter     char *str;
323818334Speter{
323918334Speter  if (this_is_asm_operands)
324018334Speter    error_for_asm (this_is_asm_operands, "invalid `asm': %s", str);
324118334Speter  else
324250503Sobrien    fatal ("Internal compiler error, output_operand_lossage `%s'", str);
324318334Speter}
324418334Speter
324518334Speter/* Output of assembler code from a template, and its subroutines.  */
324618334Speter
324718334Speter/* Output text from TEMPLATE to the assembler output file,
324818334Speter   obeying %-directions to substitute operands taken from
324918334Speter   the vector OPERANDS.
325018334Speter
325118334Speter   %N (for N a digit) means print operand N in usual manner.
325218334Speter   %lN means require operand N to be a CODE_LABEL or LABEL_REF
325318334Speter      and print the label name with no punctuation.
325418334Speter   %cN means require operand N to be a constant
325518334Speter      and print the constant expression with no punctuation.
325618334Speter   %aN means expect operand N to be a memory address
325718334Speter      (not a memory reference!) and print a reference
325818334Speter      to that address.
325918334Speter   %nN means expect operand N to be a constant
326018334Speter      and print a constant expression for minus the value
326118334Speter      of the operand, with no other punctuation.  */
326218334Speter
326318334Speterstatic void
326418334Speteroutput_asm_name ()
326518334Speter{
326618334Speter  if (flag_print_asm_name)
326718334Speter    {
326818334Speter      /* Annotate the assembly with a comment describing the pattern and
326918334Speter	 alternative used.  */
327018334Speter      if (debug_insn)
327118334Speter	{
327218334Speter	  register int num = INSN_CODE (debug_insn);
327318334Speter	  fprintf (asm_out_file, " %s %d %s",
327418334Speter		   ASM_COMMENT_START, INSN_UID (debug_insn), insn_name[num]);
327518334Speter	  if (insn_n_alternatives[num] > 1)
327618334Speter	    fprintf (asm_out_file, "/%d", which_alternative + 1);
327718334Speter
327818334Speter	  /* Clear this so only the first assembler insn
327918334Speter	     of any rtl insn will get the special comment for -dp.  */
328018334Speter	  debug_insn = 0;
328118334Speter	}
328218334Speter    }
328318334Speter}
328418334Speter
328518334Spetervoid
328618334Speteroutput_asm_insn (template, operands)
328718334Speter     char *template;
328818334Speter     rtx *operands;
328918334Speter{
329018334Speter  register char *p;
329150503Sobrien  register int c;
329218334Speter
329318334Speter  /* An insn may return a null string template
329418334Speter     in a case where no assembler code is needed.  */
329518334Speter  if (*template == 0)
329618334Speter    return;
329718334Speter
329818334Speter  p = template;
329918334Speter  putc ('\t', asm_out_file);
330018334Speter
330118334Speter#ifdef ASM_OUTPUT_OPCODE
330218334Speter  ASM_OUTPUT_OPCODE (asm_out_file, p);
330318334Speter#endif
330418334Speter
330550503Sobrien  while ((c = *p++))
330618334Speter    switch (c)
330718334Speter      {
330818334Speter      case '\n':
330918334Speter	output_asm_name ();
331018334Speter	putc (c, asm_out_file);
331118334Speter#ifdef ASM_OUTPUT_OPCODE
331218334Speter	while ((c = *p) == '\t')
331318334Speter	  {
331418334Speter	    putc (c, asm_out_file);
331518334Speter	    p++;
331618334Speter	  }
331718334Speter	ASM_OUTPUT_OPCODE (asm_out_file, p);
331818334Speter#endif
331918334Speter	break;
332018334Speter
332118334Speter#ifdef ASSEMBLER_DIALECT
332218334Speter      case '{':
332350503Sobrien	{
332450503Sobrien	  register int i;
332550503Sobrien
332650503Sobrien	  /* If we want the first dialect, do nothing.  Otherwise, skip
332750503Sobrien	     DIALECT_NUMBER of strings ending with '|'.  */
332850503Sobrien	  for (i = 0; i < dialect_number; i++)
332950503Sobrien	    {
333050503Sobrien	      while (*p && *p++ != '|')
333150503Sobrien		;
333218334Speter
333350503Sobrien	      if (*p == '|')
333450503Sobrien		p++;
333550503Sobrien	    }
333650503Sobrien	}
333718334Speter	break;
333818334Speter
333918334Speter      case '|':
334018334Speter	/* Skip to close brace.  */
334118334Speter	while (*p && *p++ != '}')
334218334Speter	  ;
334318334Speter	break;
334418334Speter
334518334Speter      case '}':
334618334Speter	break;
334718334Speter#endif
334818334Speter
334918334Speter      case '%':
335018334Speter	/* %% outputs a single %.  */
335118334Speter	if (*p == '%')
335218334Speter	  {
335318334Speter	    p++;
335418334Speter	    putc (c, asm_out_file);
335518334Speter	  }
335618334Speter	/* %= outputs a number which is unique to each insn in the entire
335718334Speter	   compilation.  This is useful for making local labels that are
335818334Speter	   referred to more than once in a given insn.  */
335918334Speter	else if (*p == '=')
336018334Speter	  {
336118334Speter	    p++;
336218334Speter	    fprintf (asm_out_file, "%d", insn_counter);
336318334Speter	  }
336418334Speter	/* % followed by a letter and some digits
336518334Speter	   outputs an operand in a special way depending on the letter.
336618334Speter	   Letters `acln' are implemented directly.
336718334Speter	   Other letters are passed to `output_operand' so that
336818334Speter	   the PRINT_OPERAND macro can define them.  */
336918334Speter	else if ((*p >= 'a' && *p <= 'z')
337018334Speter		 || (*p >= 'A' && *p <= 'Z'))
337118334Speter	  {
337218334Speter	    int letter = *p++;
337318334Speter	    c = atoi (p);
337418334Speter
337518334Speter	    if (! (*p >= '0' && *p <= '9'))
337618334Speter	      output_operand_lossage ("operand number missing after %-letter");
337750503Sobrien	    else if (this_is_asm_operands && (c < 0 || (unsigned int) c >= insn_noperands))
337818334Speter	      output_operand_lossage ("operand number out of range");
337918334Speter	    else if (letter == 'l')
338018334Speter	      output_asm_label (operands[c]);
338118334Speter	    else if (letter == 'a')
338218334Speter	      output_address (operands[c]);
338318334Speter	    else if (letter == 'c')
338418334Speter	      {
338518334Speter		if (CONSTANT_ADDRESS_P (operands[c]))
338618334Speter		  output_addr_const (asm_out_file, operands[c]);
338718334Speter		else
338818334Speter		  output_operand (operands[c], 'c');
338918334Speter	      }
339018334Speter	    else if (letter == 'n')
339118334Speter	      {
339218334Speter		if (GET_CODE (operands[c]) == CONST_INT)
339350503Sobrien		  fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC,
339418334Speter			   - INTVAL (operands[c]));
339518334Speter		else
339618334Speter		  {
339718334Speter		    putc ('-', asm_out_file);
339818334Speter		    output_addr_const (asm_out_file, operands[c]);
339918334Speter		  }
340018334Speter	      }
340118334Speter	    else
340218334Speter	      output_operand (operands[c], letter);
340318334Speter
340418334Speter	    while ((c = *p) >= '0' && c <= '9') p++;
340518334Speter	  }
340618334Speter	/* % followed by a digit outputs an operand the default way.  */
340718334Speter	else if (*p >= '0' && *p <= '9')
340818334Speter	  {
340918334Speter	    c = atoi (p);
341050503Sobrien	    if (this_is_asm_operands && (c < 0 || (unsigned int) c >= insn_noperands))
341118334Speter	      output_operand_lossage ("operand number out of range");
341218334Speter	    else
341318334Speter	      output_operand (operands[c], 0);
341418334Speter	    while ((c = *p) >= '0' && c <= '9') p++;
341518334Speter	  }
341618334Speter	/* % followed by punctuation: output something for that
341718334Speter	   punctuation character alone, with no operand.
341818334Speter	   The PRINT_OPERAND macro decides what is actually done.  */
341918334Speter#ifdef PRINT_OPERAND_PUNCT_VALID_P
342018334Speter	else if (PRINT_OPERAND_PUNCT_VALID_P (*p))
342118334Speter	  output_operand (NULL_RTX, *p++);
342218334Speter#endif
342318334Speter	else
342418334Speter	  output_operand_lossage ("invalid %%-code");
342518334Speter	break;
342618334Speter
342718334Speter      default:
342818334Speter	putc (c, asm_out_file);
342918334Speter      }
343018334Speter
343118334Speter  output_asm_name ();
343218334Speter
343318334Speter  putc ('\n', asm_out_file);
343418334Speter}
343518334Speter
343618334Speter/* Output a LABEL_REF, or a bare CODE_LABEL, as an assembler symbol.  */
343718334Speter
343818334Spetervoid
343918334Speteroutput_asm_label (x)
344018334Speter     rtx x;
344118334Speter{
344218334Speter  char buf[256];
344318334Speter
344418334Speter  if (GET_CODE (x) == LABEL_REF)
344518334Speter    ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0)));
344618334Speter  else if (GET_CODE (x) == CODE_LABEL)
344718334Speter    ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
344818334Speter  else
344918334Speter    output_operand_lossage ("`%l' operand isn't a label");
345018334Speter
345118334Speter  assemble_name (asm_out_file, buf);
345218334Speter}
345318334Speter
345418334Speter/* Print operand X using machine-dependent assembler syntax.
345518334Speter   The macro PRINT_OPERAND is defined just to control this function.
345618334Speter   CODE is a non-digit that preceded the operand-number in the % spec,
345718334Speter   such as 'z' if the spec was `%z3'.  CODE is 0 if there was no char
345818334Speter   between the % and the digits.
345918334Speter   When CODE is a non-letter, X is 0.
346018334Speter
346118334Speter   The meanings of the letters are machine-dependent and controlled
346218334Speter   by PRINT_OPERAND.  */
346318334Speter
346418334Speterstatic void
346518334Speteroutput_operand (x, code)
346618334Speter     rtx x;
346718334Speter     int code;
346818334Speter{
346918334Speter  if (x && GET_CODE (x) == SUBREG)
347018334Speter    x = alter_subreg (x);
347118334Speter
347218334Speter  /* If X is a pseudo-register, abort now rather than writing trash to the
347318334Speter     assembler file.  */
347418334Speter
347518334Speter  if (x && GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER)
347618334Speter    abort ();
347718334Speter
347818334Speter  PRINT_OPERAND (asm_out_file, x, code);
347918334Speter}
348018334Speter
348118334Speter/* Print a memory reference operand for address X
348218334Speter   using machine-dependent assembler syntax.
348318334Speter   The macro PRINT_OPERAND_ADDRESS exists just to control this function.  */
348418334Speter
348518334Spetervoid
348618334Speteroutput_address (x)
348718334Speter     rtx x;
348818334Speter{
348918334Speter  walk_alter_subreg (x);
349018334Speter  PRINT_OPERAND_ADDRESS (asm_out_file, x);
349118334Speter}
349218334Speter
349318334Speter/* Print an integer constant expression in assembler syntax.
349418334Speter   Addition and subtraction are the only arithmetic
349518334Speter   that may appear in these expressions.  */
349618334Speter
349718334Spetervoid
349818334Speteroutput_addr_const (file, x)
349918334Speter     FILE *file;
350018334Speter     rtx x;
350118334Speter{
350218334Speter  char buf[256];
350318334Speter
350418334Speter restart:
350518334Speter  switch (GET_CODE (x))
350618334Speter    {
350718334Speter    case PC:
350818334Speter      if (flag_pic)
350918334Speter	putc ('.', file);
351018334Speter      else
351118334Speter	abort ();
351218334Speter      break;
351318334Speter
351418334Speter    case SYMBOL_REF:
351518334Speter      assemble_name (file, XSTR (x, 0));
351618334Speter      break;
351718334Speter
351818334Speter    case LABEL_REF:
351918334Speter      ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0)));
352018334Speter      assemble_name (file, buf);
352118334Speter      break;
352218334Speter
352318334Speter    case CODE_LABEL:
352418334Speter      ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
352518334Speter      assemble_name (file, buf);
352618334Speter      break;
352718334Speter
352818334Speter    case CONST_INT:
352950503Sobrien      fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
353018334Speter      break;
353118334Speter
353218334Speter    case CONST:
353318334Speter      /* This used to output parentheses around the expression,
353418334Speter	 but that does not work on the 386 (either ATT or BSD assembler).  */
353518334Speter      output_addr_const (file, XEXP (x, 0));
353618334Speter      break;
353718334Speter
353818334Speter    case CONST_DOUBLE:
353918334Speter      if (GET_MODE (x) == VOIDmode)
354018334Speter	{
354118334Speter	  /* We can use %d if the number is one word and positive.  */
354218334Speter	  if (CONST_DOUBLE_HIGH (x))
354350503Sobrien	    fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
354418334Speter		     CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x));
354518334Speter	  else if  (CONST_DOUBLE_LOW (x) < 0)
354650503Sobrien	    fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (x));
354718334Speter	  else
354850503Sobrien	    fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x));
354918334Speter	}
355018334Speter      else
355118334Speter	/* We can't handle floating point constants;
355218334Speter	   PRINT_OPERAND must handle them.  */
355318334Speter	output_operand_lossage ("floating constant misused");
355418334Speter      break;
355518334Speter
355618334Speter    case PLUS:
355718334Speter      /* Some assemblers need integer constants to appear last (eg masm).  */
355818334Speter      if (GET_CODE (XEXP (x, 0)) == CONST_INT)
355918334Speter	{
356018334Speter	  output_addr_const (file, XEXP (x, 1));
356118334Speter	  if (INTVAL (XEXP (x, 0)) >= 0)
356218334Speter	    fprintf (file, "+");
356318334Speter	  output_addr_const (file, XEXP (x, 0));
356418334Speter	}
356518334Speter      else
356618334Speter	{
356718334Speter	  output_addr_const (file, XEXP (x, 0));
356818334Speter	  if (INTVAL (XEXP (x, 1)) >= 0)
356918334Speter	    fprintf (file, "+");
357018334Speter	  output_addr_const (file, XEXP (x, 1));
357118334Speter	}
357218334Speter      break;
357318334Speter
357418334Speter    case MINUS:
357518334Speter      /* Avoid outputting things like x-x or x+5-x,
357618334Speter	 since some assemblers can't handle that.  */
357718334Speter      x = simplify_subtraction (x);
357818334Speter      if (GET_CODE (x) != MINUS)
357918334Speter	goto restart;
358018334Speter
358118334Speter      output_addr_const (file, XEXP (x, 0));
358218334Speter      fprintf (file, "-");
358318334Speter      if (GET_CODE (XEXP (x, 1)) == CONST_INT
358418334Speter	  && INTVAL (XEXP (x, 1)) < 0)
358518334Speter	{
358618334Speter	  fprintf (file, ASM_OPEN_PAREN);
358718334Speter	  output_addr_const (file, XEXP (x, 1));
358818334Speter	  fprintf (file, ASM_CLOSE_PAREN);
358918334Speter	}
359018334Speter      else
359118334Speter	output_addr_const (file, XEXP (x, 1));
359218334Speter      break;
359318334Speter
359418334Speter    case ZERO_EXTEND:
359518334Speter    case SIGN_EXTEND:
359618334Speter      output_addr_const (file, XEXP (x, 0));
359718334Speter      break;
359818334Speter
359918334Speter    default:
360018334Speter      output_operand_lossage ("invalid expression as operand");
360118334Speter    }
360218334Speter}
360318334Speter
360418334Speter/* A poor man's fprintf, with the added features of %I, %R, %L, and %U.
360518334Speter   %R prints the value of REGISTER_PREFIX.
360618334Speter   %L prints the value of LOCAL_LABEL_PREFIX.
360718334Speter   %U prints the value of USER_LABEL_PREFIX.
360818334Speter   %I prints the value of IMMEDIATE_PREFIX.
360918334Speter   %O runs ASM_OUTPUT_OPCODE to transform what follows in the string.
361018334Speter   Also supported are %d, %x, %s, %e, %f, %g and %%.
361118334Speter
361218334Speter   We handle alternate assembler dialects here, just like output_asm_insn.  */
361318334Speter
361418334Spetervoid
361518334Speterasm_fprintf VPROTO((FILE *file, char *p, ...))
361618334Speter{
361718334Speter#ifndef __STDC__
361818334Speter  FILE *file;
361918334Speter  char *p;
362018334Speter#endif
362118334Speter  va_list argptr;
362218334Speter  char buf[10];
362318334Speter  char *q, c;
362418334Speter
362518334Speter  VA_START (argptr, p);
362618334Speter
362718334Speter#ifndef __STDC__
362850503Sobrien  file = va_arg (argptr, FILE *);
362950503Sobrien  p = va_arg (argptr, char *);
363018334Speter#endif
363118334Speter
363218334Speter  buf[0] = '%';
363318334Speter
363450503Sobrien  while ((c = *p++))
363518334Speter    switch (c)
363618334Speter      {
363718334Speter#ifdef ASSEMBLER_DIALECT
363818334Speter      case '{':
363950503Sobrien	{
364050503Sobrien	  int i;
364118334Speter
364250503Sobrien	  /* If we want the first dialect, do nothing.  Otherwise, skip
364350503Sobrien	     DIALECT_NUMBER of strings ending with '|'.  */
364450503Sobrien	  for (i = 0; i < dialect_number; i++)
364550503Sobrien	    {
364650503Sobrien	      while (*p && *p++ != '|')
364750503Sobrien		;
364850503Sobrien
364950503Sobrien	      if (*p == '|')
365050503Sobrien		p++;
365118334Speter	  }
365250503Sobrien	}
365318334Speter	break;
365418334Speter
365518334Speter      case '|':
365618334Speter	/* Skip to close brace.  */
365718334Speter	while (*p && *p++ != '}')
365818334Speter	  ;
365918334Speter	break;
366018334Speter
366118334Speter      case '}':
366218334Speter	break;
366318334Speter#endif
366418334Speter
366518334Speter      case '%':
366618334Speter	c = *p++;
366718334Speter	q = &buf[1];
366818334Speter	while ((c >= '0' && c <= '9') || c == '.')
366918334Speter	  {
367018334Speter	    *q++ = c;
367118334Speter	    c = *p++;
367218334Speter	  }
367318334Speter	switch (c)
367418334Speter	  {
367518334Speter	  case '%':
367618334Speter	    fprintf (file, "%%");
367718334Speter	    break;
367818334Speter
367918334Speter	  case 'd':  case 'i':  case 'u':
368018334Speter	  case 'x':  case 'p':  case 'X':
368118334Speter	  case 'o':
368218334Speter	    *q++ = c;
368318334Speter	    *q = 0;
368418334Speter	    fprintf (file, buf, va_arg (argptr, int));
368518334Speter	    break;
368618334Speter
368718334Speter	  case 'w':
368818334Speter	    /* This is a prefix to the 'd', 'i', 'u', 'x', 'p', and 'X' cases,
368918334Speter	       but we do not check for those cases.  It means that the value
369018334Speter	       is a HOST_WIDE_INT, which may be either `int' or `long'.  */
369118334Speter
369250503Sobrien#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
369350503Sobrien#else
369450503Sobrien#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
369518334Speter	    *q++ = 'l';
369650503Sobrien#else
369750503Sobrien	    *q++ = 'l';
369850503Sobrien	    *q++ = 'l';
369918334Speter#endif
370050503Sobrien#endif
370118334Speter
370218334Speter	    *q++ = *p++;
370318334Speter	    *q = 0;
370418334Speter	    fprintf (file, buf, va_arg (argptr, HOST_WIDE_INT));
370518334Speter	    break;
370618334Speter
370718334Speter	  case 'l':
370818334Speter	    *q++ = c;
370918334Speter	    *q++ = *p++;
371018334Speter	    *q = 0;
371118334Speter	    fprintf (file, buf, va_arg (argptr, long));
371218334Speter	    break;
371318334Speter
371418334Speter	  case 'e':
371518334Speter	  case 'f':
371618334Speter	  case 'g':
371718334Speter	    *q++ = c;
371818334Speter	    *q = 0;
371918334Speter	    fprintf (file, buf, va_arg (argptr, double));
372018334Speter	    break;
372118334Speter
372218334Speter	  case 's':
372318334Speter	    *q++ = c;
372418334Speter	    *q = 0;
372518334Speter	    fprintf (file, buf, va_arg (argptr, char *));
372618334Speter	    break;
372718334Speter
372818334Speter	  case 'O':
372918334Speter#ifdef ASM_OUTPUT_OPCODE
373018334Speter	    ASM_OUTPUT_OPCODE (asm_out_file, p);
373118334Speter#endif
373218334Speter	    break;
373318334Speter
373418334Speter	  case 'R':
373518334Speter#ifdef REGISTER_PREFIX
373618334Speter	    fprintf (file, "%s", REGISTER_PREFIX);
373718334Speter#endif
373818334Speter	    break;
373918334Speter
374018334Speter	  case 'I':
374118334Speter#ifdef IMMEDIATE_PREFIX
374218334Speter	    fprintf (file, "%s", IMMEDIATE_PREFIX);
374318334Speter#endif
374418334Speter	    break;
374518334Speter
374618334Speter	  case 'L':
374718334Speter#ifdef LOCAL_LABEL_PREFIX
374818334Speter	    fprintf (file, "%s", LOCAL_LABEL_PREFIX);
374918334Speter#endif
375018334Speter	    break;
375118334Speter
375218334Speter	  case 'U':
375318334Speter#ifdef USER_LABEL_PREFIX
375418334Speter	    fprintf (file, "%s", USER_LABEL_PREFIX);
375518334Speter#endif
375618334Speter	    break;
375718334Speter
375818334Speter	  default:
375918334Speter	    abort ();
376018334Speter	  }
376118334Speter	break;
376218334Speter
376318334Speter      default:
376418334Speter	fputc (c, file);
376518334Speter      }
376618334Speter}
376718334Speter
376818334Speter/* Split up a CONST_DOUBLE or integer constant rtx
376918334Speter   into two rtx's for single words,
377018334Speter   storing in *FIRST the word that comes first in memory in the target
377118334Speter   and in *SECOND the other.  */
377218334Speter
377318334Spetervoid
377418334Spetersplit_double (value, first, second)
377518334Speter     rtx value;
377618334Speter     rtx *first, *second;
377718334Speter{
377818334Speter  if (GET_CODE (value) == CONST_INT)
377918334Speter    {
378018334Speter      if (HOST_BITS_PER_WIDE_INT >= (2 * BITS_PER_WORD))
378118334Speter	{
378218334Speter	  /* In this case the CONST_INT holds both target words.
378350503Sobrien	     Extract the bits from it into two word-sized pieces.
378450503Sobrien	     Sign extend each half to HOST_WIDE_INT.  */
378518334Speter	  rtx low, high;
378650503Sobrien	  /* On machines where HOST_BITS_PER_WIDE_INT == BITS_PER_WORD
378750503Sobrien	     the shift below will cause a compiler warning, even though
378850503Sobrien	     this code won't be executed.  So put the shift amounts in
378950503Sobrien	     variables to avoid the warning.  */
379050503Sobrien	  int rshift = HOST_BITS_PER_WIDE_INT - BITS_PER_WORD;
379150503Sobrien	  int lshift = HOST_BITS_PER_WIDE_INT - 2 * BITS_PER_WORD;
379218334Speter
379350503Sobrien	  low = GEN_INT ((INTVAL (value) << rshift) >> rshift);
379450503Sobrien	  high = GEN_INT ((INTVAL (value) << lshift) >> rshift);
379518334Speter	  if (WORDS_BIG_ENDIAN)
379618334Speter	    {
379718334Speter	      *first = high;
379818334Speter	      *second = low;
379918334Speter	    }
380018334Speter	  else
380118334Speter	    {
380218334Speter	      *first = low;
380318334Speter	      *second = high;
380418334Speter	    }
380518334Speter	}
380618334Speter      else
380718334Speter	{
380818334Speter	  /* The rule for using CONST_INT for a wider mode
380918334Speter	     is that we regard the value as signed.
381018334Speter	     So sign-extend it.  */
381118334Speter	  rtx high = (INTVAL (value) < 0 ? constm1_rtx : const0_rtx);
381218334Speter	  if (WORDS_BIG_ENDIAN)
381318334Speter	    {
381418334Speter	      *first = high;
381518334Speter	      *second = value;
381618334Speter	    }
381718334Speter	  else
381818334Speter	    {
381918334Speter	      *first = value;
382018334Speter	      *second = high;
382118334Speter	    }
382218334Speter	}
382318334Speter    }
382418334Speter  else if (GET_CODE (value) != CONST_DOUBLE)
382518334Speter    {
382618334Speter      if (WORDS_BIG_ENDIAN)
382718334Speter	{
382818334Speter	  *first = const0_rtx;
382918334Speter	  *second = value;
383018334Speter	}
383118334Speter      else
383218334Speter	{
383318334Speter	  *first = value;
383418334Speter	  *second = const0_rtx;
383518334Speter	}
383618334Speter    }
383718334Speter  else if (GET_MODE (value) == VOIDmode
383818334Speter	   /* This is the old way we did CONST_DOUBLE integers.  */
383918334Speter	   || GET_MODE_CLASS (GET_MODE (value)) == MODE_INT)
384018334Speter    {
384118334Speter      /* In an integer, the words are defined as most and least significant.
384218334Speter	 So order them by the target's convention.  */
384318334Speter      if (WORDS_BIG_ENDIAN)
384418334Speter	{
384518334Speter	  *first = GEN_INT (CONST_DOUBLE_HIGH (value));
384618334Speter	  *second = GEN_INT (CONST_DOUBLE_LOW (value));
384718334Speter	}
384818334Speter      else
384918334Speter	{
385018334Speter	  *first = GEN_INT (CONST_DOUBLE_LOW (value));
385118334Speter	  *second = GEN_INT (CONST_DOUBLE_HIGH (value));
385218334Speter	}
385318334Speter    }
385418334Speter  else
385518334Speter    {
385618334Speter#ifdef REAL_ARITHMETIC
385718334Speter      REAL_VALUE_TYPE r; long l[2];
385818334Speter      REAL_VALUE_FROM_CONST_DOUBLE (r, value);
385918334Speter
386018334Speter      /* Note, this converts the REAL_VALUE_TYPE to the target's
386118334Speter	 format, splits up the floating point double and outputs
386218334Speter	 exactly 32 bits of it into each of l[0] and l[1] --
386350503Sobrien	 not necessarily BITS_PER_WORD bits.  */
386418334Speter      REAL_VALUE_TO_TARGET_DOUBLE (r, l);
386518334Speter
386618334Speter      *first = GEN_INT ((HOST_WIDE_INT) l[0]);
386718334Speter      *second = GEN_INT ((HOST_WIDE_INT) l[1]);
386818334Speter#else
386918334Speter      if ((HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
387018334Speter	   || HOST_BITS_PER_WIDE_INT != BITS_PER_WORD)
387118334Speter	  && ! flag_pretend_float)
387218334Speter      abort ();
387318334Speter
387418334Speter      if (
387518334Speter#ifdef HOST_WORDS_BIG_ENDIAN
387618334Speter	  WORDS_BIG_ENDIAN
387718334Speter#else
387818334Speter	  ! WORDS_BIG_ENDIAN
387918334Speter#endif
388018334Speter	  )
388118334Speter	{
388218334Speter	  /* Host and target agree => no need to swap.  */
388318334Speter	  *first = GEN_INT (CONST_DOUBLE_LOW (value));
388418334Speter	  *second = GEN_INT (CONST_DOUBLE_HIGH (value));
388518334Speter	}
388618334Speter      else
388718334Speter	{
388818334Speter	  *second = GEN_INT (CONST_DOUBLE_LOW (value));
388918334Speter	  *first = GEN_INT (CONST_DOUBLE_HIGH (value));
389018334Speter	}
389118334Speter#endif /* no REAL_ARITHMETIC */
389218334Speter    }
389318334Speter}
389418334Speter
389518334Speter/* Return nonzero if this function has no function calls.  */
389618334Speter
389718334Speterint
389818334Speterleaf_function_p ()
389918334Speter{
390018334Speter  rtx insn;
390118334Speter
390250503Sobrien  if (profile_flag || profile_block_flag || profile_arc_flag)
390318334Speter    return 0;
390418334Speter
390518334Speter  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
390618334Speter    {
390718334Speter      if (GET_CODE (insn) == CALL_INSN)
390818334Speter	return 0;
390918334Speter      if (GET_CODE (insn) == INSN
391018334Speter	  && GET_CODE (PATTERN (insn)) == SEQUENCE
391118334Speter	  && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN)
391218334Speter	return 0;
391318334Speter    }
391418334Speter  for (insn = current_function_epilogue_delay_list; insn; insn = XEXP (insn, 1))
391518334Speter    {
391618334Speter      if (GET_CODE (XEXP (insn, 0)) == CALL_INSN)
391718334Speter	return 0;
391818334Speter      if (GET_CODE (XEXP (insn, 0)) == INSN
391918334Speter	  && GET_CODE (PATTERN (XEXP (insn, 0))) == SEQUENCE
392018334Speter	  && GET_CODE (XVECEXP (PATTERN (XEXP (insn, 0)), 0, 0)) == CALL_INSN)
392118334Speter	return 0;
392218334Speter    }
392318334Speter
392418334Speter  return 1;
392518334Speter}
392618334Speter
392718334Speter/* On some machines, a function with no call insns
392818334Speter   can run faster if it doesn't create its own register window.
392918334Speter   When output, the leaf function should use only the "output"
393018334Speter   registers.  Ordinarily, the function would be compiled to use
393118334Speter   the "input" registers to find its arguments; it is a candidate
393218334Speter   for leaf treatment if it uses only the "input" registers.
393318334Speter   Leaf function treatment means renumbering so the function
393418334Speter   uses the "output" registers instead.  */
393518334Speter
393618334Speter#ifdef LEAF_REGISTERS
393718334Speter
393818334Speterstatic char permitted_reg_in_leaf_functions[] = LEAF_REGISTERS;
393918334Speter
394018334Speter/* Return 1 if this function uses only the registers that can be
394118334Speter   safely renumbered.  */
394218334Speter
394318334Speterint
394418334Speteronly_leaf_regs_used ()
394518334Speter{
394618334Speter  int i;
394718334Speter
394818334Speter  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
394950503Sobrien    if ((regs_ever_live[i] || global_regs[i])
395050503Sobrien	&& ! permitted_reg_in_leaf_functions[i])
395150503Sobrien      return 0;
395250503Sobrien
395350503Sobrien  if (current_function_uses_pic_offset_table
395450503Sobrien      && pic_offset_table_rtx != 0
395550503Sobrien      && GET_CODE (pic_offset_table_rtx) == REG
395650503Sobrien      && ! permitted_reg_in_leaf_functions[REGNO (pic_offset_table_rtx)])
395750503Sobrien    return 0;
395850503Sobrien
395918334Speter  return 1;
396018334Speter}
396118334Speter
396218334Speter/* Scan all instructions and renumber all registers into those
396318334Speter   available in leaf functions.  */
396418334Speter
396518334Speterstatic void
396618334Speterleaf_renumber_regs (first)
396718334Speter     rtx first;
396818334Speter{
396918334Speter  rtx insn;
397018334Speter
397118334Speter  /* Renumber only the actual patterns.
397218334Speter     The reg-notes can contain frame pointer refs,
397318334Speter     and renumbering them could crash, and should not be needed.  */
397418334Speter  for (insn = first; insn; insn = NEXT_INSN (insn))
397518334Speter    if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
397618334Speter      leaf_renumber_regs_insn (PATTERN (insn));
397718334Speter  for (insn = current_function_epilogue_delay_list; insn; insn = XEXP (insn, 1))
397818334Speter    if (GET_RTX_CLASS (GET_CODE (XEXP (insn, 0))) == 'i')
397918334Speter      leaf_renumber_regs_insn (PATTERN (XEXP (insn, 0)));
398018334Speter}
398118334Speter
398218334Speter/* Scan IN_RTX and its subexpressions, and renumber all regs into those
398318334Speter   available in leaf functions.  */
398418334Speter
398518334Spetervoid
398618334Speterleaf_renumber_regs_insn (in_rtx)
398718334Speter     register rtx in_rtx;
398818334Speter{
398918334Speter  register int i, j;
399018334Speter  register char *format_ptr;
399118334Speter
399218334Speter  if (in_rtx == 0)
399318334Speter    return;
399418334Speter
399518334Speter  /* Renumber all input-registers into output-registers.
399618334Speter     renumbered_regs would be 1 for an output-register;
399718334Speter     they  */
399818334Speter
399918334Speter  if (GET_CODE (in_rtx) == REG)
400018334Speter    {
400118334Speter      int newreg;
400218334Speter
400318334Speter      /* Don't renumber the same reg twice.  */
400418334Speter      if (in_rtx->used)
400518334Speter	return;
400618334Speter
400718334Speter      newreg = REGNO (in_rtx);
400818334Speter      /* Don't try to renumber pseudo regs.  It is possible for a pseudo reg
400918334Speter	 to reach here as part of a REG_NOTE.  */
401018334Speter      if (newreg >= FIRST_PSEUDO_REGISTER)
401118334Speter	{
401218334Speter	  in_rtx->used = 1;
401318334Speter	  return;
401418334Speter	}
401518334Speter      newreg = LEAF_REG_REMAP (newreg);
401618334Speter      if (newreg < 0)
401718334Speter	abort ();
401818334Speter      regs_ever_live[REGNO (in_rtx)] = 0;
401918334Speter      regs_ever_live[newreg] = 1;
402018334Speter      REGNO (in_rtx) = newreg;
402118334Speter      in_rtx->used = 1;
402218334Speter    }
402318334Speter
402418334Speter  if (GET_RTX_CLASS (GET_CODE (in_rtx)) == 'i')
402518334Speter    {
402618334Speter      /* Inside a SEQUENCE, we find insns.
402718334Speter	 Renumber just the patterns of these insns,
402818334Speter	 just as we do for the top-level insns.  */
402918334Speter      leaf_renumber_regs_insn (PATTERN (in_rtx));
403018334Speter      return;
403118334Speter    }
403218334Speter
403318334Speter  format_ptr = GET_RTX_FORMAT (GET_CODE (in_rtx));
403418334Speter
403518334Speter  for (i = 0; i < GET_RTX_LENGTH (GET_CODE (in_rtx)); i++)
403618334Speter    switch (*format_ptr++)
403718334Speter      {
403818334Speter      case 'e':
403918334Speter	leaf_renumber_regs_insn (XEXP (in_rtx, i));
404018334Speter	break;
404118334Speter
404218334Speter      case 'E':
404318334Speter	if (NULL != XVEC (in_rtx, i))
404418334Speter	  {
404518334Speter	    for (j = 0; j < XVECLEN (in_rtx, i); j++)
404618334Speter	      leaf_renumber_regs_insn (XVECEXP (in_rtx, i, j));
404718334Speter	  }
404818334Speter	break;
404918334Speter
405018334Speter      case 'S':
405118334Speter      case 's':
405218334Speter      case '0':
405318334Speter      case 'i':
405418334Speter      case 'w':
405518334Speter      case 'n':
405618334Speter      case 'u':
405718334Speter	break;
405818334Speter
405918334Speter      default:
406018334Speter	abort ();
406118334Speter      }
406218334Speter}
406318334Speter#endif
4064