final.c revision 74478
118334Speter/* Convert RTL to assembler code and output it, for GNU compiler.
252515Sobrien   Copyright (C) 1987, 88, 89, 92-98, 1999 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
2152515Sobrien/* $FreeBSD: head/contrib/gcc/final.c 74478 2001-03-19 19:50:16Z obrien $ */
2218334Speter
2352515Sobrien
2418334Speter/* This is the final pass of the compiler.
2518334Speter   It looks at the rtl code for a function and outputs assembler code.
2618334Speter
2718334Speter   Call `final_start_function' to output the assembler code for function entry,
2818334Speter   `final' to output assembler code for some RTL code,
2918334Speter   `final_end_function' to output assembler code for function exit.
3018334Speter   If a function is compiled in several pieces, each piece is
3118334Speter   output separately with `final'.
3218334Speter
3318334Speter   Some optimizations are also done at this level.
3418334Speter   Move instructions that were made unnecessary by good register allocation
3518334Speter   are detected and omitted from the output.  (Though most of these
3618334Speter   are removed by the last jump pass.)
3718334Speter
3818334Speter   Instructions to set the condition codes are omitted when it can be
3918334Speter   seen that the condition codes already had the desired values.
4018334Speter
4118334Speter   In some cases it is sufficient if the inherited condition codes
4218334Speter   have related values, but this may require the following insn
4318334Speter   (the one that tests the condition codes) to be modified.
4418334Speter
4518334Speter   The code for the function prologue and epilogue are generated
4618334Speter   directly as assembler code by the macros FUNCTION_PROLOGUE and
4718334Speter   FUNCTION_EPILOGUE.  Those instructions never exist as rtl.  */
4818334Speter
4918334Speter#include "config.h"
5050503Sobrien#include "system.h"
5118334Speter
5218334Speter#include "tree.h"
5318334Speter#include "rtl.h"
5418334Speter#include "regs.h"
5518334Speter#include "insn-config.h"
5618334Speter#include "insn-flags.h"
5718334Speter#include "insn-attr.h"
5818334Speter#include "insn-codes.h"
5918334Speter#include "recog.h"
6018334Speter#include "conditions.h"
6118334Speter#include "flags.h"
6218334Speter#include "real.h"
6318334Speter#include "hard-reg-set.h"
6418334Speter#include "defaults.h"
6518334Speter#include "output.h"
6650503Sobrien#include "except.h"
6750503Sobrien#include "toplev.h"
6850503Sobrien#include "reload.h"
6952515Sobrien#include "intl.h"
7018334Speter
7118334Speter/* Get N_SLINE and N_SOL from stab.h if we can expect the file to exist.  */
7218334Speter#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
7350503Sobrien#include "dbxout.h"
7450503Sobrien#if defined (USG) || !defined (HAVE_STAB_H)
7518334Speter#include "gstab.h"  /* If doing DBX on sysV, use our own stab.h.  */
7618334Speter#else
7750503Sobrien#include <stab.h>
7850503Sobrien#endif
7950503Sobrien
8018334Speter#endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */
8118334Speter
8218334Speter#ifdef XCOFF_DEBUGGING_INFO
8318334Speter#include "xcoffout.h"
8418334Speter#endif
8518334Speter
8650503Sobrien#ifdef DWARF_DEBUGGING_INFO
8750503Sobrien#include "dwarfout.h"
8850503Sobrien#endif
8950503Sobrien
9050503Sobrien#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
9150503Sobrien#include "dwarf2out.h"
9250503Sobrien#endif
9350503Sobrien
9450503Sobrien#ifdef SDB_DEBUGGING_INFO
9550503Sobrien#include "sdbout.h"
9650503Sobrien#endif
9750503Sobrien
9818334Speter/* .stabd code for line number.  */
9918334Speter#ifndef N_SLINE
10018334Speter#define	N_SLINE	0x44
10118334Speter#endif
10218334Speter
10318334Speter/* .stabs code for included file name.  */
10418334Speter#ifndef N_SOL
10518334Speter#define	N_SOL 0x84
10618334Speter#endif
10718334Speter
10818334Speter#ifndef INT_TYPE_SIZE
10918334Speter#define INT_TYPE_SIZE BITS_PER_WORD
11018334Speter#endif
11118334Speter
11250503Sobrien#ifndef LONG_TYPE_SIZE
11350503Sobrien#define LONG_TYPE_SIZE BITS_PER_WORD
11450503Sobrien#endif
11550503Sobrien
11618334Speter/* If we aren't using cc0, CC_STATUS_INIT shouldn't exist.  So define a
11718334Speter   null default for it to save conditionalization later.  */
11818334Speter#ifndef CC_STATUS_INIT
11918334Speter#define CC_STATUS_INIT
12018334Speter#endif
12118334Speter
12218334Speter/* How to start an assembler comment.  */
12318334Speter#ifndef ASM_COMMENT_START
12418334Speter#define ASM_COMMENT_START ";#"
12518334Speter#endif
12618334Speter
12718334Speter/* Is the given character a logical line separator for the assembler?  */
12818334Speter#ifndef IS_ASM_LOGICAL_LINE_SEPARATOR
12918334Speter#define IS_ASM_LOGICAL_LINE_SEPARATOR(C) ((C) == ';')
13018334Speter#endif
13118334Speter
13250503Sobrien#ifndef JUMP_TABLES_IN_TEXT_SECTION
13350503Sobrien#define JUMP_TABLES_IN_TEXT_SECTION 0
13450503Sobrien#endif
13550503Sobrien
13618334Speter/* Last insn processed by final_scan_insn.  */
13718334Speterstatic rtx debug_insn = 0;
13818334Speter
13918334Speter/* Line number of last NOTE.  */
14018334Speterstatic int last_linenum;
14118334Speter
14218334Speter/* Highest line number in current block.  */
14318334Speterstatic int high_block_linenum;
14418334Speter
14518334Speter/* Likewise for function.  */
14618334Speterstatic int high_function_linenum;
14718334Speter
14818334Speter/* Filename of last NOTE.  */
14918334Speterstatic char *last_filename;
15018334Speter
15118334Speter/* Number of basic blocks seen so far;
15218334Speter   used if profile_block_flag is set.  */
15318334Speterstatic int count_basic_blocks;
15418334Speter
15550503Sobrien/* Number of instrumented arcs when profile_arc_flag is set.  */
15650503Sobrienextern int count_instrumented_arcs;
15750503Sobrien
15850503Sobrienextern int length_unit_log; /* This is defined in insn-attrtab.c.  */
15950503Sobrien
16018334Speter/* Nonzero while outputting an `asm' with operands.
16118334Speter   This means that inconsistencies are the user's fault, so don't abort.
16218334Speter   The precise value is the insn being output, to pass to error_for_asm.  */
16318334Speterstatic rtx this_is_asm_operands;
16418334Speter
16518334Speter/* Number of operands of this insn, for an `asm' with operands.  */
16650503Sobrienstatic unsigned int insn_noperands;
16718334Speter
16818334Speter/* Compare optimization flag.  */
16918334Speter
17018334Speterstatic rtx last_ignored_compare = 0;
17118334Speter
17218334Speter/* Flag indicating this insn is the start of a new basic block.  */
17318334Speter
17418334Speterstatic int new_block = 1;
17518334Speter
17618334Speter/* All the symbol-blocks (levels of scoping) in the compilation
17718334Speter   are assigned sequence numbers in order of appearance of the
17818334Speter   beginnings of the symbol-blocks.  Both final and dbxout do this,
17918334Speter   and assume that they will both give the same number to each block.
18018334Speter   Final uses these sequence numbers to generate assembler label names
18118334Speter   LBBnnn and LBEnnn for the beginning and end of the symbol-block.
18218334Speter   Dbxout uses the sequence numbers to generate references to the same labels
18318334Speter   from the dbx debugging information.
18418334Speter
18518334Speter   Sdb records this level at the beginning of each function,
18618334Speter   in order to find the current level when recursing down declarations.
18718334Speter   It outputs the block beginning and endings
18818334Speter   at the point in the asm file where the blocks would begin and end.  */
18918334Speter
19018334Speterint next_block_index;
19118334Speter
19218334Speter/* Assign a unique number to each insn that is output.
19318334Speter   This can be used to generate unique local labels.  */
19418334Speter
19518334Speterstatic int insn_counter = 0;
19618334Speter
19718334Speter#ifdef HAVE_cc0
19818334Speter/* This variable contains machine-dependent flags (defined in tm.h)
19918334Speter   set and examined by output routines
20018334Speter   that describe how to interpret the condition codes properly.  */
20118334Speter
20218334SpeterCC_STATUS cc_status;
20318334Speter
20418334Speter/* During output of an insn, this contains a copy of cc_status
20518334Speter   from before the insn.  */
20618334Speter
20718334SpeterCC_STATUS cc_prev_status;
20818334Speter#endif
20918334Speter
21018334Speter/* Indexed by hardware reg number, is 1 if that register is ever
21118334Speter   used in the current function.
21218334Speter
21318334Speter   In life_analysis, or in stupid_life_analysis, this is set
21418334Speter   up to record the hard regs used explicitly.  Reload adds
21518334Speter   in the hard regs used for holding pseudo regs.  Final uses
21618334Speter   it to generate the code in the function prologue and epilogue
21718334Speter   to save and restore registers as needed.  */
21818334Speter
21918334Speterchar regs_ever_live[FIRST_PSEUDO_REGISTER];
22018334Speter
22118334Speter/* Nonzero means current function must be given a frame pointer.
22218334Speter   Set in stmt.c if anything is allocated on the stack there.
22318334Speter   Set in reload1.c if anything is allocated on the stack there.  */
22418334Speter
22518334Speterint frame_pointer_needed;
22618334Speter
22718334Speter/* Assign unique numbers to labels generated for profiling.  */
22818334Speter
22918334Speterint profile_label_no;
23018334Speter
23118334Speter/* Length so far allocated in PENDING_BLOCKS.  */
23218334Speter
23318334Speterstatic int max_block_depth;
23418334Speter
23518334Speter/* Stack of sequence numbers of symbol-blocks of which we have seen the
23618334Speter   beginning but not yet the end.  Sequence numbers are assigned at
23718334Speter   the beginning; this stack allows us to find the sequence number
23818334Speter   of a block that is ending.  */
23918334Speter
24018334Speterstatic int *pending_blocks;
24118334Speter
24218334Speter/* Number of elements currently in use in PENDING_BLOCKS.  */
24318334Speter
24418334Speterstatic int block_depth;
24518334Speter
24618334Speter/* Nonzero if have enabled APP processing of our assembler output.  */
24718334Speter
24818334Speterstatic int app_on;
24918334Speter
25018334Speter/* If we are outputting an insn sequence, this contains the sequence rtx.
25118334Speter   Zero otherwise.  */
25218334Speter
25318334Speterrtx final_sequence;
25418334Speter
25518334Speter#ifdef ASSEMBLER_DIALECT
25618334Speter
25718334Speter/* Number of the assembler dialect to use, starting at 0.  */
25818334Speterstatic int dialect_number;
25918334Speter#endif
26018334Speter
26118334Speter/* Indexed by line number, nonzero if there is a note for that line.  */
26218334Speter
26318334Speterstatic char *line_note_exists;
26418334Speter
26518334Speter/* Linked list to hold line numbers for each basic block.  */
26618334Speter
26718334Speterstruct bb_list {
26818334Speter  struct bb_list *next;		/* pointer to next basic block */
26918334Speter  int line_num;			/* line number */
27018334Speter  int file_label_num;		/* LPBC<n> label # for stored filename */
27118334Speter  int func_label_num;		/* LPBC<n> label # for stored function name */
27218334Speter};
27318334Speter
27418334Speterstatic struct bb_list *bb_head	= 0;		/* Head of basic block list */
27518334Speterstatic struct bb_list **bb_tail = &bb_head;	/* Ptr to store next bb ptr */
27618334Speterstatic int bb_file_label_num	= -1;		/* Current label # for file */
27718334Speterstatic int bb_func_label_num	= -1;		/* Current label # for func */
27818334Speter
27918334Speter/* Linked list to hold the strings for each file and function name output.  */
28018334Speter
28118334Speterstruct bb_str {
28218334Speter  struct bb_str *next;		/* pointer to next string */
28352515Sobrien  const char *string;		/* string */
28418334Speter  int label_num;		/* label number */
28518334Speter  int length;			/* string length */
28618334Speter};
28718334Speter
28818334Speterextern rtx peephole		PROTO((rtx));
28918334Speter
29018334Speterstatic struct bb_str *sbb_head	= 0;		/* Head of string list.  */
29118334Speterstatic struct bb_str **sbb_tail	= &sbb_head;	/* Ptr to store next bb str */
29218334Speterstatic int sbb_label_num	= 0;		/* Last label used */
29318334Speter
29450503Sobrien#ifdef HAVE_ATTR_length
29518334Speterstatic int asm_insn_count	PROTO((rtx));
29650503Sobrien#endif
29718334Speterstatic void profile_function	PROTO((FILE *));
29818334Speterstatic void profile_after_prologue PROTO((FILE *));
29918334Speterstatic void add_bb		PROTO((FILE *));
30052515Sobrienstatic int add_bb_string	PROTO((const char *, int));
30118334Speterstatic void output_source_line	PROTO((FILE *, rtx));
30218334Speterstatic rtx walk_alter_subreg	PROTO((rtx));
30318334Speterstatic void output_asm_name	PROTO((void));
30418334Speterstatic void output_operand	PROTO((rtx, int));
30550503Sobrien#ifdef LEAF_REGISTERS
30618334Speterstatic void leaf_renumber_regs	PROTO((rtx));
30750503Sobrien#endif
30850503Sobrien#ifdef HAVE_cc0
30950503Sobrienstatic int alter_cond		PROTO((rtx));
31050503Sobrien#endif
31118334Speter
31218334Speterextern char *getpwd ();
31318334Speter
31418334Speter/* Initialize data in final at the beginning of a compilation.  */
31518334Speter
31618334Spetervoid
31718334Speterinit_final (filename)
31818334Speter     char *filename;
31918334Speter{
32018334Speter  next_block_index = 2;
32118334Speter  app_on = 0;
32218334Speter  max_block_depth = 20;
32318334Speter  pending_blocks = (int *) xmalloc (20 * sizeof *pending_blocks);
32418334Speter  final_sequence = 0;
32518334Speter
32618334Speter#ifdef ASSEMBLER_DIALECT
32718334Speter  dialect_number = ASSEMBLER_DIALECT;
32818334Speter#endif
32918334Speter}
33018334Speter
33118334Speter/* Called at end of source file,
33218334Speter   to output the block-profiling table for this entire compilation.  */
33318334Speter
33418334Spetervoid
33518334Speterend_final (filename)
33652515Sobrien  const char *filename;
33718334Speter{
33818334Speter  int i;
33918334Speter
34050503Sobrien  if (profile_block_flag || profile_arc_flag)
34118334Speter    {
34218334Speter      char name[20];
34318334Speter      int align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
34450503Sobrien      int size, rounded;
34518334Speter      struct bb_list *ptr;
34618334Speter      struct bb_str *sptr;
34750503Sobrien      int long_bytes = LONG_TYPE_SIZE / BITS_PER_UNIT;
34850503Sobrien      int pointer_bytes = POINTER_SIZE / BITS_PER_UNIT;
34918334Speter
35050503Sobrien      if (profile_block_flag)
35150503Sobrien	size = long_bytes * count_basic_blocks;
35250503Sobrien      else
35350503Sobrien	size = long_bytes * count_instrumented_arcs;
35450503Sobrien      rounded = size;
35550503Sobrien
35618334Speter      rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;
35718334Speter      rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
35818334Speter		 * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
35918334Speter
36018334Speter      data_section ();
36118334Speter
36250503Sobrien      /* Output the main header, of 11 words:
36350503Sobrien	 0:  1 if this file is initialized, else 0.
36418334Speter	 1:  address of file name (LPBX1).
36518334Speter	 2:  address of table of counts (LPBX2).
36618334Speter	 3:  number of counts in the table.
36718334Speter	 4:  always 0, for compatibility with Sun.
36818334Speter
36918334Speter         The following are GNU extensions:
37018334Speter
37118334Speter	 5:  address of table of start addrs of basic blocks (LPBX3).
37218334Speter	 6:  Number of bytes in this header.
37318334Speter	 7:  address of table of function names (LPBX4).
37418334Speter	 8:  address of table of line numbers (LPBX5) or 0.
37550503Sobrien	 9:  address of table of file names (LPBX6) or 0.
37650503Sobrien	10:  space reserved for basic block profiling.  */
37718334Speter
37818334Speter      ASM_OUTPUT_ALIGN (asm_out_file, align);
37918334Speter
38018334Speter      ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 0);
38118334Speter      /* zero word */
38250503Sobrien      assemble_integer (const0_rtx, long_bytes, 1);
38318334Speter
38418334Speter      /* address of filename */
38518334Speter      ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 1);
38650503Sobrien      assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes, 1);
38718334Speter
38818334Speter      /* address of count table */
38918334Speter      ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2);
39050503Sobrien      assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes, 1);
39118334Speter
39250503Sobrien      /* count of the # of basic blocks or # of instrumented arcs */
39350503Sobrien      if (profile_block_flag)
39450503Sobrien	assemble_integer (GEN_INT (count_basic_blocks), long_bytes, 1);
39550503Sobrien      else
39650503Sobrien	assemble_integer (GEN_INT (count_instrumented_arcs), long_bytes,
39750503Sobrien			  1);
39818334Speter
39918334Speter      /* zero word (link field) */
40050503Sobrien      assemble_integer (const0_rtx, pointer_bytes, 1);
40118334Speter
40218334Speter      /* address of basic block start address table */
40350503Sobrien      if (profile_block_flag)
40450503Sobrien	{
40550503Sobrien	  ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 3);
40650503Sobrien	  assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes,
40750503Sobrien			    1);
40850503Sobrien	}
40950503Sobrien      else
41050503Sobrien	assemble_integer (const0_rtx, pointer_bytes, 1);
41118334Speter
41218334Speter      /* byte count for extended structure.  */
41352515Sobrien      assemble_integer (GEN_INT (11 * UNITS_PER_WORD), long_bytes, 1);
41418334Speter
41518334Speter      /* address of function name table */
41650503Sobrien      if (profile_block_flag)
41750503Sobrien	{
41850503Sobrien	  ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 4);
41950503Sobrien	  assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes,
42050503Sobrien			    1);
42150503Sobrien	}
42250503Sobrien      else
42350503Sobrien	assemble_integer (const0_rtx, pointer_bytes, 1);
42418334Speter
42518334Speter      /* address of line number and filename tables if debugging.  */
42650503Sobrien      if (write_symbols != NO_DEBUG && profile_block_flag)
42718334Speter	{
42818334Speter	  ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 5);
42950503Sobrien	  assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes, 1);
43018334Speter	  ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 6);
43150503Sobrien	  assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes, 1);
43218334Speter	}
43318334Speter      else
43418334Speter	{
43550503Sobrien	  assemble_integer (const0_rtx, pointer_bytes, 1);
43650503Sobrien	  assemble_integer (const0_rtx, pointer_bytes, 1);
43718334Speter	}
43818334Speter
43950503Sobrien      /* space for extension ptr (link field) */
44050503Sobrien      assemble_integer (const0_rtx, UNITS_PER_WORD, 1);
44150503Sobrien
44218334Speter      /* Output the file name changing the suffix to .d for Sun tcov
44318334Speter	 compatibility.  */
44418334Speter      ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 1);
44518334Speter      {
44618334Speter	char *cwd = getpwd ();
44718334Speter	int len = strlen (filename) + strlen (cwd) + 1;
44818334Speter	char *data_file = (char *) alloca (len + 4);
44918334Speter
45018334Speter	strcpy (data_file, cwd);
45118334Speter	strcat (data_file, "/");
45218334Speter	strcat (data_file, filename);
45318334Speter	strip_off_ending (data_file, len);
45450503Sobrien	if (profile_block_flag)
45550503Sobrien	  strcat (data_file, ".d");
45650503Sobrien	else
45750503Sobrien	  strcat (data_file, ".da");
45818334Speter	assemble_string (data_file, strlen (data_file) + 1);
45918334Speter      }
46018334Speter
46118334Speter      /* Make space for the table of counts.  */
46250503Sobrien      if (size == 0)
46318334Speter	{
46418334Speter	  /* Realign data section.  */
46518334Speter	  ASM_OUTPUT_ALIGN (asm_out_file, align);
46618334Speter	  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 2);
46718334Speter	  if (size != 0)
46818334Speter	    assemble_zeros (size);
46918334Speter	}
47018334Speter      else
47118334Speter	{
47218334Speter	  ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2);
47318334Speter#ifdef ASM_OUTPUT_SHARED_LOCAL
47418334Speter	  if (flag_shared_data)
47518334Speter	    ASM_OUTPUT_SHARED_LOCAL (asm_out_file, name, size, rounded);
47618334Speter	  else
47718334Speter#endif
47850503Sobrien#ifdef ASM_OUTPUT_ALIGNED_DECL_LOCAL
47950503Sobrien	    ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, NULL_TREE, name, size,
48050503Sobrien					      BIGGEST_ALIGNMENT);
48150503Sobrien#else
48218334Speter#ifdef ASM_OUTPUT_ALIGNED_LOCAL
48318334Speter	    ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size,
48418334Speter				      BIGGEST_ALIGNMENT);
48518334Speter#else
48618334Speter	    ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
48718334Speter#endif
48850503Sobrien#endif
48918334Speter	}
49018334Speter
49118334Speter      /* Output any basic block strings */
49250503Sobrien      if (profile_block_flag)
49318334Speter	{
49450503Sobrien	  readonly_data_section ();
49550503Sobrien	  if (sbb_head)
49618334Speter	    {
49750503Sobrien	      ASM_OUTPUT_ALIGN (asm_out_file, align);
49850503Sobrien	      for (sptr = sbb_head; sptr != 0; sptr = sptr->next)
49950503Sobrien		{
50050503Sobrien		  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBC",
50150503Sobrien					     sptr->label_num);
50250503Sobrien		  assemble_string (sptr->string, sptr->length);
50350503Sobrien		}
50418334Speter	    }
50518334Speter	}
50618334Speter
50718334Speter      /* Output the table of addresses.  */
50850503Sobrien      if (profile_block_flag)
50918334Speter	{
51050503Sobrien	  /* Realign in new section */
51150503Sobrien	  ASM_OUTPUT_ALIGN (asm_out_file, align);
51250503Sobrien	  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 3);
51350503Sobrien	  for (i = 0; i < count_basic_blocks; i++)
51450503Sobrien	    {
51550503Sobrien	      ASM_GENERATE_INTERNAL_LABEL (name, "LPB", i);
51650503Sobrien	      assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name),
51750503Sobrien				pointer_bytes, 1);
51850503Sobrien	    }
51918334Speter	}
52018334Speter
52118334Speter      /* Output the table of function names.  */
52250503Sobrien      if (profile_block_flag)
52318334Speter	{
52450503Sobrien	  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 4);
52550503Sobrien	  for ((ptr = bb_head), (i = 0); ptr != 0; (ptr = ptr->next), i++)
52618334Speter	    {
52750503Sobrien	      if (ptr->func_label_num >= 0)
52850503Sobrien		{
52950503Sobrien		  ASM_GENERATE_INTERNAL_LABEL (name, "LPBC",
53050503Sobrien					       ptr->func_label_num);
53150503Sobrien		  assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name),
53250503Sobrien				    pointer_bytes, 1);
53350503Sobrien		}
53450503Sobrien	      else
53550503Sobrien		assemble_integer (const0_rtx, pointer_bytes, 1);
53618334Speter	    }
53750503Sobrien
53850503Sobrien	  for ( ; i < count_basic_blocks; i++)
53950503Sobrien	    assemble_integer (const0_rtx, pointer_bytes, 1);
54018334Speter	}
54118334Speter
54250503Sobrien      if (write_symbols != NO_DEBUG && profile_block_flag)
54318334Speter	{
54418334Speter	  /* Output the table of line numbers.  */
54518334Speter	  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 5);
54618334Speter	  for ((ptr = bb_head), (i = 0); ptr != 0; (ptr = ptr->next), i++)
54750503Sobrien	    assemble_integer (GEN_INT (ptr->line_num), long_bytes, 1);
54818334Speter
54918334Speter	  for ( ; i < count_basic_blocks; i++)
55050503Sobrien	    assemble_integer (const0_rtx, long_bytes, 1);
55118334Speter
55218334Speter	  /* Output the table of file names.  */
55318334Speter	  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 6);
55418334Speter	  for ((ptr = bb_head), (i = 0); ptr != 0; (ptr = ptr->next), i++)
55518334Speter	    {
55618334Speter	      if (ptr->file_label_num >= 0)
55718334Speter		{
55850503Sobrien		  ASM_GENERATE_INTERNAL_LABEL (name, "LPBC",
55950503Sobrien					       ptr->file_label_num);
56050503Sobrien		  assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name),
56150503Sobrien				    pointer_bytes, 1);
56218334Speter		}
56318334Speter	      else
56450503Sobrien		assemble_integer (const0_rtx, pointer_bytes, 1);
56518334Speter	    }
56618334Speter
56718334Speter	  for ( ; i < count_basic_blocks; i++)
56850503Sobrien	    assemble_integer (const0_rtx, pointer_bytes, 1);
56918334Speter	}
57018334Speter
57118334Speter      /* End with the address of the table of addresses,
57218334Speter	 so we can find it easily, as the last word in the file's text.  */
57350503Sobrien      if (profile_block_flag)
57450503Sobrien	{
57550503Sobrien	  ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 3);
57650503Sobrien	  assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes,
57750503Sobrien			    1);
57850503Sobrien	}
57918334Speter    }
58018334Speter}
58118334Speter
58218334Speter/* Enable APP processing of subsequent output.
58318334Speter   Used before the output from an `asm' statement.  */
58418334Speter
58518334Spetervoid
58618334Speterapp_enable ()
58718334Speter{
58818334Speter  if (! app_on)
58918334Speter    {
59050503Sobrien      fputs (ASM_APP_ON, asm_out_file);
59118334Speter      app_on = 1;
59218334Speter    }
59318334Speter}
59418334Speter
59518334Speter/* Disable APP processing of subsequent output.
59618334Speter   Called from varasm.c before most kinds of output.  */
59718334Speter
59818334Spetervoid
59918334Speterapp_disable ()
60018334Speter{
60118334Speter  if (app_on)
60218334Speter    {
60350503Sobrien      fputs (ASM_APP_OFF, asm_out_file);
60418334Speter      app_on = 0;
60518334Speter    }
60618334Speter}
60718334Speter
60818334Speter/* Return the number of slots filled in the current
60918334Speter   delayed branch sequence (we don't count the insn needing the
61018334Speter   delay slot).   Zero if not in a delayed branch sequence.  */
61118334Speter
61218334Speter#ifdef DELAY_SLOTS
61318334Speterint
61418334Speterdbr_sequence_length ()
61518334Speter{
61618334Speter  if (final_sequence != 0)
61718334Speter    return XVECLEN (final_sequence, 0) - 1;
61818334Speter  else
61918334Speter    return 0;
62018334Speter}
62118334Speter#endif
62218334Speter
62318334Speter/* The next two pages contain routines used to compute the length of an insn
62418334Speter   and to shorten branches.  */
62518334Speter
62618334Speter/* Arrays for insn lengths, and addresses.  The latter is referenced by
62718334Speter   `insn_current_length'.  */
62818334Speter
62918334Speterstatic short *insn_lengths;
63018334Speterint *insn_addresses;
63118334Speter
63252515Sobrien/* Max uid for which the above arrays are valid.  */
63352515Sobrienstatic int insn_lengths_max_uid;
63452515Sobrien
63518334Speter/* Address of insn being processed.  Used by `insn_current_length'.  */
63618334Speterint insn_current_address;
63718334Speter
63850503Sobrien/* Address of insn being processed in previous iteration.  */
63950503Sobrienint insn_last_address;
64050503Sobrien
64150503Sobrien/* konwn invariant alignment of insn being processed.  */
64250503Sobrienint insn_current_align;
64350503Sobrien
64450503Sobrien/* After shorten_branches, for any insn, uid_align[INSN_UID (insn)]
64550503Sobrien   gives the next following alignment insn that increases the known
64650503Sobrien   alignment, or NULL_RTX if there is no such insn.
64750503Sobrien   For any alignment obtained this way, we can again index uid_align with
64850503Sobrien   its uid to obtain the next following align that in turn increases the
64950503Sobrien   alignment, till we reach NULL_RTX; the sequence obtained this way
65050503Sobrien   for each insn we'll call the alignment chain of this insn in the following
65150503Sobrien   comments.  */
65250503Sobrien
65350503Sobrienstruct label_alignment {
65450503Sobrien  short alignment;
65550503Sobrien  short max_skip;
65650503Sobrien};
65750503Sobrien
65850503Sobrienstatic rtx *uid_align;
65950503Sobrienstatic int *uid_shuid;
66050503Sobrienstatic struct label_alignment *label_align;
66150503Sobrien
66218334Speter/* Indicate that branch shortening hasn't yet been done.  */
66318334Speter
66418334Spetervoid
66518334Speterinit_insn_lengths ()
66618334Speter{
66750503Sobrien  if (label_align)
66850503Sobrien    {
66950503Sobrien      free (label_align);
67050503Sobrien      label_align = 0;
67150503Sobrien    }
67250503Sobrien  if (uid_shuid)
67350503Sobrien    {
67450503Sobrien      free (uid_shuid);
67550503Sobrien      uid_shuid = 0;
67650503Sobrien    }
67750503Sobrien  if (insn_lengths)
67850503Sobrien    {
67950503Sobrien      free (insn_lengths);
68050503Sobrien      insn_lengths = 0;
68152515Sobrien      insn_lengths_max_uid = 0;
68250503Sobrien    }
68350503Sobrien  if (insn_addresses)
68450503Sobrien    {
68550503Sobrien      free (insn_addresses);
68650503Sobrien      insn_addresses = 0;
68750503Sobrien    }
68850503Sobrien  if (uid_align)
68950503Sobrien    {
69050503Sobrien      free (uid_align);
69150503Sobrien      uid_align = 0;
69250503Sobrien    }
69318334Speter}
69418334Speter
69518334Speter/* Obtain the current length of an insn.  If branch shortening has been done,
69618334Speter   get its actual length.  Otherwise, get its maximum length.  */
69718334Speter
69818334Speterint
69918334Speterget_attr_length (insn)
70018334Speter     rtx insn;
70118334Speter{
70218334Speter#ifdef HAVE_ATTR_length
70318334Speter  rtx body;
70418334Speter  int i;
70518334Speter  int length = 0;
70618334Speter
70752515Sobrien  if (insn_lengths_max_uid > INSN_UID (insn))
70818334Speter    return insn_lengths[INSN_UID (insn)];
70918334Speter  else
71018334Speter    switch (GET_CODE (insn))
71118334Speter      {
71218334Speter      case NOTE:
71318334Speter      case BARRIER:
71418334Speter      case CODE_LABEL:
71518334Speter	return 0;
71618334Speter
71718334Speter      case CALL_INSN:
71818334Speter	length = insn_default_length (insn);
71918334Speter	break;
72018334Speter
72118334Speter      case JUMP_INSN:
72218334Speter	body = PATTERN (insn);
72318334Speter        if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
72418334Speter	  {
72550503Sobrien	    /* Alignment is machine-dependent and should be handled by
72650503Sobrien	       ADDR_VEC_ALIGN.  */
72718334Speter	  }
72818334Speter	else
72918334Speter	  length = insn_default_length (insn);
73018334Speter	break;
73118334Speter
73218334Speter      case INSN:
73318334Speter	body = PATTERN (insn);
73418334Speter	if (GET_CODE (body) == USE || GET_CODE (body) == CLOBBER)
73518334Speter	  return 0;
73618334Speter
73718334Speter	else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0)
73818334Speter	  length = asm_insn_count (body) * insn_default_length (insn);
73918334Speter	else if (GET_CODE (body) == SEQUENCE)
74018334Speter	  for (i = 0; i < XVECLEN (body, 0); i++)
74118334Speter	    length += get_attr_length (XVECEXP (body, 0, i));
74218334Speter	else
74318334Speter	  length = insn_default_length (insn);
74450503Sobrien	break;
74550503Sobrien
74650503Sobrien      default:
74750503Sobrien	break;
74818334Speter      }
74918334Speter
75018334Speter#ifdef ADJUST_INSN_LENGTH
75118334Speter  ADJUST_INSN_LENGTH (insn, length);
75218334Speter#endif
75318334Speter  return length;
75418334Speter#else /* not HAVE_ATTR_length */
75518334Speter  return 0;
75618334Speter#endif /* not HAVE_ATTR_length */
75718334Speter}
75818334Speter
75950503Sobrien/* Code to handle alignment inside shorten_branches.  */
76050503Sobrien
76150503Sobrien/* Here is an explanation how the algorithm in align_fuzz can give
76250503Sobrien   proper results:
76350503Sobrien
76450503Sobrien   Call a sequence of instructions beginning with alignment point X
76550503Sobrien   and continuing until the next alignment point `block X'.  When `X'
76650503Sobrien   is used in an expression, it means the alignment value of the
76750503Sobrien   alignment point.
76850503Sobrien
76950503Sobrien   Call the distance between the start of the first insn of block X, and
77050503Sobrien   the end of the last insn of block X `IX', for the `inner size of X'.
77150503Sobrien   This is clearly the sum of the instruction lengths.
77250503Sobrien
77350503Sobrien   Likewise with the next alignment-delimited block following X, which we
77450503Sobrien   shall call block Y.
77550503Sobrien
77650503Sobrien   Call the distance between the start of the first insn of block X, and
77750503Sobrien   the start of the first insn of block Y `OX', for the `outer size of X'.
77850503Sobrien
77950503Sobrien   The estimated padding is then OX - IX.
78050503Sobrien
78150503Sobrien   OX can be safely estimated as
78250503Sobrien
78350503Sobrien           if (X >= Y)
78450503Sobrien                   OX = round_up(IX, Y)
78550503Sobrien           else
78650503Sobrien                   OX = round_up(IX, X) + Y - X
78750503Sobrien
78850503Sobrien   Clearly est(IX) >= real(IX), because that only depends on the
78950503Sobrien   instruction lengths, and those being overestimated is a given.
79050503Sobrien
79150503Sobrien   Clearly round_up(foo, Z) >= round_up(bar, Z) if foo >= bar, so
79250503Sobrien   we needn't worry about that when thinking about OX.
79350503Sobrien
79450503Sobrien   When X >= Y, the alignment provided by Y adds no uncertainty factor
79550503Sobrien   for branch ranges starting before X, so we can just round what we have.
79650503Sobrien   But when X < Y, we don't know anything about the, so to speak,
79750503Sobrien   `middle bits', so we have to assume the worst when aligning up from an
79850503Sobrien   address mod X to one mod Y, which is Y - X.  */
79950503Sobrien
80050503Sobrien#ifndef LABEL_ALIGN
80150503Sobrien#define LABEL_ALIGN(LABEL) 0
80250503Sobrien#endif
80350503Sobrien
80450503Sobrien#ifndef LABEL_ALIGN_MAX_SKIP
80550503Sobrien#define LABEL_ALIGN_MAX_SKIP 0
80650503Sobrien#endif
80750503Sobrien
80850503Sobrien#ifndef LOOP_ALIGN
80950503Sobrien#define LOOP_ALIGN(LABEL) 0
81050503Sobrien#endif
81150503Sobrien
81250503Sobrien#ifndef LOOP_ALIGN_MAX_SKIP
81350503Sobrien#define LOOP_ALIGN_MAX_SKIP 0
81450503Sobrien#endif
81550503Sobrien
81650503Sobrien#ifndef LABEL_ALIGN_AFTER_BARRIER
81750503Sobrien#define LABEL_ALIGN_AFTER_BARRIER(LABEL) 0
81850503Sobrien#endif
81950503Sobrien
82050503Sobrien#ifndef LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP
82150503Sobrien#define LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP 0
82250503Sobrien#endif
82350503Sobrien
82450503Sobrien#ifndef ADDR_VEC_ALIGN
82550503Sobrienint
82650503Sobrienfinal_addr_vec_align (addr_vec)
82750503Sobrien     rtx addr_vec;
82850503Sobrien{
82950503Sobrien  int align = exact_log2 (GET_MODE_SIZE (GET_MODE (PATTERN (addr_vec))));
83050503Sobrien
83150503Sobrien  if (align > BIGGEST_ALIGNMENT / BITS_PER_UNIT)
83250503Sobrien    align = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
83350503Sobrien  return align;
83450503Sobrien
83550503Sobrien}
83650503Sobrien#define ADDR_VEC_ALIGN(ADDR_VEC) final_addr_vec_align (ADDR_VEC)
83750503Sobrien#endif
83850503Sobrien
83950503Sobrien#ifndef INSN_LENGTH_ALIGNMENT
84050503Sobrien#define INSN_LENGTH_ALIGNMENT(INSN) length_unit_log
84150503Sobrien#endif
84250503Sobrien
84350503Sobrien#define INSN_SHUID(INSN) (uid_shuid[INSN_UID (INSN)])
84450503Sobrien
84550503Sobrienstatic int min_labelno, max_labelno;
84650503Sobrien
84750503Sobrien#define LABEL_TO_ALIGNMENT(LABEL) \
84850503Sobrien  (label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno].alignment)
84950503Sobrien
85050503Sobrien#define LABEL_TO_MAX_SKIP(LABEL) \
85150503Sobrien  (label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno].max_skip)
85250503Sobrien
85350503Sobrien/* For the benefit of port specific code do this also as a function.  */
85450503Sobrienint
85550503Sobrienlabel_to_alignment (label)
85650503Sobrien     rtx label;
85750503Sobrien{
85850503Sobrien  return LABEL_TO_ALIGNMENT (label);
85950503Sobrien}
86050503Sobrien
86150503Sobrien#ifdef HAVE_ATTR_length
86250503Sobrien/* The differences in addresses
86350503Sobrien   between a branch and its target might grow or shrink depending on
86450503Sobrien   the alignment the start insn of the range (the branch for a forward
86550503Sobrien   branch or the label for a backward branch) starts out on; if these
86650503Sobrien   differences are used naively, they can even oscillate infinitely.
86750503Sobrien   We therefore want to compute a 'worst case' address difference that
86850503Sobrien   is independent of the alignment the start insn of the range end
86950503Sobrien   up on, and that is at least as large as the actual difference.
87050503Sobrien   The function align_fuzz calculates the amount we have to add to the
87150503Sobrien   naively computed difference, by traversing the part of the alignment
87250503Sobrien   chain of the start insn of the range that is in front of the end insn
87350503Sobrien   of the range, and considering for each alignment the maximum amount
87450503Sobrien   that it might contribute to a size increase.
87550503Sobrien
87650503Sobrien   For casesi tables, we also want to know worst case minimum amounts of
87750503Sobrien   address difference, in case a machine description wants to introduce
87850503Sobrien   some common offset that is added to all offsets in a table.
87950503Sobrien   For this purpose, align_fuzz with a growth argument of 0 comuptes the
88050503Sobrien   appropriate adjustment.  */
88150503Sobrien
88250503Sobrien
88350503Sobrien/* Compute the maximum delta by which the difference of the addresses of
88450503Sobrien   START and END might grow / shrink due to a different address for start
88550503Sobrien   which changes the size of alignment insns between START and END.
88650503Sobrien   KNOWN_ALIGN_LOG is the alignment known for START.
88750503Sobrien   GROWTH should be ~0 if the objective is to compute potential code size
88850503Sobrien   increase, and 0 if the objective is to compute potential shrink.
88950503Sobrien   The return value is undefined for any other value of GROWTH.  */
89050503Sobrienint
89150503Sobrienalign_fuzz (start, end, known_align_log, growth)
89250503Sobrien     rtx start, end;
89350503Sobrien     int known_align_log;
89450503Sobrien     unsigned growth;
89550503Sobrien{
89650503Sobrien  int uid = INSN_UID (start);
89750503Sobrien  rtx align_label;
89850503Sobrien  int known_align = 1 << known_align_log;
89950503Sobrien  int end_shuid = INSN_SHUID (end);
90050503Sobrien  int fuzz = 0;
90150503Sobrien
90250503Sobrien  for (align_label = uid_align[uid]; align_label; align_label = uid_align[uid])
90350503Sobrien    {
90450503Sobrien      int align_addr, new_align;
90550503Sobrien
90650503Sobrien      uid = INSN_UID (align_label);
90750503Sobrien      align_addr = insn_addresses[uid] - insn_lengths[uid];
90850503Sobrien      if (uid_shuid[uid] > end_shuid)
90950503Sobrien	break;
91050503Sobrien      known_align_log = LABEL_TO_ALIGNMENT (align_label);
91150503Sobrien      new_align = 1 << known_align_log;
91250503Sobrien      if (new_align < known_align)
91350503Sobrien	continue;
91450503Sobrien      fuzz += (-align_addr ^ growth) & (new_align - known_align);
91550503Sobrien      known_align = new_align;
91650503Sobrien    }
91750503Sobrien  return fuzz;
91850503Sobrien}
91950503Sobrien
92050503Sobrien/* Compute a worst-case reference address of a branch so that it
92150503Sobrien   can be safely used in the presence of aligned labels.  Since the
92250503Sobrien   size of the branch itself is unknown, the size of the branch is
92350503Sobrien   not included in the range.  I.e. for a forward branch, the reference
92450503Sobrien   address is the end address of the branch as known from the previous
92550503Sobrien   branch shortening pass, minus a value to account for possible size
92650503Sobrien   increase due to alignment.  For a backward branch, it is the start
92750503Sobrien   address of the branch as known from the current pass, plus a value
92850503Sobrien   to account for possible size increase due to alignment.
92950503Sobrien   NB.: Therefore, the maximum offset allowed for backward branches needs
93050503Sobrien   to exclude the branch size.  */
93150503Sobrienint
93250503Sobrieninsn_current_reference_address (branch)
93350503Sobrien     rtx branch;
93450503Sobrien{
93550503Sobrien  rtx dest;
93650503Sobrien  rtx seq = NEXT_INSN (PREV_INSN (branch));
93750503Sobrien  int seq_uid = INSN_UID (seq);
93850503Sobrien  if (GET_CODE (branch) != JUMP_INSN)
93950503Sobrien    /* This can happen for example on the PA; the objective is to know the
94050503Sobrien       offset to address something in front of the start of the function.
94150503Sobrien       Thus, we can treat it like a backward branch.
94250503Sobrien       We assume here that FUNCTION_BOUNDARY / BITS_PER_UNIT is larger than
94350503Sobrien       any alignment we'd encounter, so we skip the call to align_fuzz.  */
94450503Sobrien    return insn_current_address;
94550503Sobrien  dest = JUMP_LABEL (branch);
94650503Sobrien  /* BRANCH has no proper alignment chain set, so use SEQ.  */
94750503Sobrien  if (INSN_SHUID (branch) < INSN_SHUID (dest))
94850503Sobrien    {
94950503Sobrien      /* Forward branch. */
95050503Sobrien      return (insn_last_address + insn_lengths[seq_uid]
95150503Sobrien	      - align_fuzz (seq, dest, length_unit_log, ~0));
95250503Sobrien    }
95350503Sobrien  else
95450503Sobrien    {
95550503Sobrien      /* Backward branch. */
95650503Sobrien      return (insn_current_address
95750503Sobrien	      + align_fuzz (dest, seq, length_unit_log, ~0));
95850503Sobrien    }
95950503Sobrien}
96050503Sobrien#endif /* HAVE_ATTR_length */
96150503Sobrien
96218334Speter/* Make a pass over all insns and compute their actual lengths by shortening
96318334Speter   any branches of variable length if possible.  */
96418334Speter
96518334Speter/* Give a default value for the lowest address in a function.  */
96618334Speter
96718334Speter#ifndef FIRST_INSN_ADDRESS
96818334Speter#define FIRST_INSN_ADDRESS 0
96918334Speter#endif
97018334Speter
97150503Sobrien/* shorten_branches might be called multiple times:  for example, the SH
97250503Sobrien   port splits out-of-range conditional branches in MACHINE_DEPENDENT_REORG.
97350503Sobrien   In order to do this, it needs proper length information, which it obtains
97450503Sobrien   by calling shorten_branches.  This cannot be collapsed with
97550503Sobrien   shorten_branches itself into a single pass unless we also want to intergate
97650503Sobrien   reorg.c, since the branch splitting exposes new instructions with delay
97750503Sobrien   slots.  */
97850503Sobrien
97918334Spetervoid
98018334Spetershorten_branches (first)
98118334Speter     rtx first;
98218334Speter{
98350503Sobrien  rtx insn;
98450503Sobrien  int max_uid;
98550503Sobrien  int i;
98650503Sobrien  int max_log;
98750503Sobrien  int max_skip;
98818334Speter#ifdef HAVE_ATTR_length
98950503Sobrien#define MAX_CODE_ALIGN 16
99050503Sobrien  rtx seq;
99118334Speter  int something_changed = 1;
99218334Speter  char *varying_length;
99318334Speter  rtx body;
99418334Speter  int uid;
99550503Sobrien  rtx align_tab[MAX_CODE_ALIGN];
99618334Speter
99750503Sobrien  /* In order to make sure that all instructions have valid length info,
99850503Sobrien     we must split them before we compute the address/length info.  */
99918334Speter
100050503Sobrien  for (insn = NEXT_INSN (first); insn; insn = NEXT_INSN (insn))
100150503Sobrien    if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
100250503Sobrien      {
100350503Sobrien	rtx old = insn;
100452515Sobrien	/* Don't split the insn if it has been deleted.  */
100552515Sobrien	if (! INSN_DELETED_P (old))
100652515Sobrien	  insn = try_split (PATTERN (old), old, 1);
100750503Sobrien	/* When not optimizing, the old insn will be still left around
100850503Sobrien	   with only the 'deleted' bit set.  Transform it into a note
100950503Sobrien	   to avoid confusion of subsequent processing.  */
101050503Sobrien	if (INSN_DELETED_P (old))
101150503Sobrien          {
101250503Sobrien            PUT_CODE (old , NOTE);
101350503Sobrien            NOTE_LINE_NUMBER (old) = NOTE_INSN_DELETED;
101450503Sobrien            NOTE_SOURCE_FILE (old) = 0;
101550503Sobrien          }
101650503Sobrien      }
101750503Sobrien#endif
101818334Speter
101950503Sobrien  /* We must do some computations even when not actually shortening, in
102050503Sobrien     order to get the alignment information for the labels.  */
102150503Sobrien
102250503Sobrien  init_insn_lengths ();
102350503Sobrien
102450503Sobrien  /* Compute maximum UID and allocate label_align / uid_shuid.  */
102550503Sobrien  max_uid = get_max_uid ();
102650503Sobrien
102750503Sobrien  max_labelno = max_label_num ();
102850503Sobrien  min_labelno = get_first_label_num ();
102950503Sobrien  label_align = (struct label_alignment *) xmalloc (
103050503Sobrien    (max_labelno - min_labelno + 1) * sizeof (struct label_alignment));
103150503Sobrien  bzero ((char *) label_align,
103250503Sobrien    (max_labelno - min_labelno + 1) * sizeof (struct label_alignment));
103350503Sobrien
103450503Sobrien  uid_shuid = (int *) xmalloc (max_uid * sizeof *uid_shuid);
103550503Sobrien
103650503Sobrien  /* Initialize label_align and set up uid_shuid to be strictly
103750503Sobrien     monotonically rising with insn order.  */
103850503Sobrien  /* We use max_log here to keep track of the maximum alignment we want to
103950503Sobrien     impose on the next CODE_LABEL (or the current one if we are processing
104050503Sobrien     the CODE_LABEL itself).  */
104150503Sobrien
104250503Sobrien  max_log = 0;
104350503Sobrien  max_skip = 0;
104450503Sobrien
104550503Sobrien  for (insn = get_insns (), i = 1; insn; insn = NEXT_INSN (insn))
104650503Sobrien    {
104750503Sobrien      int log;
104850503Sobrien
104950503Sobrien      INSN_SHUID (insn) = i++;
105050503Sobrien      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
105150503Sobrien	{
105250503Sobrien	  /* reorg might make the first insn of a loop being run once only,
105350503Sobrien             and delete the label in front of it.  Then we want to apply
105450503Sobrien             the loop alignment to the new label created by reorg, which
105550503Sobrien             is separated by the former loop start insn from the
105650503Sobrien	     NOTE_INSN_LOOP_BEG.  */
105750503Sobrien	}
105850503Sobrien      else if (GET_CODE (insn) == CODE_LABEL)
105950503Sobrien	{
106050503Sobrien	  rtx next;
106150503Sobrien
106250503Sobrien	  log = LABEL_ALIGN (insn);
106350503Sobrien	  if (max_log < log)
106450503Sobrien	    {
106550503Sobrien	      max_log = log;
106650503Sobrien	      max_skip = LABEL_ALIGN_MAX_SKIP;
106750503Sobrien	    }
106850503Sobrien	  next = NEXT_INSN (insn);
106950503Sobrien	  /* ADDR_VECs only take room if read-only data goes into the text
107050503Sobrien	     section.  */
107150503Sobrien	  if (JUMP_TABLES_IN_TEXT_SECTION
107250503Sobrien#if !defined(READONLY_DATA_SECTION)
107350503Sobrien	      || 1
107450503Sobrien#endif
107550503Sobrien	      )
107650503Sobrien	    if (next && GET_CODE (next) == JUMP_INSN)
107750503Sobrien	      {
107850503Sobrien		rtx nextbody = PATTERN (next);
107950503Sobrien		if (GET_CODE (nextbody) == ADDR_VEC
108050503Sobrien		    || GET_CODE (nextbody) == ADDR_DIFF_VEC)
108150503Sobrien		  {
108250503Sobrien		    log = ADDR_VEC_ALIGN (next);
108350503Sobrien		    if (max_log < log)
108450503Sobrien		      {
108550503Sobrien			max_log = log;
108650503Sobrien			max_skip = LABEL_ALIGN_MAX_SKIP;
108750503Sobrien		      }
108850503Sobrien		  }
108950503Sobrien	      }
109050503Sobrien	  LABEL_TO_ALIGNMENT (insn) = max_log;
109150503Sobrien	  LABEL_TO_MAX_SKIP (insn) = max_skip;
109250503Sobrien	  max_log = 0;
109350503Sobrien	  max_skip = 0;
109450503Sobrien	}
109550503Sobrien      else if (GET_CODE (insn) == BARRIER)
109650503Sobrien	{
109750503Sobrien	  rtx label;
109850503Sobrien
109950503Sobrien	  for (label = insn; label && GET_RTX_CLASS (GET_CODE (label)) != 'i';
110050503Sobrien	       label = NEXT_INSN (label))
110150503Sobrien	    if (GET_CODE (label) == CODE_LABEL)
110250503Sobrien	      {
110350503Sobrien		log = LABEL_ALIGN_AFTER_BARRIER (insn);
110450503Sobrien		if (max_log < log)
110550503Sobrien		  {
110650503Sobrien		    max_log = log;
110750503Sobrien		    max_skip = LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP;
110850503Sobrien		  }
110950503Sobrien		break;
111050503Sobrien	      }
111150503Sobrien	}
111250503Sobrien      /* Again, we allow NOTE_INSN_LOOP_BEG - INSN - CODE_LABEL
111350503Sobrien	 sequences in order to handle reorg output efficiently.  */
111450503Sobrien      else if (GET_CODE (insn) == NOTE
111550503Sobrien	       && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
111650503Sobrien	{
111750503Sobrien	  rtx label;
111850503Sobrien
111950503Sobrien	  for (label = insn; label; label = NEXT_INSN (label))
112050503Sobrien	    if (GET_CODE (label) == CODE_LABEL)
112150503Sobrien	      {
112250503Sobrien		log = LOOP_ALIGN (insn);
112350503Sobrien		if (max_log < log)
112450503Sobrien		  {
112550503Sobrien		    max_log = log;
112650503Sobrien		    max_skip = LOOP_ALIGN_MAX_SKIP;
112750503Sobrien		  }
112850503Sobrien		break;
112950503Sobrien	      }
113050503Sobrien	}
113150503Sobrien      else
113250503Sobrien	continue;
113350503Sobrien    }
113450503Sobrien#ifdef HAVE_ATTR_length
113550503Sobrien
113650503Sobrien  /* Allocate the rest of the arrays.  */
113750503Sobrien  insn_lengths = (short *) xmalloc (max_uid * sizeof (short));
113850503Sobrien  insn_addresses = (int *) xmalloc (max_uid * sizeof (int));
113952515Sobrien  insn_lengths_max_uid = max_uid;
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]);
132552515Sobrien      if (insn_lengths[uid] < 0)
132652515Sobrien	fatal_insn ("Negative insn length", insn);
132718334Speter#endif
132818334Speter    }
132918334Speter
133018334Speter  /* Now loop over all the insns finding varying length insns.  For each,
133118334Speter     get the current insn length.  If it has changed, reflect the change.
133218334Speter     When nothing changes for a full pass, we are done.  */
133318334Speter
133418334Speter  while (something_changed)
133518334Speter    {
133618334Speter      something_changed = 0;
133750503Sobrien      insn_current_align = MAX_CODE_ALIGN - 1;
133818334Speter      for (insn_current_address = FIRST_INSN_ADDRESS, insn = first;
133918334Speter	   insn != 0;
134018334Speter	   insn = NEXT_INSN (insn))
134118334Speter	{
134218334Speter	  int new_length;
134350503Sobrien#ifdef ADJUST_INSN_LENGTH
134418334Speter	  int tmp_length;
134550503Sobrien#endif
134650503Sobrien	  int length_align;
134718334Speter
134818334Speter	  uid = INSN_UID (insn);
134950503Sobrien
135050503Sobrien	  if (GET_CODE (insn) == CODE_LABEL)
135150503Sobrien	    {
135250503Sobrien	      int log = LABEL_TO_ALIGNMENT (insn);
135350503Sobrien	      if (log > insn_current_align)
135450503Sobrien		{
135550503Sobrien		  int align = 1 << log;
135650503Sobrien		  int new_address= (insn_current_address + align - 1) & -align;
135750503Sobrien		  insn_lengths[uid] = new_address - insn_current_address;
135850503Sobrien		  insn_current_align = log;
135950503Sobrien		  insn_current_address = new_address;
136050503Sobrien		}
136150503Sobrien	      else
136250503Sobrien		insn_lengths[uid] = 0;
136350503Sobrien	      insn_addresses[uid] = insn_current_address;
136450503Sobrien	      continue;
136550503Sobrien	    }
136650503Sobrien
136750503Sobrien	  length_align = INSN_LENGTH_ALIGNMENT (insn);
136850503Sobrien	  if (length_align < insn_current_align)
136950503Sobrien	    insn_current_align = length_align;
137050503Sobrien
137150503Sobrien	  insn_last_address = insn_addresses[uid];
137218334Speter	  insn_addresses[uid] = insn_current_address;
137350503Sobrien
137450503Sobrien#ifdef CASE_VECTOR_SHORTEN_MODE
137550503Sobrien	  if (optimize && GET_CODE (insn) == JUMP_INSN
137650503Sobrien	      && GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
137718334Speter	    {
137850503Sobrien	      rtx body = PATTERN (insn);
137950503Sobrien	      int old_length = insn_lengths[uid];
138050503Sobrien	      rtx rel_lab = XEXP (XEXP (body, 0), 0);
138150503Sobrien	      rtx min_lab = XEXP (XEXP (body, 2), 0);
138250503Sobrien	      rtx max_lab = XEXP (XEXP (body, 3), 0);
138350503Sobrien	      addr_diff_vec_flags flags = ADDR_DIFF_VEC_FLAGS (body);
138450503Sobrien	      int rel_addr = insn_addresses[INSN_UID (rel_lab)];
138550503Sobrien	      int min_addr = insn_addresses[INSN_UID (min_lab)];
138650503Sobrien	      int max_addr = insn_addresses[INSN_UID (max_lab)];
138750503Sobrien	      rtx prev;
138850503Sobrien	      int rel_align = 0;
138950503Sobrien
139050503Sobrien	      /* Try to find a known alignment for rel_lab.  */
139150503Sobrien	      for (prev = rel_lab;
139250503Sobrien		   prev
139350503Sobrien		   && ! insn_lengths[INSN_UID (prev)]
139450503Sobrien		   && ! (varying_length[INSN_UID (prev)] & 1);
139550503Sobrien		   prev = PREV_INSN (prev))
139650503Sobrien		if (varying_length[INSN_UID (prev)] & 2)
139750503Sobrien		  {
139850503Sobrien		    rel_align = LABEL_TO_ALIGNMENT (prev);
139950503Sobrien		    break;
140050503Sobrien		  }
140150503Sobrien
140250503Sobrien	      /* See the comment on addr_diff_vec_flags in rtl.h for the
140350503Sobrien		 meaning of the flags values.  base: REL_LAB   vec: INSN  */
140450503Sobrien	      /* Anything after INSN has still addresses from the last
140550503Sobrien		 pass; adjust these so that they reflect our current
140650503Sobrien		 estimate for this pass.  */
140750503Sobrien	      if (flags.base_after_vec)
140850503Sobrien		rel_addr += insn_current_address - insn_last_address;
140950503Sobrien	      if (flags.min_after_vec)
141050503Sobrien		min_addr += insn_current_address - insn_last_address;
141150503Sobrien	      if (flags.max_after_vec)
141250503Sobrien		max_addr += insn_current_address - insn_last_address;
141350503Sobrien	      /* We want to know the worst case, i.e. lowest possible value
141450503Sobrien		 for the offset of MIN_LAB.  If MIN_LAB is after REL_LAB,
141550503Sobrien		 its offset is positive, and we have to be wary of code shrink;
141650503Sobrien		 otherwise, it is negative, and we have to be vary of code
141750503Sobrien		 size increase.  */
141850503Sobrien	      if (flags.min_after_base)
141950503Sobrien		{
142050503Sobrien		  /* If INSN is between REL_LAB and MIN_LAB, the size
142150503Sobrien		     changes we are about to make can change the alignment
142250503Sobrien		     within the observed offset, therefore we have to break
142350503Sobrien		     it up into two parts that are independent.  */
142450503Sobrien		  if (! flags.base_after_vec && flags.min_after_vec)
142550503Sobrien		    {
142650503Sobrien		      min_addr -= align_fuzz (rel_lab, insn, rel_align, 0);
142750503Sobrien		      min_addr -= align_fuzz (insn, min_lab, 0, 0);
142850503Sobrien		    }
142950503Sobrien		  else
143050503Sobrien		    min_addr -= align_fuzz (rel_lab, min_lab, rel_align, 0);
143150503Sobrien		}
143250503Sobrien	      else
143350503Sobrien		{
143450503Sobrien		  if (flags.base_after_vec && ! flags.min_after_vec)
143550503Sobrien		    {
143650503Sobrien		      min_addr -= align_fuzz (min_lab, insn, 0, ~0);
143750503Sobrien		      min_addr -= align_fuzz (insn, rel_lab, 0, ~0);
143850503Sobrien		    }
143950503Sobrien		  else
144050503Sobrien		    min_addr -= align_fuzz (min_lab, rel_lab, 0, ~0);
144150503Sobrien		}
144250503Sobrien	      /* Likewise, determine the highest lowest possible value
144350503Sobrien		 for the offset of MAX_LAB.  */
144450503Sobrien	      if (flags.max_after_base)
144550503Sobrien		{
144650503Sobrien		  if (! flags.base_after_vec && flags.max_after_vec)
144750503Sobrien		    {
144850503Sobrien		      max_addr += align_fuzz (rel_lab, insn, rel_align, ~0);
144950503Sobrien		      max_addr += align_fuzz (insn, max_lab, 0, ~0);
145050503Sobrien		    }
145150503Sobrien		  else
145250503Sobrien		    max_addr += align_fuzz (rel_lab, max_lab, rel_align, ~0);
145350503Sobrien		}
145450503Sobrien	      else
145550503Sobrien		{
145650503Sobrien		  if (flags.base_after_vec && ! flags.max_after_vec)
145750503Sobrien		    {
145850503Sobrien		      max_addr += align_fuzz (max_lab, insn, 0, 0);
145950503Sobrien		      max_addr += align_fuzz (insn, rel_lab, 0, 0);
146050503Sobrien		    }
146150503Sobrien		  else
146250503Sobrien		    max_addr += align_fuzz (max_lab, rel_lab, 0, 0);
146350503Sobrien		}
146450503Sobrien	      PUT_MODE (body, CASE_VECTOR_SHORTEN_MODE (min_addr - rel_addr,
146550503Sobrien							max_addr - rel_addr,
146650503Sobrien							body));
146750503Sobrien	      if (JUMP_TABLES_IN_TEXT_SECTION
146850503Sobrien#if !defined(READONLY_DATA_SECTION)
146950503Sobrien		  || 1
147050503Sobrien#endif
147150503Sobrien		  )
147250503Sobrien		{
147350503Sobrien		  insn_lengths[uid]
147450503Sobrien		    = (XVECLEN (body, 1) * GET_MODE_SIZE (GET_MODE (body)));
147550503Sobrien		  insn_current_address += insn_lengths[uid];
147650503Sobrien		  if (insn_lengths[uid] != old_length)
147750503Sobrien		    something_changed = 1;
147850503Sobrien		}
147950503Sobrien
148050503Sobrien	      continue;
148150503Sobrien	    }
148250503Sobrien#endif /* CASE_VECTOR_SHORTEN_MODE */
148350503Sobrien
148450503Sobrien	  if (! (varying_length[uid]))
148550503Sobrien	    {
148618334Speter	      insn_current_address += insn_lengths[uid];
148718334Speter	      continue;
148818334Speter	    }
148918334Speter	  if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE)
149018334Speter	    {
149118334Speter	      int i;
149218334Speter
149318334Speter	      body = PATTERN (insn);
149418334Speter	      new_length = 0;
149518334Speter	      for (i = 0; i < XVECLEN (body, 0); i++)
149618334Speter		{
149718334Speter		  rtx inner_insn = XVECEXP (body, 0, i);
149818334Speter		  int inner_uid = INSN_UID (inner_insn);
149918334Speter		  int inner_length;
150018334Speter
150118334Speter		  insn_addresses[inner_uid] = insn_current_address;
150218334Speter
150318334Speter		  /* insn_current_length returns 0 for insns with a
150418334Speter		     non-varying length.  */
150518334Speter		  if (! varying_length[inner_uid])
150618334Speter		    inner_length = insn_lengths[inner_uid];
150718334Speter		  else
150818334Speter		    inner_length = insn_current_length (inner_insn);
150918334Speter
151018334Speter		  if (inner_length != insn_lengths[inner_uid])
151118334Speter		    {
151218334Speter		      insn_lengths[inner_uid] = inner_length;
151318334Speter		      something_changed = 1;
151418334Speter		    }
151518334Speter		  insn_current_address += insn_lengths[inner_uid];
151618334Speter		  new_length += inner_length;
151718334Speter		}
151818334Speter	    }
151918334Speter	  else
152018334Speter	    {
152118334Speter	      new_length = insn_current_length (insn);
152218334Speter	      insn_current_address += new_length;
152318334Speter	    }
152418334Speter
152518334Speter#ifdef ADJUST_INSN_LENGTH
152618334Speter	  /* If needed, do any adjustment.  */
152718334Speter	  tmp_length = new_length;
152818334Speter	  ADJUST_INSN_LENGTH (insn, new_length);
152918334Speter	  insn_current_address += (new_length - tmp_length);
153018334Speter#endif
153118334Speter
153218334Speter	  if (new_length != insn_lengths[uid])
153318334Speter	    {
153418334Speter	      insn_lengths[uid] = new_length;
153518334Speter	      something_changed = 1;
153618334Speter	    }
153718334Speter	}
153818334Speter      /* For a non-optimizing compile, do only a single pass.  */
153918334Speter      if (!optimize)
154018334Speter	break;
154118334Speter    }
154250503Sobrien
154350503Sobrien  free (varying_length);
154450503Sobrien
154518334Speter#endif /* HAVE_ATTR_length */
154618334Speter}
154718334Speter
154818334Speter#ifdef HAVE_ATTR_length
154918334Speter/* Given the body of an INSN known to be generated by an ASM statement, return
155018334Speter   the number of machine instructions likely to be generated for this insn.
155118334Speter   This is used to compute its length.  */
155218334Speter
155318334Speterstatic int
155418334Speterasm_insn_count (body)
155518334Speter     rtx body;
155618334Speter{
155718334Speter  char *template;
155818334Speter  int count = 1;
155918334Speter
156018334Speter  if (GET_CODE (body) == ASM_INPUT)
156118334Speter    template = XSTR (body, 0);
156218334Speter  else
156318334Speter    template = decode_asm_operands (body, NULL_PTR, NULL_PTR,
156418334Speter				    NULL_PTR, NULL_PTR);
156518334Speter
156618334Speter  for ( ; *template; template++)
156718334Speter    if (IS_ASM_LOGICAL_LINE_SEPARATOR(*template) || *template == '\n')
156818334Speter      count++;
156918334Speter
157018334Speter  return count;
157118334Speter}
157218334Speter#endif
157318334Speter
157418334Speter/* Output assembler code for the start of a function,
157518334Speter   and initialize some of the variables in this file
157618334Speter   for the new function.  The label for the function and associated
157718334Speter   assembler pseudo-ops have already been output in `assemble_start_function'.
157818334Speter
157918334Speter   FIRST is the first insn of the rtl for the function being compiled.
158018334Speter   FILE is the file to write assembler code to.
158118334Speter   OPTIMIZE is nonzero if we should eliminate redundant
158218334Speter     test and compare insns.  */
158318334Speter
158418334Spetervoid
158518334Speterfinal_start_function (first, file, optimize)
158618334Speter     rtx first;
158718334Speter     FILE *file;
158818334Speter     int optimize;
158918334Speter{
159018334Speter  block_depth = 0;
159118334Speter
159218334Speter  this_is_asm_operands = 0;
159318334Speter
159418334Speter#ifdef NON_SAVING_SETJMP
159518334Speter  /* A function that calls setjmp should save and restore all the
159618334Speter     call-saved registers on a system where longjmp clobbers them.  */
159718334Speter  if (NON_SAVING_SETJMP && current_function_calls_setjmp)
159818334Speter    {
159918334Speter      int i;
160018334Speter
160118334Speter      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
160252515Sobrien	if (!call_used_regs[i])
160318334Speter	  regs_ever_live[i] = 1;
160418334Speter    }
160518334Speter#endif
160618334Speter
160718334Speter  /* Initial line number is supposed to be output
160818334Speter     before the function's prologue and label
160918334Speter     so that the function's address will not appear to be
161018334Speter     in the last statement of the preceding function.  */
161118334Speter  if (NOTE_LINE_NUMBER (first) != NOTE_INSN_DELETED)
161218334Speter    last_linenum = high_block_linenum = high_function_linenum
161318334Speter      = NOTE_LINE_NUMBER (first);
161418334Speter
161550503Sobrien#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
161650503Sobrien  /* Output DWARF definition of the function.  */
161750503Sobrien  if (dwarf2out_do_frame ())
161850503Sobrien    dwarf2out_begin_prologue ();
161950503Sobrien#endif
162050503Sobrien
162118334Speter  /* For SDB and XCOFF, the function beginning must be marked between
162218334Speter     the function label and the prologue.  We always need this, even when
162318334Speter     -g1 was used.  Defer on MIPS systems so that parameter descriptions
162450503Sobrien     follow function entry.  */
162518334Speter#if defined(SDB_DEBUGGING_INFO) && !defined(MIPS_DEBUGGING_INFO)
162618334Speter  if (write_symbols == SDB_DEBUG)
162718334Speter    sdbout_begin_function (last_linenum);
162818334Speter  else
162918334Speter#endif
163018334Speter#ifdef XCOFF_DEBUGGING_INFO
163118334Speter    if (write_symbols == XCOFF_DEBUG)
163218334Speter      xcoffout_begin_function (file, last_linenum);
163318334Speter    else
163418334Speter#endif
163518334Speter      /* But only output line number for other debug info types if -g2
163618334Speter	 or better.  */
163718334Speter      if (NOTE_LINE_NUMBER (first) != NOTE_INSN_DELETED)
163818334Speter	output_source_line (file, first);
163918334Speter
164018334Speter#ifdef LEAF_REG_REMAP
164152515Sobrien  if (current_function_uses_only_leaf_regs)
164218334Speter    leaf_renumber_regs (first);
164318334Speter#endif
164418334Speter
164518347Speter  if (profile_block_flag)
164618347Speter    add_bb (file);
164718347Speter
164818334Speter  /* The Sun386i and perhaps other machines don't work right
164918334Speter     if the profiling code comes after the prologue.  */
165018334Speter#ifdef PROFILE_BEFORE_PROLOGUE
165118334Speter  if (profile_flag)
165218334Speter    profile_function (file);
165318334Speter#endif /* PROFILE_BEFORE_PROLOGUE */
165418334Speter
165550503Sobrien#if defined (DWARF2_UNWIND_INFO) && defined (HAVE_prologue)
165650503Sobrien  if (dwarf2out_do_frame ())
165750503Sobrien    dwarf2out_frame_debug (NULL_RTX);
165850503Sobrien#endif
165950503Sobrien
166018334Speter#ifdef FUNCTION_PROLOGUE
166118334Speter  /* First output the function prologue: code to set up the stack frame.  */
166218334Speter  FUNCTION_PROLOGUE (file, get_frame_size ());
166318334Speter#endif
166418334Speter
166518334Speter#if defined (SDB_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
166618334Speter  if (write_symbols == SDB_DEBUG || write_symbols == XCOFF_DEBUG)
166718334Speter    next_block_index = 1;
166818334Speter#endif
166918334Speter
167018334Speter  /* If the machine represents the prologue as RTL, the profiling code must
167118334Speter     be emitted when NOTE_INSN_PROLOGUE_END is scanned.  */
167218334Speter#ifdef HAVE_prologue
167318334Speter  if (! HAVE_prologue)
167418334Speter#endif
167518334Speter    profile_after_prologue (file);
167618334Speter
167718334Speter  profile_label_no++;
167818334Speter
167918334Speter  /* If we are doing basic block profiling, remember a printable version
168018334Speter     of the function name.  */
168118334Speter  if (profile_block_flag)
168218334Speter    {
168350503Sobrien      bb_func_label_num
168450503Sobrien	= add_bb_string ((*decl_printable_name) (current_function_decl, 2), FALSE);
168518334Speter    }
168618334Speter}
168718334Speter
168818334Speterstatic void
168918334Speterprofile_after_prologue (file)
169018334Speter     FILE *file;
169118334Speter{
169218334Speter#ifdef FUNCTION_BLOCK_PROFILER
169318334Speter  if (profile_block_flag)
169418334Speter    {
169550503Sobrien      FUNCTION_BLOCK_PROFILER (file, count_basic_blocks);
169618334Speter    }
169718334Speter#endif /* FUNCTION_BLOCK_PROFILER */
169818334Speter
169918334Speter#ifndef PROFILE_BEFORE_PROLOGUE
170018334Speter  if (profile_flag)
170118334Speter    profile_function (file);
170218334Speter#endif /* not PROFILE_BEFORE_PROLOGUE */
170318334Speter}
170418334Speter
170518334Speterstatic void
170618334Speterprofile_function (file)
170718334Speter     FILE *file;
170818334Speter{
170974478Sobrien#ifndef NO_PROFILE_COUNTERS
171050503Sobrien  int align = MIN (BIGGEST_ALIGNMENT, LONG_TYPE_SIZE);
171174478Sobrien#endif
171250503Sobrien#if defined(ASM_OUTPUT_REG_PUSH)
171350503Sobrien#if defined(STRUCT_VALUE_INCOMING_REGNUM) || defined(STRUCT_VALUE_REGNUM)
171418334Speter  int sval = current_function_returns_struct;
171550503Sobrien#endif
171650503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) || defined(STATIC_CHAIN_REGNUM)
171718334Speter  int cxt = current_function_needs_context;
171850503Sobrien#endif
171950503Sobrien#endif /* ASM_OUTPUT_REG_PUSH */
172018334Speter
172174478Sobrien#ifndef NO_PROFILE_COUNTERS
172218334Speter  data_section ();
172318334Speter  ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
172418334Speter  ASM_OUTPUT_INTERNAL_LABEL (file, "LP", profile_label_no);
172550503Sobrien  assemble_integer (const0_rtx, LONG_TYPE_SIZE / BITS_PER_UNIT, 1);
172674478Sobrien#endif
172718334Speter
172850503Sobrien  function_section (current_function_decl);
172918334Speter
173050503Sobrien#if defined(STRUCT_VALUE_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
173118334Speter  if (sval)
173218334Speter    ASM_OUTPUT_REG_PUSH (file, STRUCT_VALUE_INCOMING_REGNUM);
173318334Speter#else
173450503Sobrien#if defined(STRUCT_VALUE_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
173518334Speter  if (sval)
173650503Sobrien    {
173750503Sobrien      ASM_OUTPUT_REG_PUSH (file, STRUCT_VALUE_REGNUM);
173850503Sobrien    }
173918334Speter#endif
174018334Speter#endif
174118334Speter
174250503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
174318334Speter  if (cxt)
174418334Speter    ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_INCOMING_REGNUM);
174518334Speter#else
174650503Sobrien#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
174718334Speter  if (cxt)
174850503Sobrien    {
174950503Sobrien      ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_REGNUM);
175050503Sobrien    }
175118334Speter#endif
175218334Speter#endif
175318334Speter
175418334Speter  FUNCTION_PROFILER (file, profile_label_no);
175518334Speter
175650503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
175718334Speter  if (cxt)
175818334Speter    ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_INCOMING_REGNUM);
175918334Speter#else
176050503Sobrien#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
176118334Speter  if (cxt)
176250503Sobrien    {
176350503Sobrien      ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_REGNUM);
176450503Sobrien    }
176518334Speter#endif
176618334Speter#endif
176718334Speter
176850503Sobrien#if defined(STRUCT_VALUE_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
176918334Speter  if (sval)
177018334Speter    ASM_OUTPUT_REG_POP (file, STRUCT_VALUE_INCOMING_REGNUM);
177118334Speter#else
177250503Sobrien#if defined(STRUCT_VALUE_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
177318334Speter  if (sval)
177450503Sobrien    {
177550503Sobrien      ASM_OUTPUT_REG_POP (file, STRUCT_VALUE_REGNUM);
177650503Sobrien    }
177718334Speter#endif
177818334Speter#endif
177918334Speter}
178018334Speter
178118334Speter/* Output assembler code for the end of a function.
178218334Speter   For clarity, args are same as those of `final_start_function'
178318334Speter   even though not all of them are needed.  */
178418334Speter
178518334Spetervoid
178618334Speterfinal_end_function (first, file, optimize)
178718334Speter     rtx first;
178818334Speter     FILE *file;
178918334Speter     int optimize;
179018334Speter{
179118334Speter  if (app_on)
179218334Speter    {
179350503Sobrien      fputs (ASM_APP_OFF, file);
179418334Speter      app_on = 0;
179518334Speter    }
179618334Speter
179718334Speter#ifdef SDB_DEBUGGING_INFO
179818334Speter  if (write_symbols == SDB_DEBUG)
179918334Speter    sdbout_end_function (high_function_linenum);
180018334Speter#endif
180118334Speter
180218334Speter#ifdef DWARF_DEBUGGING_INFO
180318334Speter  if (write_symbols == DWARF_DEBUG)
180418334Speter    dwarfout_end_function ();
180518334Speter#endif
180618334Speter
180718334Speter#ifdef XCOFF_DEBUGGING_INFO
180818334Speter  if (write_symbols == XCOFF_DEBUG)
180918334Speter    xcoffout_end_function (file, high_function_linenum);
181018334Speter#endif
181118334Speter
181218334Speter#ifdef FUNCTION_EPILOGUE
181318334Speter  /* Finally, output the function epilogue:
181418334Speter     code to restore the stack frame and return to the caller.  */
181518334Speter  FUNCTION_EPILOGUE (file, get_frame_size ());
181618334Speter#endif
181718334Speter
181818347Speter  if (profile_block_flag)
181918347Speter    add_bb (file);
182018347Speter
182118334Speter#ifdef SDB_DEBUGGING_INFO
182218334Speter  if (write_symbols == SDB_DEBUG)
182318334Speter    sdbout_end_epilogue ();
182418334Speter#endif
182518334Speter
182618334Speter#ifdef DWARF_DEBUGGING_INFO
182718334Speter  if (write_symbols == DWARF_DEBUG)
182818334Speter    dwarfout_end_epilogue ();
182918334Speter#endif
183018334Speter
183150503Sobrien#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
183250503Sobrien  if (dwarf2out_do_frame ())
183350503Sobrien    dwarf2out_end_epilogue ();
183450503Sobrien#endif
183550503Sobrien
183618334Speter#ifdef XCOFF_DEBUGGING_INFO
183718334Speter  if (write_symbols == XCOFF_DEBUG)
183818334Speter    xcoffout_end_epilogue (file);
183918334Speter#endif
184018334Speter
184118334Speter  bb_func_label_num = -1;	/* not in function, nuke label # */
184218334Speter
184318334Speter  /* If FUNCTION_EPILOGUE is not defined, then the function body
184418334Speter     itself contains return instructions wherever needed.  */
184518334Speter}
184618334Speter
184718334Speter/* Add a block to the linked list that remembers the current line/file/function
184818334Speter   for basic block profiling.  Emit the label in front of the basic block and
184918334Speter   the instructions that increment the count field.  */
185018334Speter
185118334Speterstatic void
185218334Speteradd_bb (file)
185318334Speter     FILE *file;
185418334Speter{
185518334Speter  struct bb_list *ptr = (struct bb_list *) permalloc (sizeof (struct bb_list));
185618334Speter
185718334Speter  /* Add basic block to linked list.  */
185818334Speter  ptr->next = 0;
185918334Speter  ptr->line_num = last_linenum;
186018334Speter  ptr->file_label_num = bb_file_label_num;
186118334Speter  ptr->func_label_num = bb_func_label_num;
186218334Speter  *bb_tail = ptr;
186318334Speter  bb_tail = &ptr->next;
186418334Speter
186518334Speter  /* Enable the table of basic-block use counts
186618334Speter     to point at the code it applies to.  */
186718334Speter  ASM_OUTPUT_INTERNAL_LABEL (file, "LPB", count_basic_blocks);
186818334Speter
186918334Speter  /* Before first insn of this basic block, increment the
187018334Speter     count of times it was entered.  */
187118334Speter#ifdef BLOCK_PROFILER
187218334Speter  BLOCK_PROFILER (file, count_basic_blocks);
187350503Sobrien#endif
187450503Sobrien#ifdef HAVE_cc0
187518334Speter  CC_STATUS_INIT;
187618334Speter#endif
187718334Speter
187818334Speter  new_block = 0;
187918334Speter  count_basic_blocks++;
188018334Speter}
188118334Speter
188218334Speter/* Add a string to be used for basic block profiling.  */
188318334Speter
188418334Speterstatic int
188518334Speteradd_bb_string (string, perm_p)
188652515Sobrien     const char *string;
188718334Speter     int perm_p;
188818334Speter{
188918334Speter  int len;
189018334Speter  struct bb_str *ptr = 0;
189118334Speter
189218334Speter  if (!string)
189318334Speter    {
189418334Speter      string = "<unknown>";
189518334Speter      perm_p = TRUE;
189618334Speter    }
189718334Speter
189818334Speter  /* Allocate a new string if the current string isn't permanent.  If
189918334Speter     the string is permanent search for the same string in other
190018334Speter     allocations.  */
190118334Speter
190218334Speter  len = strlen (string) + 1;
190318334Speter  if (!perm_p)
190418334Speter    {
190518334Speter      char *p = (char *) permalloc (len);
190618334Speter      bcopy (string, p, len);
190718334Speter      string = p;
190818334Speter    }
190918334Speter  else
191050503Sobrien    for (ptr = sbb_head; ptr != (struct bb_str *) 0; ptr = ptr->next)
191118334Speter      if (ptr->string == string)
191218334Speter	break;
191318334Speter
191418334Speter  /* Allocate a new string block if we need to.  */
191518334Speter  if (!ptr)
191618334Speter    {
191718334Speter      ptr = (struct bb_str *) permalloc (sizeof (*ptr));
191818334Speter      ptr->next = 0;
191918334Speter      ptr->length = len;
192018334Speter      ptr->label_num = sbb_label_num++;
192118334Speter      ptr->string = string;
192218334Speter      *sbb_tail = ptr;
192318334Speter      sbb_tail = &ptr->next;
192418334Speter    }
192518334Speter
192618334Speter  return ptr->label_num;
192718334Speter}
192818334Speter
192918334Speter
193018334Speter/* Output assembler code for some insns: all or part of a function.
193118334Speter   For description of args, see `final_start_function', above.
193218334Speter
193318334Speter   PRESCAN is 1 if we are not really outputting,
193418334Speter     just scanning as if we were outputting.
193518334Speter   Prescanning deletes and rearranges insns just like ordinary output.
193618334Speter   PRESCAN is -2 if we are outputting after having prescanned.
193718334Speter   In this case, don't try to delete or rearrange insns
193818334Speter   because that has already been done.
193918334Speter   Prescanning is done only on certain machines.  */
194018334Speter
194118334Spetervoid
194218334Speterfinal (first, file, optimize, prescan)
194318334Speter     rtx first;
194418334Speter     FILE *file;
194518334Speter     int optimize;
194618334Speter     int prescan;
194718334Speter{
194818334Speter  register rtx insn;
194918334Speter  int max_line = 0;
195050503Sobrien  int max_uid = 0;
195118334Speter
195218334Speter  last_ignored_compare = 0;
195318334Speter  new_block = 1;
195418334Speter
195550503Sobrien  check_exception_handler_labels ();
195650503Sobrien
195718334Speter  /* Make a map indicating which line numbers appear in this function.
195818334Speter     When producing SDB debugging info, delete troublesome line number
195918334Speter     notes from inlined functions in other files as well as duplicate
196018334Speter     line number notes.  */
196118334Speter#ifdef SDB_DEBUGGING_INFO
196218334Speter  if (write_symbols == SDB_DEBUG)
196318334Speter    {
196418334Speter      rtx last = 0;
196518334Speter      for (insn = first; insn; insn = NEXT_INSN (insn))
196618334Speter	if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
196718334Speter	  {
196818334Speter	    if ((RTX_INTEGRATED_P (insn)
196918334Speter		 && strcmp (NOTE_SOURCE_FILE (insn), main_input_filename) != 0)
197018334Speter		 || (last != 0
197118334Speter		     && NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last)
197218334Speter		     && NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last)))
197318334Speter	      {
197418334Speter		NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
197518334Speter		NOTE_SOURCE_FILE (insn) = 0;
197618334Speter		continue;
197718334Speter	      }
197818334Speter	    last = insn;
197918334Speter	    if (NOTE_LINE_NUMBER (insn) > max_line)
198018334Speter	      max_line = NOTE_LINE_NUMBER (insn);
198118334Speter	  }
198218334Speter    }
198318334Speter  else
198418334Speter#endif
198518334Speter    {
198618334Speter      for (insn = first; insn; insn = NEXT_INSN (insn))
198718334Speter	if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > max_line)
198818334Speter	  max_line = NOTE_LINE_NUMBER (insn);
198918334Speter    }
199018334Speter
199118334Speter  line_note_exists = (char *) oballoc (max_line + 1);
199218334Speter  bzero (line_note_exists, max_line + 1);
199318334Speter
199418334Speter  for (insn = first; insn; insn = NEXT_INSN (insn))
199550503Sobrien    {
199650503Sobrien      if (INSN_UID (insn) > max_uid)       /* find largest UID */
199750503Sobrien        max_uid = INSN_UID (insn);
199850503Sobrien      if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
199950503Sobrien        line_note_exists[NOTE_LINE_NUMBER (insn)] = 1;
200052515Sobrien#ifdef HAVE_cc0
200152515Sobrien      /* If CC tracking across branches is enabled, record the insn which
200252515Sobrien	 jumps to each branch only reached from one place.  */
200352515Sobrien      if (optimize && GET_CODE (insn) == JUMP_INSN)
200452515Sobrien	{
200552515Sobrien	  rtx lab = JUMP_LABEL (insn);
200652515Sobrien	  if (lab && LABEL_NUSES (lab) == 1)
200752515Sobrien	    {
200852515Sobrien	      LABEL_REFS (lab) = insn;
200952515Sobrien	    }
201052515Sobrien	}
201152515Sobrien#endif
201250503Sobrien    }
201318334Speter
201450503Sobrien  /* Initialize insn_eh_region table if eh is being used. */
201550503Sobrien
201650503Sobrien  init_insn_eh_region (first, max_uid);
201750503Sobrien
201818334Speter  init_recog ();
201918334Speter
202018334Speter  CC_STATUS_INIT;
202118334Speter
202218334Speter  /* Output the insns.  */
202318334Speter  for (insn = NEXT_INSN (first); insn;)
202450503Sobrien    {
202550503Sobrien#ifdef HAVE_ATTR_length
202650503Sobrien      insn_current_address = insn_addresses[INSN_UID (insn)];
202750503Sobrien#endif
202850503Sobrien      insn = final_scan_insn (insn, file, optimize, prescan, 0);
202950503Sobrien    }
203018334Speter
203118334Speter  /* Do basic-block profiling here
203218334Speter     if the last insn was a conditional branch.  */
203318334Speter  if (profile_block_flag && new_block)
203418334Speter    add_bb (file);
203550503Sobrien
203650503Sobrien  free_insn_eh_region ();
203718334Speter}
203818334Speter
203918334Speter/* The final scan for one insn, INSN.
204018334Speter   Args are same as in `final', except that INSN
204118334Speter   is the insn being scanned.
204218334Speter   Value returned is the next insn to be scanned.
204318334Speter
204418334Speter   NOPEEPHOLES is the flag to disallow peephole processing (currently
204518334Speter   used for within delayed branch sequence output).  */
204618334Speter
204718334Speterrtx
204818334Speterfinal_scan_insn (insn, file, optimize, prescan, nopeepholes)
204918334Speter     rtx insn;
205018334Speter     FILE *file;
205118334Speter     int optimize;
205218334Speter     int prescan;
205318334Speter     int nopeepholes;
205418334Speter{
205550503Sobrien#ifdef HAVE_cc0
205650503Sobrien  rtx set;
205750503Sobrien#endif
205850503Sobrien
205918334Speter  insn_counter++;
206018334Speter
206118334Speter  /* Ignore deleted insns.  These can occur when we split insns (due to a
206218334Speter     template of "#") while not optimizing.  */
206318334Speter  if (INSN_DELETED_P (insn))
206418334Speter    return NEXT_INSN (insn);
206518334Speter
206618334Speter  switch (GET_CODE (insn))
206718334Speter    {
206818334Speter    case NOTE:
206918334Speter      if (prescan > 0)
207018334Speter	break;
207118334Speter
207218334Speter      /* Align the beginning of a loop, for higher speed
207318334Speter	 on certain machines.  */
207418334Speter
207550503Sobrien      if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
207650503Sobrien	break; /* This used to depend on optimize, but that was bogus.  */
207750503Sobrien      if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
207850503Sobrien	break;
207950503Sobrien
208050503Sobrien      if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG
208150503Sobrien	  && ! exceptions_via_longjmp)
208218334Speter	{
208350503Sobrien	  ASM_OUTPUT_INTERNAL_LABEL (file, "LEHB", NOTE_BLOCK_NUMBER (insn));
208450503Sobrien          if (! flag_new_exceptions)
208550503Sobrien            add_eh_table_entry (NOTE_BLOCK_NUMBER (insn));
208650503Sobrien#ifdef ASM_OUTPUT_EH_REGION_BEG
208750503Sobrien	  ASM_OUTPUT_EH_REGION_BEG (file, NOTE_BLOCK_NUMBER (insn));
208818334Speter#endif
208918334Speter	  break;
209018334Speter	}
209118334Speter
209250503Sobrien      if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END
209350503Sobrien	  && ! exceptions_via_longjmp)
209450503Sobrien	{
209550503Sobrien	  ASM_OUTPUT_INTERNAL_LABEL (file, "LEHE", NOTE_BLOCK_NUMBER (insn));
209650503Sobrien          if (flag_new_exceptions)
209750503Sobrien            add_eh_table_entry (NOTE_BLOCK_NUMBER (insn));
209850503Sobrien#ifdef ASM_OUTPUT_EH_REGION_END
209950503Sobrien	  ASM_OUTPUT_EH_REGION_END (file, NOTE_BLOCK_NUMBER (insn));
210050503Sobrien#endif
210150503Sobrien	  break;
210250503Sobrien	}
210350503Sobrien
210418334Speter      if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_PROLOGUE_END)
210518334Speter	{
210618334Speter#ifdef FUNCTION_END_PROLOGUE
210718334Speter	  FUNCTION_END_PROLOGUE (file);
210818334Speter#endif
210918334Speter	  profile_after_prologue (file);
211018334Speter	  break;
211118334Speter	}
211218334Speter
211318334Speter#ifdef FUNCTION_BEGIN_EPILOGUE
211418334Speter      if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EPILOGUE_BEG)
211518334Speter	{
211618334Speter	  FUNCTION_BEGIN_EPILOGUE (file);
211718334Speter	  break;
211818334Speter	}
211918334Speter#endif
212018334Speter
212118334Speter      if (write_symbols == NO_DEBUG)
212218334Speter	break;
212318334Speter      if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG)
212418334Speter	{
212518334Speter#if defined(SDB_DEBUGGING_INFO) && defined(MIPS_DEBUGGING_INFO)
212618334Speter	  /* MIPS stabs require the parameter descriptions to be after the
212750503Sobrien	     function entry point rather than before.  */
212818334Speter	  if (write_symbols == SDB_DEBUG)
212918334Speter	    sdbout_begin_function (last_linenum);
213018334Speter	  else
213118334Speter#endif
213218334Speter#ifdef DWARF_DEBUGGING_INFO
213318334Speter	  /* This outputs a marker where the function body starts, so it
213418334Speter	     must be after the prologue.  */
213518334Speter	  if (write_symbols == DWARF_DEBUG)
213618334Speter	    dwarfout_begin_function ();
213718334Speter#endif
213818334Speter	  break;
213918334Speter	}
214018334Speter      if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED)
214118334Speter	break;			/* An insn that was "deleted" */
214218334Speter      if (app_on)
214318334Speter	{
214450503Sobrien	  fputs (ASM_APP_OFF, file);
214518334Speter	  app_on = 0;
214618334Speter	}
214718334Speter      if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
214818334Speter	  && (debug_info_level == DINFO_LEVEL_NORMAL
214918334Speter	      || debug_info_level == DINFO_LEVEL_VERBOSE
215018334Speter	      || write_symbols == DWARF_DEBUG
215150503Sobrien	      || write_symbols == DWARF2_DEBUG))
215218334Speter	{
215318334Speter	  /* Beginning of a symbol-block.  Assign it a sequence number
215418334Speter	     and push the number onto the stack PENDING_BLOCKS.  */
215518334Speter
215618334Speter	  if (block_depth == max_block_depth)
215718334Speter	    {
215818334Speter	      /* PENDING_BLOCKS is full; make it longer.  */
215918334Speter	      max_block_depth *= 2;
216018334Speter	      pending_blocks
216118334Speter		= (int *) xrealloc (pending_blocks,
216218334Speter				    max_block_depth * sizeof (int));
216318334Speter	    }
216418334Speter	  pending_blocks[block_depth++] = next_block_index;
216518334Speter
216618334Speter	  high_block_linenum = last_linenum;
216718334Speter
216818334Speter	  /* Output debugging info about the symbol-block beginning.  */
216918334Speter
217018334Speter#ifdef SDB_DEBUGGING_INFO
217118334Speter	  if (write_symbols == SDB_DEBUG)
217218334Speter	    sdbout_begin_block (file, last_linenum, next_block_index);
217318334Speter#endif
217418334Speter#ifdef XCOFF_DEBUGGING_INFO
217518334Speter	  if (write_symbols == XCOFF_DEBUG)
217618334Speter	    xcoffout_begin_block (file, last_linenum, next_block_index);
217718334Speter#endif
217818334Speter#ifdef DBX_DEBUGGING_INFO
217918334Speter	  if (write_symbols == DBX_DEBUG)
218018334Speter	    ASM_OUTPUT_INTERNAL_LABEL (file, "LBB", next_block_index);
218118334Speter#endif
218218334Speter#ifdef DWARF_DEBUGGING_INFO
218350503Sobrien	  if (write_symbols == DWARF_DEBUG)
218418334Speter	    dwarfout_begin_block (next_block_index);
218518334Speter#endif
218650503Sobrien#ifdef DWARF2_DEBUGGING_INFO
218750503Sobrien	  if (write_symbols == DWARF2_DEBUG)
218850503Sobrien	    dwarf2out_begin_block (next_block_index);
218950503Sobrien#endif
219018334Speter
219118334Speter	  next_block_index++;
219218334Speter	}
219318334Speter      else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END
219418334Speter	       && (debug_info_level == DINFO_LEVEL_NORMAL
219518334Speter		   || debug_info_level == DINFO_LEVEL_VERBOSE
219618334Speter	           || write_symbols == DWARF_DEBUG
219750503Sobrien	           || write_symbols == DWARF2_DEBUG))
219818334Speter	{
219918334Speter	  /* End of a symbol-block.  Pop its sequence number off
220018334Speter	     PENDING_BLOCKS and output debugging info based on that.  */
220118334Speter
220218334Speter	  --block_depth;
220352515Sobrien	  if (block_depth < 0)
220452515Sobrien	    abort ();
220518334Speter
220618334Speter#ifdef XCOFF_DEBUGGING_INFO
220752515Sobrien	  if (write_symbols == XCOFF_DEBUG)
220818334Speter	    xcoffout_end_block (file, high_block_linenum,
220918334Speter				pending_blocks[block_depth]);
221018334Speter#endif
221118334Speter#ifdef DBX_DEBUGGING_INFO
221252515Sobrien	  if (write_symbols == DBX_DEBUG)
221318334Speter	    ASM_OUTPUT_INTERNAL_LABEL (file, "LBE",
221418334Speter				       pending_blocks[block_depth]);
221518334Speter#endif
221618334Speter#ifdef SDB_DEBUGGING_INFO
221752515Sobrien	  if (write_symbols == SDB_DEBUG)
221818334Speter	    sdbout_end_block (file, high_block_linenum,
221918334Speter			      pending_blocks[block_depth]);
222018334Speter#endif
222118334Speter#ifdef DWARF_DEBUGGING_INFO
222252515Sobrien	  if (write_symbols == DWARF_DEBUG)
222318334Speter	    dwarfout_end_block (pending_blocks[block_depth]);
222418334Speter#endif
222550503Sobrien#ifdef DWARF2_DEBUGGING_INFO
222652515Sobrien	  if (write_symbols == DWARF2_DEBUG)
222750503Sobrien	    dwarf2out_end_block (pending_blocks[block_depth]);
222850503Sobrien#endif
222918334Speter	}
223018334Speter      else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL
223118334Speter	       && (debug_info_level == DINFO_LEVEL_NORMAL
223218334Speter		   || debug_info_level == DINFO_LEVEL_VERBOSE))
223318334Speter	{
223418334Speter#ifdef DWARF_DEBUGGING_INFO
223518334Speter          if (write_symbols == DWARF_DEBUG)
223618334Speter            dwarfout_label (insn);
223718334Speter#endif
223850503Sobrien#ifdef DWARF2_DEBUGGING_INFO
223950503Sobrien          if (write_symbols == DWARF2_DEBUG)
224050503Sobrien            dwarf2out_label (insn);
224150503Sobrien#endif
224218334Speter	}
224318334Speter      else if (NOTE_LINE_NUMBER (insn) > 0)
224418334Speter	/* This note is a line-number.  */
224518334Speter	{
224618334Speter	  register rtx note;
224718334Speter
224818334Speter#if 0 /* This is what we used to do.  */
224918334Speter	  output_source_line (file, insn);
225018334Speter#endif
225118334Speter	  int note_after = 0;
225218334Speter
225318334Speter	  /* If there is anything real after this note,
225418334Speter	     output it.  If another line note follows, omit this one.  */
225518334Speter	  for (note = NEXT_INSN (insn); note; note = NEXT_INSN (note))
225618334Speter	    {
225718334Speter	      if (GET_CODE (note) != NOTE && GET_CODE (note) != CODE_LABEL)
225818334Speter		break;
225918334Speter	      /* These types of notes can be significant
226018334Speter		 so make sure the preceding line number stays.  */
226118334Speter	      else if (GET_CODE (note) == NOTE
226218334Speter		       && (NOTE_LINE_NUMBER (note) == NOTE_INSN_BLOCK_BEG
226318334Speter			   || NOTE_LINE_NUMBER (note) == NOTE_INSN_BLOCK_END
226418334Speter			   || NOTE_LINE_NUMBER (note) == NOTE_INSN_FUNCTION_BEG))
226518334Speter  		break;
226618334Speter	      else if (GET_CODE (note) == NOTE && NOTE_LINE_NUMBER (note) > 0)
226718334Speter		{
226818334Speter		  /* Another line note follows; we can delete this note
226918334Speter		     if no intervening line numbers have notes elsewhere.  */
227018334Speter		  int num;
227118334Speter		  for (num = NOTE_LINE_NUMBER (insn) + 1;
227218334Speter		       num < NOTE_LINE_NUMBER (note);
227318334Speter		       num++)
227418334Speter		    if (line_note_exists[num])
227518334Speter		      break;
227618334Speter
227718334Speter		  if (num >= NOTE_LINE_NUMBER (note))
227818334Speter		    note_after = 1;
227918334Speter		  break;
228018334Speter		}
228118334Speter	    }
228218334Speter
228318334Speter	  /* Output this line note
228418334Speter	     if it is the first or the last line note in a row.  */
228518334Speter	  if (!note_after)
228618334Speter	    output_source_line (file, insn);
228718334Speter	}
228818334Speter      break;
228918334Speter
229018334Speter    case BARRIER:
229150503Sobrien#if defined (DWARF2_UNWIND_INFO) && !defined (ACCUMULATE_OUTGOING_ARGS)
229250503Sobrien	/* If we push arguments, we need to check all insns for stack
229350503Sobrien	   adjustments.  */
229450503Sobrien	if (dwarf2out_do_frame ())
229550503Sobrien	  dwarf2out_frame_debug (insn);
229618334Speter#endif
229718334Speter      break;
229818334Speter
229918334Speter    case CODE_LABEL:
230050503Sobrien      /* The target port might emit labels in the output function for
230150503Sobrien	 some insn, e.g. sh.c output_branchy_insn.  */
230250503Sobrien      if (CODE_LABEL_NUMBER (insn) <= max_labelno)
230350503Sobrien	{
230450503Sobrien	  int align = LABEL_TO_ALIGNMENT (insn);
230550503Sobrien#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
230650503Sobrien	  int max_skip = LABEL_TO_MAX_SKIP (insn);
230750503Sobrien#endif
230850503Sobrien
230950503Sobrien	  if (align && NEXT_INSN (insn))
231050503Sobrien#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
231150503Sobrien	    ASM_OUTPUT_MAX_SKIP_ALIGN (file, align, max_skip);
231250503Sobrien#else
231350503Sobrien	    ASM_OUTPUT_ALIGN (file, align);
231450503Sobrien#endif
231550503Sobrien	}
231652515Sobrien#ifdef HAVE_cc0
231718334Speter      CC_STATUS_INIT;
231852515Sobrien      /* If this label is reached from only one place, set the condition
231952515Sobrien	 codes from the instruction just before the branch.  */
232052515Sobrien
232152515Sobrien      /* Disabled because some insns set cc_status in the C output code
232252515Sobrien	 and NOTICE_UPDATE_CC alone can set incorrect status.  */
232352515Sobrien      if (0 /* optimize && LABEL_NUSES (insn) == 1*/)
232452515Sobrien	{
232552515Sobrien	  rtx jump = LABEL_REFS (insn);
232652515Sobrien	  rtx barrier = prev_nonnote_insn (insn);
232752515Sobrien	  rtx prev;
232852515Sobrien	  /* If the LABEL_REFS field of this label has been set to point
232952515Sobrien	     at a branch, the predecessor of the branch is a regular
233052515Sobrien	     insn, and that branch is the only way to reach this label,
233152515Sobrien	     set the condition codes based on the branch and its
233252515Sobrien	     predecessor.  */
233352515Sobrien	  if (barrier && GET_CODE (barrier) == BARRIER
233452515Sobrien	      && jump && GET_CODE (jump) == JUMP_INSN
233552515Sobrien	      && (prev = prev_nonnote_insn (jump))
233652515Sobrien	      && GET_CODE (prev) == INSN)
233752515Sobrien	    {
233852515Sobrien	      NOTICE_UPDATE_CC (PATTERN (prev), prev);
233952515Sobrien	      NOTICE_UPDATE_CC (PATTERN (jump), jump);
234052515Sobrien	    }
234152515Sobrien	}
234252515Sobrien#endif
234318334Speter      if (prescan > 0)
234418334Speter	break;
234518334Speter      new_block = 1;
234650503Sobrien
234750503Sobrien#ifdef FINAL_PRESCAN_LABEL
234850503Sobrien      FINAL_PRESCAN_INSN (insn, NULL_PTR, 0);
234950503Sobrien#endif
235050503Sobrien
235118334Speter#ifdef SDB_DEBUGGING_INFO
235218334Speter      if (write_symbols == SDB_DEBUG && LABEL_NAME (insn))
235318334Speter	sdbout_label (insn);
235418334Speter#endif
235518334Speter#ifdef DWARF_DEBUGGING_INFO
235618334Speter      if (write_symbols == DWARF_DEBUG && LABEL_NAME (insn))
235718334Speter	dwarfout_label (insn);
235818334Speter#endif
235950503Sobrien#ifdef DWARF2_DEBUGGING_INFO
236050503Sobrien      if (write_symbols == DWARF2_DEBUG && LABEL_NAME (insn))
236150503Sobrien	dwarf2out_label (insn);
236250503Sobrien#endif
236318334Speter      if (app_on)
236418334Speter	{
236550503Sobrien	  fputs (ASM_APP_OFF, file);
236618334Speter	  app_on = 0;
236718334Speter	}
236818334Speter      if (NEXT_INSN (insn) != 0
236918334Speter	  && GET_CODE (NEXT_INSN (insn)) == JUMP_INSN)
237018334Speter	{
237118334Speter	  rtx nextbody = PATTERN (NEXT_INSN (insn));
237218334Speter
237318334Speter	  /* If this label is followed by a jump-table,
237418334Speter	     make sure we put the label in the read-only section.  Also
237518334Speter	     possibly write the label and jump table together.  */
237618334Speter
237718334Speter	  if (GET_CODE (nextbody) == ADDR_VEC
237818334Speter	      || GET_CODE (nextbody) == ADDR_DIFF_VEC)
237918334Speter	    {
238052515Sobrien#if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)
238152515Sobrien	      /* In this case, the case vector is being moved by the
238252515Sobrien		 target, so don't output the label at all.  Leave that
238352515Sobrien		 to the back end macros.  */
238452515Sobrien#else
238550503Sobrien	      if (! JUMP_TABLES_IN_TEXT_SECTION)
238650503Sobrien		{
238750503Sobrien		  readonly_data_section ();
238818334Speter#ifdef READONLY_DATA_SECTION
238950503Sobrien		  ASM_OUTPUT_ALIGN (file,
239050503Sobrien				    exact_log2 (BIGGEST_ALIGNMENT
239150503Sobrien						/ BITS_PER_UNIT));
239218334Speter#endif /* READONLY_DATA_SECTION */
239350503Sobrien		}
239450503Sobrien	      else
239550503Sobrien		function_section (current_function_decl);
239650503Sobrien
239718334Speter#ifdef ASM_OUTPUT_CASE_LABEL
239818334Speter	      ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn),
239918334Speter				     NEXT_INSN (insn));
240018334Speter#else
240118334Speter	      ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
240218334Speter#endif
240352515Sobrien#endif
240418334Speter	      break;
240518334Speter	    }
240618334Speter	}
240718334Speter
240818334Speter      ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
240918334Speter      break;
241018334Speter
241118334Speter    default:
241218334Speter      {
241318334Speter	register rtx body = PATTERN (insn);
241418334Speter	int insn_code_number;
241552515Sobrien	const char *template;
241650503Sobrien#ifdef HAVE_cc0
241718334Speter	rtx note;
241850503Sobrien#endif
241918334Speter
242018334Speter	/* An INSN, JUMP_INSN or CALL_INSN.
242118334Speter	   First check for special kinds that recog doesn't recognize.  */
242218334Speter
242318334Speter	if (GET_CODE (body) == USE /* These are just declarations */
242418334Speter	    || GET_CODE (body) == CLOBBER)
242518334Speter	  break;
242618334Speter
242718334Speter#ifdef HAVE_cc0
242818334Speter	/* If there is a REG_CC_SETTER note on this insn, it means that
242918334Speter	   the setting of the condition code was done in the delay slot
243018334Speter	   of the insn that branched here.  So recover the cc status
243118334Speter	   from the insn that set it.  */
243218334Speter
243318334Speter	note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX);
243418334Speter	if (note)
243518334Speter	  {
243618334Speter	    NOTICE_UPDATE_CC (PATTERN (XEXP (note, 0)), XEXP (note, 0));
243718334Speter	    cc_prev_status = cc_status;
243818334Speter	  }
243918334Speter#endif
244018334Speter
244118334Speter	/* Detect insns that are really jump-tables
244218334Speter	   and output them as such.  */
244318334Speter
244418334Speter	if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
244518334Speter	  {
244652515Sobrien#if !(defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC))
244718334Speter	    register int vlen, idx;
244852515Sobrien#endif
244918334Speter
245018334Speter	    if (prescan > 0)
245118334Speter	      break;
245218334Speter
245318334Speter	    if (app_on)
245418334Speter	      {
245550503Sobrien		fputs (ASM_APP_OFF, file);
245618334Speter		app_on = 0;
245718334Speter	      }
245818334Speter
245952515Sobrien#if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)
246052515Sobrien	    if (GET_CODE (body) == ADDR_VEC)
246152515Sobrien	      {
246252515Sobrien#ifdef ASM_OUTPUT_ADDR_VEC
246352515Sobrien		ASM_OUTPUT_ADDR_VEC (PREV_INSN (insn), body);
246452515Sobrien#else
246552515Sobrien		abort();
246652515Sobrien#endif
246752515Sobrien	      }
246852515Sobrien	    else
246952515Sobrien	      {
247052515Sobrien#ifdef ASM_OUTPUT_ADDR_DIFF_VEC
247152515Sobrien		ASM_OUTPUT_ADDR_DIFF_VEC (PREV_INSN (insn), body);
247252515Sobrien#else
247352515Sobrien		abort();
247452515Sobrien#endif
247552515Sobrien	      }
247652515Sobrien#else
247718334Speter	    vlen = XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC);
247818334Speter	    for (idx = 0; idx < vlen; idx++)
247918334Speter	      {
248018334Speter		if (GET_CODE (body) == ADDR_VEC)
248118334Speter		  {
248218334Speter#ifdef ASM_OUTPUT_ADDR_VEC_ELT
248318334Speter		    ASM_OUTPUT_ADDR_VEC_ELT
248418334Speter		      (file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0)));
248518334Speter#else
248618334Speter		    abort ();
248718334Speter#endif
248818334Speter		  }
248918334Speter		else
249018334Speter		  {
249118334Speter#ifdef ASM_OUTPUT_ADDR_DIFF_ELT
249218334Speter		    ASM_OUTPUT_ADDR_DIFF_ELT
249318334Speter		      (file,
249450503Sobrien		       body,
249518334Speter		       CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)),
249618334Speter		       CODE_LABEL_NUMBER (XEXP (XEXP (body, 0), 0)));
249718334Speter#else
249818334Speter		    abort ();
249918334Speter#endif
250018334Speter		  }
250118334Speter	      }
250218334Speter#ifdef ASM_OUTPUT_CASE_END
250318334Speter	    ASM_OUTPUT_CASE_END (file,
250418334Speter				 CODE_LABEL_NUMBER (PREV_INSN (insn)),
250518334Speter				 insn);
250618334Speter#endif
250752515Sobrien#endif
250818334Speter
250918334Speter	    function_section (current_function_decl);
251018334Speter
251118334Speter	    break;
251218334Speter	  }
251318334Speter
251418334Speter	/* Do basic-block profiling when we reach a new block.
251518334Speter	   Done here to avoid jump tables.  */
251618334Speter	if (profile_block_flag && new_block)
251718334Speter	  add_bb (file);
251818334Speter
251918334Speter	if (GET_CODE (body) == ASM_INPUT)
252018334Speter	  {
252118334Speter	    /* There's no telling what that did to the condition codes.  */
252218334Speter	    CC_STATUS_INIT;
252318334Speter	    if (prescan > 0)
252418334Speter	      break;
252518334Speter	    if (! app_on)
252618334Speter	      {
252750503Sobrien		fputs (ASM_APP_ON, file);
252818334Speter		app_on = 1;
252918334Speter	      }
253018334Speter	    fprintf (asm_out_file, "\t%s\n", XSTR (body, 0));
253118334Speter	    break;
253218334Speter	  }
253318334Speter
253418334Speter	/* Detect `asm' construct with operands.  */
253518334Speter	if (asm_noperands (body) >= 0)
253618334Speter	  {
253750503Sobrien	    unsigned int noperands = asm_noperands (body);
253818334Speter	    rtx *ops = (rtx *) alloca (noperands * sizeof (rtx));
253918334Speter	    char *string;
254018334Speter
254118334Speter	    /* There's no telling what that did to the condition codes.  */
254218334Speter	    CC_STATUS_INIT;
254318334Speter	    if (prescan > 0)
254418334Speter	      break;
254518334Speter
254618334Speter	    if (! app_on)
254718334Speter	      {
254850503Sobrien		fputs (ASM_APP_ON, file);
254918334Speter		app_on = 1;
255018334Speter	      }
255118334Speter
255218334Speter	    /* Get out the operand values.  */
255318334Speter	    string = decode_asm_operands (body, ops, NULL_PTR,
255418334Speter					  NULL_PTR, NULL_PTR);
255518334Speter	    /* Inhibit aborts on what would otherwise be compiler bugs.  */
255618334Speter	    insn_noperands = noperands;
255718334Speter	    this_is_asm_operands = insn;
255818334Speter
255918334Speter	    /* Output the insn using them.  */
256018334Speter	    output_asm_insn (string, ops);
256118334Speter	    this_is_asm_operands = 0;
256218334Speter	    break;
256318334Speter	  }
256418334Speter
256518334Speter	if (prescan <= 0 && app_on)
256618334Speter	  {
256750503Sobrien	    fputs (ASM_APP_OFF, file);
256818334Speter	    app_on = 0;
256918334Speter	  }
257018334Speter
257118334Speter	if (GET_CODE (body) == SEQUENCE)
257218334Speter	  {
257318334Speter	    /* A delayed-branch sequence */
257418334Speter	    register int i;
257518334Speter	    rtx next;
257618334Speter
257718334Speter	    if (prescan > 0)
257818334Speter	      break;
257918334Speter	    final_sequence = body;
258018334Speter
258118334Speter	    /* The first insn in this SEQUENCE might be a JUMP_INSN that will
258218334Speter	       force the restoration of a comparison that was previously
258318334Speter	       thought unnecessary.  If that happens, cancel this sequence
258418334Speter	       and cause that insn to be restored.  */
258518334Speter
258618334Speter	    next = final_scan_insn (XVECEXP (body, 0, 0), file, 0, prescan, 1);
258718334Speter	    if (next != XVECEXP (body, 0, 1))
258818334Speter	      {
258918334Speter		final_sequence = 0;
259018334Speter		return next;
259118334Speter	      }
259218334Speter
259318334Speter	    for (i = 1; i < XVECLEN (body, 0); i++)
259418334Speter	      {
259518334Speter		rtx insn = XVECEXP (body, 0, i);
259618334Speter		rtx next = NEXT_INSN (insn);
259718334Speter		/* We loop in case any instruction in a delay slot gets
259818334Speter		   split.  */
259918334Speter		do
260018334Speter		  insn = final_scan_insn (insn, file, 0, prescan, 1);
260118334Speter		while (insn != next);
260218334Speter	      }
260318334Speter#ifdef DBR_OUTPUT_SEQEND
260418334Speter	    DBR_OUTPUT_SEQEND (file);
260518334Speter#endif
260618334Speter	    final_sequence = 0;
260718334Speter
260818334Speter	    /* If the insn requiring the delay slot was a CALL_INSN, the
260918334Speter	       insns in the delay slot are actually executed before the
261018334Speter	       called function.  Hence we don't preserve any CC-setting
261118334Speter	       actions in these insns and the CC must be marked as being
261218334Speter	       clobbered by the function.  */
261318334Speter	    if (GET_CODE (XVECEXP (body, 0, 0)) == CALL_INSN)
261450503Sobrien	      {
261550503Sobrien		CC_STATUS_INIT;
261650503Sobrien	      }
261718334Speter
261818334Speter	    /* Following a conditional branch sequence, we have a new basic
261918334Speter	       block.  */
262018334Speter	    if (profile_block_flag)
262118334Speter	      {
262218334Speter		rtx insn = XVECEXP (body, 0, 0);
262318334Speter		rtx body = PATTERN (insn);
262418334Speter
262518334Speter		if ((GET_CODE (insn) == JUMP_INSN && GET_CODE (body) == SET
262618334Speter		     && GET_CODE (SET_SRC (body)) != LABEL_REF)
262718334Speter		    || (GET_CODE (insn) == JUMP_INSN
262818334Speter			&& GET_CODE (body) == PARALLEL
262918334Speter			&& GET_CODE (XVECEXP (body, 0, 0)) == SET
263018334Speter			&& GET_CODE (SET_SRC (XVECEXP (body, 0, 0))) != LABEL_REF))
263118334Speter		  new_block = 1;
263218334Speter	      }
263318334Speter	    break;
263418334Speter	  }
263518334Speter
263618334Speter	/* We have a real machine instruction as rtl.  */
263718334Speter
263818334Speter	body = PATTERN (insn);
263918334Speter
264018334Speter#ifdef HAVE_cc0
264150503Sobrien	set = single_set(insn);
264250503Sobrien
264318334Speter	/* Check for redundant test and compare instructions
264418334Speter	   (when the condition codes are already set up as desired).
264518334Speter	   This is done only when optimizing; if not optimizing,
264618334Speter	   it should be possible for the user to alter a variable
264718334Speter	   with the debugger in between statements
264818334Speter	   and the next statement should reexamine the variable
264918334Speter	   to compute the condition codes.  */
265018334Speter
265150503Sobrien	if (optimize)
265218334Speter	  {
265350503Sobrien#if 0
265450503Sobrien	    rtx set = single_set(insn);
265550503Sobrien#endif
265650503Sobrien
265750503Sobrien	    if (set
265850503Sobrien		&& GET_CODE (SET_DEST (set)) == CC0
265950503Sobrien		&& insn != last_ignored_compare)
266018334Speter	      {
266150503Sobrien		if (GET_CODE (SET_SRC (set)) == SUBREG)
266250503Sobrien		  SET_SRC (set) = alter_subreg (SET_SRC (set));
266350503Sobrien		else if (GET_CODE (SET_SRC (set)) == COMPARE)
266418334Speter		  {
266550503Sobrien		    if (GET_CODE (XEXP (SET_SRC (set), 0)) == SUBREG)
266650503Sobrien		      XEXP (SET_SRC (set), 0)
266750503Sobrien			= alter_subreg (XEXP (SET_SRC (set), 0));
266850503Sobrien		    if (GET_CODE (XEXP (SET_SRC (set), 1)) == SUBREG)
266950503Sobrien		      XEXP (SET_SRC (set), 1)
267050503Sobrien			= alter_subreg (XEXP (SET_SRC (set), 1));
267118334Speter		  }
267250503Sobrien		if ((cc_status.value1 != 0
267350503Sobrien		     && rtx_equal_p (SET_SRC (set), cc_status.value1))
267450503Sobrien		    || (cc_status.value2 != 0
267550503Sobrien			&& rtx_equal_p (SET_SRC (set), cc_status.value2)))
267650503Sobrien		  {
267750503Sobrien		    /* Don't delete insn if it has an addressing side-effect.  */
267850503Sobrien		    if (! FIND_REG_INC_NOTE (insn, 0)
267950503Sobrien			/* or if anything in it is volatile.  */
268050503Sobrien			&& ! volatile_refs_p (PATTERN (insn)))
268150503Sobrien		      {
268250503Sobrien			/* We don't really delete the insn; just ignore it.  */
268350503Sobrien			last_ignored_compare = insn;
268450503Sobrien			break;
268550503Sobrien		      }
268650503Sobrien		  }
268718334Speter	      }
268818334Speter	  }
268918334Speter#endif
269018334Speter
269118334Speter	/* Following a conditional branch, we have a new basic block.
269218334Speter	   But if we are inside a sequence, the new block starts after the
269318334Speter	   last insn of the sequence.  */
269418334Speter	if (profile_block_flag && final_sequence == 0
269518334Speter	    && ((GET_CODE (insn) == JUMP_INSN && GET_CODE (body) == SET
269618334Speter		 && GET_CODE (SET_SRC (body)) != LABEL_REF)
269718334Speter		|| (GET_CODE (insn) == JUMP_INSN && GET_CODE (body) == PARALLEL
269818334Speter		    && GET_CODE (XVECEXP (body, 0, 0)) == SET
269918334Speter		    && GET_CODE (SET_SRC (XVECEXP (body, 0, 0))) != LABEL_REF)))
270018334Speter	  new_block = 1;
270118334Speter
270218334Speter#ifndef STACK_REGS
270318334Speter	/* Don't bother outputting obvious no-ops, even without -O.
270418334Speter	   This optimization is fast and doesn't interfere with debugging.
270518334Speter	   Don't do this if the insn is in a delay slot, since this
270618334Speter	   will cause an improper number of delay insns to be written.  */
270718334Speter	if (final_sequence == 0
270818334Speter	    && prescan >= 0
270918334Speter	    && GET_CODE (insn) == INSN && GET_CODE (body) == SET
271018334Speter	    && GET_CODE (SET_SRC (body)) == REG
271118334Speter	    && GET_CODE (SET_DEST (body)) == REG
271218334Speter	    && REGNO (SET_SRC (body)) == REGNO (SET_DEST (body)))
271318334Speter	  break;
271418334Speter#endif
271518334Speter
271618334Speter#ifdef HAVE_cc0
271718334Speter	/* If this is a conditional branch, maybe modify it
271818334Speter	   if the cc's are in a nonstandard state
271918334Speter	   so that it accomplishes the same thing that it would
272018334Speter	   do straightforwardly if the cc's were set up normally.  */
272118334Speter
272218334Speter	if (cc_status.flags != 0
272318334Speter	    && GET_CODE (insn) == JUMP_INSN
272418334Speter	    && GET_CODE (body) == SET
272518334Speter	    && SET_DEST (body) == pc_rtx
272618334Speter	    && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE
272718334Speter	    && GET_RTX_CLASS (GET_CODE (XEXP (SET_SRC (body), 0))) == '<'
272818334Speter	    && XEXP (XEXP (SET_SRC (body), 0), 0) == cc0_rtx
272918334Speter	    /* This is done during prescan; it is not done again
273018334Speter	       in final scan when prescan has been done.  */
273118334Speter	    && prescan >= 0)
273218334Speter	  {
273318334Speter	    /* This function may alter the contents of its argument
273418334Speter	       and clear some of the cc_status.flags bits.
273518334Speter	       It may also return 1 meaning condition now always true
273618334Speter	       or -1 meaning condition now always false
273718334Speter	       or 2 meaning condition nontrivial but altered.  */
273818334Speter	    register int result = alter_cond (XEXP (SET_SRC (body), 0));
273918334Speter	    /* If condition now has fixed value, replace the IF_THEN_ELSE
274018334Speter	       with its then-operand or its else-operand.  */
274118334Speter	    if (result == 1)
274218334Speter	      SET_SRC (body) = XEXP (SET_SRC (body), 1);
274318334Speter	    if (result == -1)
274418334Speter	      SET_SRC (body) = XEXP (SET_SRC (body), 2);
274518334Speter
274618334Speter	    /* The jump is now either unconditional or a no-op.
274718334Speter	       If it has become a no-op, don't try to output it.
274818334Speter	       (It would not be recognized.)  */
274918334Speter	    if (SET_SRC (body) == pc_rtx)
275018334Speter	      {
275118334Speter		PUT_CODE (insn, NOTE);
275218334Speter		NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
275318334Speter		NOTE_SOURCE_FILE (insn) = 0;
275418334Speter		break;
275518334Speter	      }
275618334Speter	    else if (GET_CODE (SET_SRC (body)) == RETURN)
275718334Speter	      /* Replace (set (pc) (return)) with (return).  */
275818334Speter	      PATTERN (insn) = body = SET_SRC (body);
275918334Speter
276018334Speter	    /* Rerecognize the instruction if it has changed.  */
276118334Speter	    if (result != 0)
276218334Speter	      INSN_CODE (insn) = -1;
276318334Speter	  }
276418334Speter
276518334Speter	/* Make same adjustments to instructions that examine the
276650503Sobrien	   condition codes without jumping and instructions that
276750503Sobrien	   handle conditional moves (if this machine has either one).  */
276818334Speter
276918334Speter	if (cc_status.flags != 0
277050503Sobrien	    && set != 0)
277118334Speter	  {
277250503Sobrien	    rtx cond_rtx, then_rtx, else_rtx;
277350503Sobrien
277450503Sobrien	    if (GET_CODE (insn) != JUMP_INSN
277550503Sobrien		&& GET_CODE (SET_SRC (set)) == IF_THEN_ELSE)
277618334Speter	      {
277750503Sobrien		cond_rtx = XEXP (SET_SRC (set), 0);
277850503Sobrien		then_rtx = XEXP (SET_SRC (set), 1);
277950503Sobrien		else_rtx = XEXP (SET_SRC (set), 2);
278050503Sobrien	      }
278150503Sobrien	    else
278250503Sobrien	      {
278350503Sobrien		cond_rtx = SET_SRC (set);
278450503Sobrien		then_rtx = const_true_rtx;
278550503Sobrien		else_rtx = const0_rtx;
278650503Sobrien	      }
278750503Sobrien
278850503Sobrien	    switch (GET_CODE (cond_rtx))
278950503Sobrien	      {
279018334Speter	      case GTU:
279118334Speter	      case GT:
279218334Speter	      case LTU:
279318334Speter	      case LT:
279418334Speter	      case GEU:
279518334Speter	      case GE:
279618334Speter	      case LEU:
279718334Speter	      case LE:
279818334Speter	      case EQ:
279918334Speter	      case NE:
280018334Speter		{
280118334Speter		  register int result;
280250503Sobrien		  if (XEXP (cond_rtx, 0) != cc0_rtx)
280318334Speter		    break;
280450503Sobrien		  result = alter_cond (cond_rtx);
280518334Speter		  if (result == 1)
280650503Sobrien		    validate_change (insn, &SET_SRC (set), then_rtx, 0);
280718334Speter		  else if (result == -1)
280850503Sobrien		    validate_change (insn, &SET_SRC (set), else_rtx, 0);
280918334Speter		  else if (result == 2)
281018334Speter		    INSN_CODE (insn) = -1;
281150503Sobrien		  if (SET_DEST (set) == SET_SRC (set))
281250503Sobrien		    {
281350503Sobrien		      PUT_CODE (insn, NOTE);
281450503Sobrien		      NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
281550503Sobrien		      NOTE_SOURCE_FILE (insn) = 0;
281650503Sobrien		    }
281718334Speter		}
281850503Sobrien		break;
281950503Sobrien
282050503Sobrien	      default:
282150503Sobrien		break;
282218334Speter	      }
282318334Speter	  }
282450503Sobrien
282518334Speter#endif
282618334Speter
282718334Speter	/* Do machine-specific peephole optimizations if desired.  */
282818334Speter
282918334Speter	if (optimize && !flag_no_peephole && !nopeepholes)
283018334Speter	  {
283118334Speter	    rtx next = peephole (insn);
283218334Speter	    /* When peepholing, if there were notes within the peephole,
283318334Speter	       emit them before the peephole.  */
283418334Speter	    if (next != 0 && next != NEXT_INSN (insn))
283518334Speter	      {
283618334Speter		rtx prev = PREV_INSN (insn);
283718334Speter		rtx note;
283818334Speter
283918334Speter		for (note = NEXT_INSN (insn); note != next;
284018334Speter		     note = NEXT_INSN (note))
284118334Speter		  final_scan_insn (note, file, optimize, prescan, nopeepholes);
284218334Speter
284318334Speter		/* In case this is prescan, put the notes
284418334Speter		   in proper position for later rescan.  */
284518334Speter		note = NEXT_INSN (insn);
284618334Speter		PREV_INSN (note) = prev;
284718334Speter		NEXT_INSN (prev) = note;
284818334Speter		NEXT_INSN (PREV_INSN (next)) = insn;
284918334Speter		PREV_INSN (insn) = PREV_INSN (next);
285018334Speter		NEXT_INSN (insn) = next;
285118334Speter		PREV_INSN (next) = insn;
285218334Speter	      }
285318334Speter
285418334Speter	    /* PEEPHOLE might have changed this.  */
285518334Speter	    body = PATTERN (insn);
285618334Speter	  }
285718334Speter
285818334Speter	/* Try to recognize the instruction.
285918334Speter	   If successful, verify that the operands satisfy the
286018334Speter	   constraints for the instruction.  Crash if they don't,
286118334Speter	   since `reload' should have changed them so that they do.  */
286218334Speter
286318334Speter	insn_code_number = recog_memoized (insn);
286452515Sobrien	extract_insn (insn);
286552515Sobrien	cleanup_subreg_operands (insn);
286618334Speter
286718334Speter#ifdef REGISTER_CONSTRAINTS
286852515Sobrien	if (! constrain_operands (1))
286918334Speter	  fatal_insn_not_found (insn);
287018334Speter#endif
287118334Speter
287218334Speter	/* Some target machines need to prescan each insn before
287318334Speter	   it is output.  */
287418334Speter
287518334Speter#ifdef FINAL_PRESCAN_INSN
287652515Sobrien	FINAL_PRESCAN_INSN (insn, recog_operand, recog_n_operands);
287718334Speter#endif
287818334Speter
287918334Speter#ifdef HAVE_cc0
288018334Speter	cc_prev_status = cc_status;
288118334Speter
288218334Speter	/* Update `cc_status' for this instruction.
288318334Speter	   The instruction's output routine may change it further.
288418334Speter	   If the output routine for a jump insn needs to depend
288518334Speter	   on the cc status, it should look at cc_prev_status.  */
288618334Speter
288718334Speter	NOTICE_UPDATE_CC (body, insn);
288818334Speter#endif
288918334Speter
289018334Speter	debug_insn = insn;
289118334Speter
289250503Sobrien#if defined (DWARF2_UNWIND_INFO) && !defined (ACCUMULATE_OUTGOING_ARGS)
289350503Sobrien	/* If we push arguments, we want to know where the calls are.  */
289450503Sobrien	if (GET_CODE (insn) == CALL_INSN && dwarf2out_do_frame ())
289550503Sobrien	  dwarf2out_frame_debug (insn);
289650503Sobrien#endif
289750503Sobrien
289818334Speter	/* If the proper template needs to be chosen by some C code,
289918334Speter	   run that code and get the real template.  */
290018334Speter
290118334Speter	template = insn_template[insn_code_number];
290218334Speter	if (template == 0)
290318334Speter	  {
290418334Speter	    template = (*insn_outfun[insn_code_number]) (recog_operand, insn);
290518334Speter
290618334Speter	    /* If the C code returns 0, it means that it is a jump insn
290718334Speter	       which follows a deleted test insn, and that test insn
290818334Speter	       needs to be reinserted.  */
290918334Speter	    if (template == 0)
291018334Speter	      {
291118334Speter		if (prev_nonnote_insn (insn) != last_ignored_compare)
291218334Speter		  abort ();
291318334Speter		new_block = 0;
291418334Speter		return prev_nonnote_insn (insn);
291518334Speter	      }
291618334Speter	  }
291718334Speter
291818334Speter	/* If the template is the string "#", it means that this insn must
291918334Speter	   be split.  */
292018334Speter	if (template[0] == '#' && template[1] == '\0')
292118334Speter	  {
292218334Speter	    rtx new = try_split (body, insn, 0);
292318334Speter
292418334Speter	    /* If we didn't split the insn, go away.  */
292518334Speter	    if (new == insn && PATTERN (new) == body)
292650503Sobrien	      fatal_insn ("Could not split insn", insn);
292718334Speter
292850503Sobrien#ifdef HAVE_ATTR_length
292950503Sobrien	    /* This instruction should have been split in shorten_branches,
293050503Sobrien	       to ensure that we would have valid length info for the
293150503Sobrien	       splitees.  */
293250503Sobrien	    abort ();
293350503Sobrien#endif
293450503Sobrien
293518334Speter	    new_block = 0;
293618334Speter	    return new;
293718334Speter	  }
293818334Speter
293918334Speter	if (prescan > 0)
294018334Speter	  break;
294118334Speter
294218334Speter	/* Output assembler code from the template.  */
294318334Speter
294418334Speter	output_asm_insn (template, recog_operand);
294518334Speter
294650503Sobrien#if defined (DWARF2_UNWIND_INFO)
294750503Sobrien#if !defined (ACCUMULATE_OUTGOING_ARGS)
294850503Sobrien	/* If we push arguments, we need to check all insns for stack
294950503Sobrien	   adjustments.  */
295050503Sobrien	if (GET_CODE (insn) == INSN && dwarf2out_do_frame ())
295150503Sobrien	  dwarf2out_frame_debug (insn);
295250503Sobrien#else
295350503Sobrien#if defined (HAVE_prologue)
295450503Sobrien	/* If this insn is part of the prologue, emit DWARF v2
295550503Sobrien	   call frame info.  */
295650503Sobrien	if (RTX_FRAME_RELATED_P (insn) && dwarf2out_do_frame ())
295750503Sobrien	  dwarf2out_frame_debug (insn);
295850503Sobrien#endif
295950503Sobrien#endif
296050503Sobrien#endif
296150503Sobrien
296218334Speter#if 0
296318334Speter	/* It's not at all clear why we did this and doing so interferes
296418334Speter	   with tests we'd like to do to use REG_WAS_0 notes, so let's try
296518334Speter	   with this out.  */
296618334Speter
296718334Speter	/* Mark this insn as having been output.  */
296818334Speter	INSN_DELETED_P (insn) = 1;
296918334Speter#endif
297018334Speter
297118334Speter	debug_insn = 0;
297218334Speter      }
297318334Speter    }
297418334Speter  return NEXT_INSN (insn);
297518334Speter}
297618334Speter
297718334Speter/* Output debugging info to the assembler file FILE
297818334Speter   based on the NOTE-insn INSN, assumed to be a line number.  */
297918334Speter
298018334Speterstatic void
298118334Speteroutput_source_line (file, insn)
298218334Speter     FILE *file;
298318334Speter     rtx insn;
298418334Speter{
298518334Speter  register char *filename = NOTE_SOURCE_FILE (insn);
298618334Speter
298718334Speter  /* Remember filename for basic block profiling.
298818334Speter     Filenames are allocated on the permanent obstack
298918334Speter     or are passed in ARGV, so we don't have to save
299018334Speter     the string.  */
299118334Speter
299218334Speter  if (profile_block_flag && last_filename != filename)
299318334Speter    bb_file_label_num = add_bb_string (filename, TRUE);
299418334Speter
299518334Speter  last_filename = filename;
299618334Speter  last_linenum = NOTE_LINE_NUMBER (insn);
299718334Speter  high_block_linenum = MAX (last_linenum, high_block_linenum);
299818334Speter  high_function_linenum = MAX (last_linenum, high_function_linenum);
299918334Speter
300018334Speter  if (write_symbols != NO_DEBUG)
300118334Speter    {
300218334Speter#ifdef SDB_DEBUGGING_INFO
300318334Speter      if (write_symbols == SDB_DEBUG
300418334Speter#if 0 /* People like having line numbers even in wrong file!  */
300518334Speter	  /* COFF can't handle multiple source files--lose, lose.  */
300618334Speter	  && !strcmp (filename, main_input_filename)
300718334Speter#endif
300818334Speter	  /* COFF relative line numbers must be positive.  */
300918334Speter	  && last_linenum > sdb_begin_function_line)
301018334Speter	{
301118334Speter#ifdef ASM_OUTPUT_SOURCE_LINE
301218334Speter	  ASM_OUTPUT_SOURCE_LINE (file, last_linenum);
301318334Speter#else
301418334Speter	  fprintf (file, "\t.ln\t%d\n",
301518334Speter		   ((sdb_begin_function_line > -1)
301618334Speter		    ? last_linenum - sdb_begin_function_line : 1));
301718334Speter#endif
301818334Speter	}
301918334Speter#endif
302018334Speter
302118334Speter#if defined (DBX_DEBUGGING_INFO)
302218334Speter      if (write_symbols == DBX_DEBUG)
302318334Speter	dbxout_source_line (file, filename, NOTE_LINE_NUMBER (insn));
302418334Speter#endif
302518334Speter
302618334Speter#if defined (XCOFF_DEBUGGING_INFO)
302718334Speter      if (write_symbols == XCOFF_DEBUG)
302818334Speter	xcoffout_source_line (file, filename, insn);
302918334Speter#endif
303018334Speter
303118334Speter#ifdef DWARF_DEBUGGING_INFO
303218334Speter      if (write_symbols == DWARF_DEBUG)
303318334Speter	dwarfout_line (filename, NOTE_LINE_NUMBER (insn));
303418334Speter#endif
303550503Sobrien
303650503Sobrien#ifdef DWARF2_DEBUGGING_INFO
303750503Sobrien      if (write_symbols == DWARF2_DEBUG)
303850503Sobrien	dwarf2out_line (filename, NOTE_LINE_NUMBER (insn));
303950503Sobrien#endif
304018334Speter    }
304118334Speter}
304218334Speter
304352515Sobrien
304452515Sobrien/* For each operand in INSN, simplify (subreg (reg)) so that it refers
304552515Sobrien   directly to the desired hard register.  */
304652515Sobrienvoid
304752515Sobriencleanup_subreg_operands (insn)
304852515Sobrien     rtx insn;
304952515Sobrien{
305052515Sobrien  int i;
305152515Sobrien
305252515Sobrien  extract_insn (insn);
305352515Sobrien  for (i = 0; i < recog_n_operands; i++)
305452515Sobrien    {
305552515Sobrien      if (GET_CODE (recog_operand[i]) == SUBREG)
305652515Sobrien        recog_operand[i] = alter_subreg (recog_operand[i]);
305752515Sobrien      else if (GET_CODE (recog_operand[i]) == PLUS
305852515Sobrien               || GET_CODE (recog_operand[i]) == MULT)
305952515Sobrien       recog_operand[i] = walk_alter_subreg (recog_operand[i]);
306052515Sobrien    }
306152515Sobrien
306252515Sobrien  for (i = 0; i < recog_n_dups; i++)
306352515Sobrien    {
306452515Sobrien      if (GET_CODE (*recog_dup_loc[i]) == SUBREG)
306552515Sobrien        *recog_dup_loc[i] = alter_subreg (*recog_dup_loc[i]);
306652515Sobrien      else if (GET_CODE (*recog_dup_loc[i]) == PLUS
306752515Sobrien               || GET_CODE (*recog_dup_loc[i]) == MULT)
306852515Sobrien        *recog_dup_loc[i] = walk_alter_subreg (*recog_dup_loc[i]);
306952515Sobrien    }
307052515Sobrien}
307152515Sobrien
307218334Speter/* If X is a SUBREG, replace it with a REG or a MEM,
307318334Speter   based on the thing it is a subreg of.  */
307418334Speter
307518334Speterrtx
307618334Speteralter_subreg (x)
307718334Speter     register rtx x;
307818334Speter{
307918334Speter  register rtx y = SUBREG_REG (x);
308050503Sobrien
308118334Speter  if (GET_CODE (y) == SUBREG)
308218334Speter    y = alter_subreg (y);
308318334Speter
308450503Sobrien  /* If reload is operating, we may be replacing inside this SUBREG.
308550503Sobrien     Check for that and make a new one if so.  */
308650503Sobrien  if (reload_in_progress && find_replacement (&SUBREG_REG (x)) != 0)
308750503Sobrien    x = copy_rtx (x);
308850503Sobrien
308918334Speter  if (GET_CODE (y) == REG)
309018334Speter    {
309150503Sobrien      /* If the word size is larger than the size of this register,
309250503Sobrien	 adjust the register number to compensate.  */
309350503Sobrien      /* ??? Note that this just catches stragglers created by/for
309450503Sobrien	 integrate.  It would be better if we either caught these
309550503Sobrien	 earlier, or kept _all_ subregs until now and eliminate
309650503Sobrien	 gen_lowpart and friends.  */
309750503Sobrien
309818334Speter      PUT_CODE (x, REG);
309950503Sobrien#ifdef ALTER_HARD_SUBREG
310050503Sobrien      REGNO (x) = ALTER_HARD_SUBREG(GET_MODE (x), SUBREG_WORD (x),
310150503Sobrien				    GET_MODE (y), REGNO (y));
310250503Sobrien#else
310318334Speter      REGNO (x) = REGNO (y) + SUBREG_WORD (x);
310450503Sobrien#endif
310552515Sobrien      /* This field has a different meaning for REGs and SUBREGs.  Make sure
310652515Sobrien	 to clear it!  */
310752515Sobrien      x->used = 0;
310818334Speter    }
310918334Speter  else if (GET_CODE (y) == MEM)
311018334Speter    {
311118334Speter      register int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
311218334Speter      if (BYTES_BIG_ENDIAN)
311318334Speter	offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x)))
311418334Speter		   - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (y))));
311518334Speter      PUT_CODE (x, MEM);
311652515Sobrien      MEM_COPY_ATTRIBUTES (x, y);
311750503Sobrien      MEM_ALIAS_SET (x) = MEM_ALIAS_SET (y);
311874478Sobrien      XEXP (x, 0) = plus_constant_for_output (XEXP (y, 0), offset);
311918334Speter    }
312018334Speter
312118334Speter  return x;
312218334Speter}
312318334Speter
312418334Speter/* Do alter_subreg on all the SUBREGs contained in X.  */
312518334Speter
312618334Speterstatic rtx
312718334Speterwalk_alter_subreg (x)
312818334Speter     rtx x;
312918334Speter{
313018334Speter  switch (GET_CODE (x))
313118334Speter    {
313218334Speter    case PLUS:
313318334Speter    case MULT:
313418334Speter      XEXP (x, 0) = walk_alter_subreg (XEXP (x, 0));
313518334Speter      XEXP (x, 1) = walk_alter_subreg (XEXP (x, 1));
313618334Speter      break;
313718334Speter
313818334Speter    case MEM:
313918334Speter      XEXP (x, 0) = walk_alter_subreg (XEXP (x, 0));
314018334Speter      break;
314118334Speter
314218334Speter    case SUBREG:
314318334Speter      return alter_subreg (x);
314450503Sobrien
314550503Sobrien    default:
314650503Sobrien      break;
314718334Speter    }
314818334Speter
314918334Speter  return x;
315018334Speter}
315118334Speter
315218334Speter#ifdef HAVE_cc0
315318334Speter
315418334Speter/* Given BODY, the body of a jump instruction, alter the jump condition
315518334Speter   as required by the bits that are set in cc_status.flags.
315618334Speter   Not all of the bits there can be handled at this level in all cases.
315718334Speter
315818334Speter   The value is normally 0.
315918334Speter   1 means that the condition has become always true.
316018334Speter   -1 means that the condition has become always false.
316118334Speter   2 means that COND has been altered.  */
316218334Speter
316318334Speterstatic int
316418334Speteralter_cond (cond)
316518334Speter     register rtx cond;
316618334Speter{
316718334Speter  int value = 0;
316818334Speter
316918334Speter  if (cc_status.flags & CC_REVERSED)
317018334Speter    {
317118334Speter      value = 2;
317218334Speter      PUT_CODE (cond, swap_condition (GET_CODE (cond)));
317318334Speter    }
317418334Speter
317518334Speter  if (cc_status.flags & CC_INVERTED)
317618334Speter    {
317718334Speter      value = 2;
317818334Speter      PUT_CODE (cond, reverse_condition (GET_CODE (cond)));
317918334Speter    }
318018334Speter
318118334Speter  if (cc_status.flags & CC_NOT_POSITIVE)
318218334Speter    switch (GET_CODE (cond))
318318334Speter      {
318418334Speter      case LE:
318518334Speter      case LEU:
318618334Speter      case GEU:
318718334Speter	/* Jump becomes unconditional.  */
318818334Speter	return 1;
318918334Speter
319018334Speter      case GT:
319118334Speter      case GTU:
319218334Speter      case LTU:
319318334Speter	/* Jump becomes no-op.  */
319418334Speter	return -1;
319518334Speter
319618334Speter      case GE:
319718334Speter	PUT_CODE (cond, EQ);
319818334Speter	value = 2;
319918334Speter	break;
320018334Speter
320118334Speter      case LT:
320218334Speter	PUT_CODE (cond, NE);
320318334Speter	value = 2;
320418334Speter	break;
320550503Sobrien
320650503Sobrien      default:
320750503Sobrien	break;
320818334Speter      }
320918334Speter
321018334Speter  if (cc_status.flags & CC_NOT_NEGATIVE)
321118334Speter    switch (GET_CODE (cond))
321218334Speter      {
321318334Speter      case GE:
321418334Speter      case GEU:
321518334Speter	/* Jump becomes unconditional.  */
321618334Speter	return 1;
321718334Speter
321818334Speter      case LT:
321918334Speter      case LTU:
322018334Speter	/* Jump becomes no-op.  */
322118334Speter	return -1;
322218334Speter
322318334Speter      case LE:
322418334Speter      case LEU:
322518334Speter	PUT_CODE (cond, EQ);
322618334Speter	value = 2;
322718334Speter	break;
322818334Speter
322918334Speter      case GT:
323018334Speter      case GTU:
323118334Speter	PUT_CODE (cond, NE);
323218334Speter	value = 2;
323318334Speter	break;
323450503Sobrien
323550503Sobrien      default:
323650503Sobrien	break;
323718334Speter      }
323818334Speter
323918334Speter  if (cc_status.flags & CC_NO_OVERFLOW)
324018334Speter    switch (GET_CODE (cond))
324118334Speter      {
324218334Speter      case GEU:
324318334Speter	/* Jump becomes unconditional.  */
324418334Speter	return 1;
324518334Speter
324618334Speter      case LEU:
324718334Speter	PUT_CODE (cond, EQ);
324818334Speter	value = 2;
324918334Speter	break;
325018334Speter
325118334Speter      case GTU:
325218334Speter	PUT_CODE (cond, NE);
325318334Speter	value = 2;
325418334Speter	break;
325518334Speter
325618334Speter      case LTU:
325718334Speter	/* Jump becomes no-op.  */
325818334Speter	return -1;
325950503Sobrien
326050503Sobrien      default:
326150503Sobrien	break;
326218334Speter      }
326318334Speter
326418334Speter  if (cc_status.flags & (CC_Z_IN_NOT_N | CC_Z_IN_N))
326518334Speter    switch (GET_CODE (cond))
326618334Speter      {
326750503Sobrien      default:
326818334Speter	abort ();
326918334Speter
327018334Speter      case NE:
327118334Speter	PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? GE : LT);
327218334Speter	value = 2;
327318334Speter	break;
327418334Speter
327518334Speter      case EQ:
327618334Speter	PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? LT : GE);
327718334Speter	value = 2;
327818334Speter	break;
327918334Speter      }
328018334Speter
328118334Speter  if (cc_status.flags & CC_NOT_SIGNED)
328218334Speter    /* The flags are valid if signed condition operators are converted
328318334Speter       to unsigned.  */
328418334Speter    switch (GET_CODE (cond))
328518334Speter      {
328618334Speter      case LE:
328718334Speter	PUT_CODE (cond, LEU);
328818334Speter	value = 2;
328918334Speter	break;
329018334Speter
329118334Speter      case LT:
329218334Speter	PUT_CODE (cond, LTU);
329318334Speter	value = 2;
329418334Speter	break;
329518334Speter
329618334Speter      case GT:
329718334Speter	PUT_CODE (cond, GTU);
329818334Speter	value = 2;
329918334Speter	break;
330018334Speter
330118334Speter      case GE:
330218334Speter	PUT_CODE (cond, GEU);
330318334Speter	value = 2;
330418334Speter	break;
330550503Sobrien
330650503Sobrien      default:
330750503Sobrien	break;
330818334Speter      }
330918334Speter
331018334Speter  return value;
331118334Speter}
331218334Speter#endif
331318334Speter
331418334Speter/* Report inconsistency between the assembler template and the operands.
331518334Speter   In an `asm', it's the user's fault; otherwise, the compiler's fault.  */
331618334Speter
331718334Spetervoid
331852515Sobrienoutput_operand_lossage (msgid)
331952515Sobrien     const char *msgid;
332018334Speter{
332118334Speter  if (this_is_asm_operands)
332252515Sobrien    error_for_asm (this_is_asm_operands, "invalid `asm': %s", _(msgid));
332318334Speter  else
332452515Sobrien    fatal ("Internal compiler error, output_operand_lossage `%s'", _(msgid));
332518334Speter}
332618334Speter
332718334Speter/* Output of assembler code from a template, and its subroutines.  */
332818334Speter
332918334Speter/* Output text from TEMPLATE to the assembler output file,
333018334Speter   obeying %-directions to substitute operands taken from
333118334Speter   the vector OPERANDS.
333218334Speter
333318334Speter   %N (for N a digit) means print operand N in usual manner.
333418334Speter   %lN means require operand N to be a CODE_LABEL or LABEL_REF
333518334Speter      and print the label name with no punctuation.
333618334Speter   %cN means require operand N to be a constant
333718334Speter      and print the constant expression with no punctuation.
333818334Speter   %aN means expect operand N to be a memory address
333918334Speter      (not a memory reference!) and print a reference
334018334Speter      to that address.
334118334Speter   %nN means expect operand N to be a constant
334218334Speter      and print a constant expression for minus the value
334318334Speter      of the operand, with no other punctuation.  */
334418334Speter
334518334Speterstatic void
334618334Speteroutput_asm_name ()
334718334Speter{
334818334Speter  if (flag_print_asm_name)
334918334Speter    {
335018334Speter      /* Annotate the assembly with a comment describing the pattern and
335118334Speter	 alternative used.  */
335218334Speter      if (debug_insn)
335318334Speter	{
335418334Speter	  register int num = INSN_CODE (debug_insn);
335552515Sobrien	  fprintf (asm_out_file, "\t%s %d\t%s",
335618334Speter		   ASM_COMMENT_START, INSN_UID (debug_insn), insn_name[num]);
335718334Speter	  if (insn_n_alternatives[num] > 1)
335818334Speter	    fprintf (asm_out_file, "/%d", which_alternative + 1);
335952515Sobrien#ifdef HAVE_ATTR_length
336052515Sobrien	  fprintf (asm_out_file, "\t[length = %d]", get_attr_length (debug_insn));
336152515Sobrien#endif
336218334Speter	  /* Clear this so only the first assembler insn
336318334Speter	     of any rtl insn will get the special comment for -dp.  */
336418334Speter	  debug_insn = 0;
336518334Speter	}
336618334Speter    }
336718334Speter}
336818334Speter
336918334Spetervoid
337018334Speteroutput_asm_insn (template, operands)
337152515Sobrien     const char *template;
337218334Speter     rtx *operands;
337318334Speter{
337452515Sobrien  register const char *p;
337550503Sobrien  register int c;
337618334Speter
337718334Speter  /* An insn may return a null string template
337818334Speter     in a case where no assembler code is needed.  */
337918334Speter  if (*template == 0)
338018334Speter    return;
338118334Speter
338218334Speter  p = template;
338318334Speter  putc ('\t', asm_out_file);
338418334Speter
338518334Speter#ifdef ASM_OUTPUT_OPCODE
338618334Speter  ASM_OUTPUT_OPCODE (asm_out_file, p);
338718334Speter#endif
338818334Speter
338950503Sobrien  while ((c = *p++))
339018334Speter    switch (c)
339118334Speter      {
339218334Speter      case '\n':
339318334Speter	output_asm_name ();
339418334Speter	putc (c, asm_out_file);
339518334Speter#ifdef ASM_OUTPUT_OPCODE
339618334Speter	while ((c = *p) == '\t')
339718334Speter	  {
339818334Speter	    putc (c, asm_out_file);
339918334Speter	    p++;
340018334Speter	  }
340118334Speter	ASM_OUTPUT_OPCODE (asm_out_file, p);
340218334Speter#endif
340318334Speter	break;
340418334Speter
340518334Speter#ifdef ASSEMBLER_DIALECT
340618334Speter      case '{':
340750503Sobrien	{
340850503Sobrien	  register int i;
340950503Sobrien
341050503Sobrien	  /* If we want the first dialect, do nothing.  Otherwise, skip
341150503Sobrien	     DIALECT_NUMBER of strings ending with '|'.  */
341250503Sobrien	  for (i = 0; i < dialect_number; i++)
341350503Sobrien	    {
341450503Sobrien	      while (*p && *p++ != '|')
341550503Sobrien		;
341618334Speter
341750503Sobrien	      if (*p == '|')
341850503Sobrien		p++;
341950503Sobrien	    }
342050503Sobrien	}
342118334Speter	break;
342218334Speter
342318334Speter      case '|':
342418334Speter	/* Skip to close brace.  */
342518334Speter	while (*p && *p++ != '}')
342618334Speter	  ;
342718334Speter	break;
342818334Speter
342918334Speter      case '}':
343018334Speter	break;
343118334Speter#endif
343218334Speter
343318334Speter      case '%':
343418334Speter	/* %% outputs a single %.  */
343518334Speter	if (*p == '%')
343618334Speter	  {
343718334Speter	    p++;
343818334Speter	    putc (c, asm_out_file);
343918334Speter	  }
344018334Speter	/* %= outputs a number which is unique to each insn in the entire
344118334Speter	   compilation.  This is useful for making local labels that are
344218334Speter	   referred to more than once in a given insn.  */
344318334Speter	else if (*p == '=')
344418334Speter	  {
344518334Speter	    p++;
344618334Speter	    fprintf (asm_out_file, "%d", insn_counter);
344718334Speter	  }
344818334Speter	/* % followed by a letter and some digits
344918334Speter	   outputs an operand in a special way depending on the letter.
345018334Speter	   Letters `acln' are implemented directly.
345118334Speter	   Other letters are passed to `output_operand' so that
345218334Speter	   the PRINT_OPERAND macro can define them.  */
345318334Speter	else if ((*p >= 'a' && *p <= 'z')
345418334Speter		 || (*p >= 'A' && *p <= 'Z'))
345518334Speter	  {
345618334Speter	    int letter = *p++;
345718334Speter	    c = atoi (p);
345818334Speter
345918334Speter	    if (! (*p >= '0' && *p <= '9'))
346018334Speter	      output_operand_lossage ("operand number missing after %-letter");
346150503Sobrien	    else if (this_is_asm_operands && (c < 0 || (unsigned int) c >= insn_noperands))
346218334Speter	      output_operand_lossage ("operand number out of range");
346318334Speter	    else if (letter == 'l')
346418334Speter	      output_asm_label (operands[c]);
346518334Speter	    else if (letter == 'a')
346618334Speter	      output_address (operands[c]);
346718334Speter	    else if (letter == 'c')
346818334Speter	      {
346918334Speter		if (CONSTANT_ADDRESS_P (operands[c]))
347018334Speter		  output_addr_const (asm_out_file, operands[c]);
347118334Speter		else
347218334Speter		  output_operand (operands[c], 'c');
347318334Speter	      }
347418334Speter	    else if (letter == 'n')
347518334Speter	      {
347618334Speter		if (GET_CODE (operands[c]) == CONST_INT)
347750503Sobrien		  fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC,
347818334Speter			   - INTVAL (operands[c]));
347918334Speter		else
348018334Speter		  {
348118334Speter		    putc ('-', asm_out_file);
348218334Speter		    output_addr_const (asm_out_file, operands[c]);
348318334Speter		  }
348418334Speter	      }
348518334Speter	    else
348618334Speter	      output_operand (operands[c], letter);
348718334Speter
348818334Speter	    while ((c = *p) >= '0' && c <= '9') p++;
348918334Speter	  }
349018334Speter	/* % followed by a digit outputs an operand the default way.  */
349118334Speter	else if (*p >= '0' && *p <= '9')
349218334Speter	  {
349318334Speter	    c = atoi (p);
349450503Sobrien	    if (this_is_asm_operands && (c < 0 || (unsigned int) c >= insn_noperands))
349518334Speter	      output_operand_lossage ("operand number out of range");
349618334Speter	    else
349718334Speter	      output_operand (operands[c], 0);
349818334Speter	    while ((c = *p) >= '0' && c <= '9') p++;
349918334Speter	  }
350018334Speter	/* % followed by punctuation: output something for that
350118334Speter	   punctuation character alone, with no operand.
350218334Speter	   The PRINT_OPERAND macro decides what is actually done.  */
350318334Speter#ifdef PRINT_OPERAND_PUNCT_VALID_P
350452515Sobrien	else if (PRINT_OPERAND_PUNCT_VALID_P ((unsigned char)*p))
350518334Speter	  output_operand (NULL_RTX, *p++);
350618334Speter#endif
350718334Speter	else
350818334Speter	  output_operand_lossage ("invalid %%-code");
350918334Speter	break;
351018334Speter
351118334Speter      default:
351218334Speter	putc (c, asm_out_file);
351318334Speter      }
351418334Speter
351518334Speter  output_asm_name ();
351618334Speter
351718334Speter  putc ('\n', asm_out_file);
351818334Speter}
351918334Speter
352018334Speter/* Output a LABEL_REF, or a bare CODE_LABEL, as an assembler symbol.  */
352118334Speter
352218334Spetervoid
352318334Speteroutput_asm_label (x)
352418334Speter     rtx x;
352518334Speter{
352618334Speter  char buf[256];
352718334Speter
352818334Speter  if (GET_CODE (x) == LABEL_REF)
352918334Speter    ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0)));
353018334Speter  else if (GET_CODE (x) == CODE_LABEL)
353118334Speter    ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
353218334Speter  else
353318334Speter    output_operand_lossage ("`%l' operand isn't a label");
353418334Speter
353518334Speter  assemble_name (asm_out_file, buf);
353618334Speter}
353718334Speter
353818334Speter/* Print operand X using machine-dependent assembler syntax.
353918334Speter   The macro PRINT_OPERAND is defined just to control this function.
354018334Speter   CODE is a non-digit that preceded the operand-number in the % spec,
354118334Speter   such as 'z' if the spec was `%z3'.  CODE is 0 if there was no char
354218334Speter   between the % and the digits.
354318334Speter   When CODE is a non-letter, X is 0.
354418334Speter
354518334Speter   The meanings of the letters are machine-dependent and controlled
354618334Speter   by PRINT_OPERAND.  */
354718334Speter
354818334Speterstatic void
354918334Speteroutput_operand (x, code)
355018334Speter     rtx x;
355118334Speter     int code;
355218334Speter{
355318334Speter  if (x && GET_CODE (x) == SUBREG)
355418334Speter    x = alter_subreg (x);
355518334Speter
355618334Speter  /* If X is a pseudo-register, abort now rather than writing trash to the
355718334Speter     assembler file.  */
355818334Speter
355918334Speter  if (x && GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER)
356018334Speter    abort ();
356118334Speter
356218334Speter  PRINT_OPERAND (asm_out_file, x, code);
356318334Speter}
356418334Speter
356518334Speter/* Print a memory reference operand for address X
356618334Speter   using machine-dependent assembler syntax.
356718334Speter   The macro PRINT_OPERAND_ADDRESS exists just to control this function.  */
356818334Speter
356918334Spetervoid
357018334Speteroutput_address (x)
357118334Speter     rtx x;
357218334Speter{
357318334Speter  walk_alter_subreg (x);
357418334Speter  PRINT_OPERAND_ADDRESS (asm_out_file, x);
357518334Speter}
357618334Speter
357718334Speter/* Print an integer constant expression in assembler syntax.
357818334Speter   Addition and subtraction are the only arithmetic
357918334Speter   that may appear in these expressions.  */
358018334Speter
358118334Spetervoid
358218334Speteroutput_addr_const (file, x)
358318334Speter     FILE *file;
358418334Speter     rtx x;
358518334Speter{
358618334Speter  char buf[256];
358718334Speter
358818334Speter restart:
358918334Speter  switch (GET_CODE (x))
359018334Speter    {
359118334Speter    case PC:
359218334Speter      if (flag_pic)
359318334Speter	putc ('.', file);
359418334Speter      else
359518334Speter	abort ();
359618334Speter      break;
359718334Speter
359818334Speter    case SYMBOL_REF:
359918334Speter      assemble_name (file, XSTR (x, 0));
360018334Speter      break;
360118334Speter
360218334Speter    case LABEL_REF:
360318334Speter      ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (x, 0)));
360418334Speter      assemble_name (file, buf);
360518334Speter      break;
360618334Speter
360718334Speter    case CODE_LABEL:
360818334Speter      ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
360918334Speter      assemble_name (file, buf);
361018334Speter      break;
361118334Speter
361218334Speter    case CONST_INT:
361350503Sobrien      fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
361418334Speter      break;
361518334Speter
361618334Speter    case CONST:
361718334Speter      /* This used to output parentheses around the expression,
361818334Speter	 but that does not work on the 386 (either ATT or BSD assembler).  */
361918334Speter      output_addr_const (file, XEXP (x, 0));
362018334Speter      break;
362118334Speter
362218334Speter    case CONST_DOUBLE:
362318334Speter      if (GET_MODE (x) == VOIDmode)
362418334Speter	{
362518334Speter	  /* We can use %d if the number is one word and positive.  */
362618334Speter	  if (CONST_DOUBLE_HIGH (x))
362750503Sobrien	    fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
362818334Speter		     CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x));
362918334Speter	  else if  (CONST_DOUBLE_LOW (x) < 0)
363050503Sobrien	    fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (x));
363118334Speter	  else
363250503Sobrien	    fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x));
363318334Speter	}
363418334Speter      else
363518334Speter	/* We can't handle floating point constants;
363618334Speter	   PRINT_OPERAND must handle them.  */
363718334Speter	output_operand_lossage ("floating constant misused");
363818334Speter      break;
363918334Speter
364018334Speter    case PLUS:
364118334Speter      /* Some assemblers need integer constants to appear last (eg masm).  */
364218334Speter      if (GET_CODE (XEXP (x, 0)) == CONST_INT)
364318334Speter	{
364418334Speter	  output_addr_const (file, XEXP (x, 1));
364518334Speter	  if (INTVAL (XEXP (x, 0)) >= 0)
364618334Speter	    fprintf (file, "+");
364718334Speter	  output_addr_const (file, XEXP (x, 0));
364818334Speter	}
364918334Speter      else
365018334Speter	{
365118334Speter	  output_addr_const (file, XEXP (x, 0));
365218334Speter	  if (INTVAL (XEXP (x, 1)) >= 0)
365318334Speter	    fprintf (file, "+");
365418334Speter	  output_addr_const (file, XEXP (x, 1));
365518334Speter	}
365618334Speter      break;
365718334Speter
365818334Speter    case MINUS:
365918334Speter      /* Avoid outputting things like x-x or x+5-x,
366018334Speter	 since some assemblers can't handle that.  */
366118334Speter      x = simplify_subtraction (x);
366218334Speter      if (GET_CODE (x) != MINUS)
366318334Speter	goto restart;
366418334Speter
366518334Speter      output_addr_const (file, XEXP (x, 0));
366618334Speter      fprintf (file, "-");
366718334Speter      if (GET_CODE (XEXP (x, 1)) == CONST_INT
366818334Speter	  && INTVAL (XEXP (x, 1)) < 0)
366918334Speter	{
367018334Speter	  fprintf (file, ASM_OPEN_PAREN);
367118334Speter	  output_addr_const (file, XEXP (x, 1));
367218334Speter	  fprintf (file, ASM_CLOSE_PAREN);
367318334Speter	}
367418334Speter      else
367518334Speter	output_addr_const (file, XEXP (x, 1));
367618334Speter      break;
367718334Speter
367818334Speter    case ZERO_EXTEND:
367918334Speter    case SIGN_EXTEND:
368018334Speter      output_addr_const (file, XEXP (x, 0));
368118334Speter      break;
368218334Speter
368318334Speter    default:
368418334Speter      output_operand_lossage ("invalid expression as operand");
368518334Speter    }
368618334Speter}
368718334Speter
368818334Speter/* A poor man's fprintf, with the added features of %I, %R, %L, and %U.
368918334Speter   %R prints the value of REGISTER_PREFIX.
369018334Speter   %L prints the value of LOCAL_LABEL_PREFIX.
369118334Speter   %U prints the value of USER_LABEL_PREFIX.
369218334Speter   %I prints the value of IMMEDIATE_PREFIX.
369318334Speter   %O runs ASM_OUTPUT_OPCODE to transform what follows in the string.
369418334Speter   Also supported are %d, %x, %s, %e, %f, %g and %%.
369518334Speter
369618334Speter   We handle alternate assembler dialects here, just like output_asm_insn.  */
369718334Speter
369818334Spetervoid
369952515Sobrienasm_fprintf VPROTO((FILE *file, const char *p, ...))
370018334Speter{
370152515Sobrien#ifndef ANSI_PROTOTYPES
370218334Speter  FILE *file;
370352515Sobrien  const char *p;
370418334Speter#endif
370518334Speter  va_list argptr;
370618334Speter  char buf[10];
370718334Speter  char *q, c;
370818334Speter
370918334Speter  VA_START (argptr, p);
371018334Speter
371152515Sobrien#ifndef ANSI_PROTOTYPES
371250503Sobrien  file = va_arg (argptr, FILE *);
371352515Sobrien  p = va_arg (argptr, const char *);
371418334Speter#endif
371518334Speter
371618334Speter  buf[0] = '%';
371718334Speter
371850503Sobrien  while ((c = *p++))
371918334Speter    switch (c)
372018334Speter      {
372118334Speter#ifdef ASSEMBLER_DIALECT
372218334Speter      case '{':
372350503Sobrien	{
372450503Sobrien	  int i;
372518334Speter
372650503Sobrien	  /* If we want the first dialect, do nothing.  Otherwise, skip
372750503Sobrien	     DIALECT_NUMBER of strings ending with '|'.  */
372850503Sobrien	  for (i = 0; i < dialect_number; i++)
372950503Sobrien	    {
373050503Sobrien	      while (*p && *p++ != '|')
373150503Sobrien		;
373250503Sobrien
373350503Sobrien	      if (*p == '|')
373450503Sobrien		p++;
373518334Speter	  }
373650503Sobrien	}
373718334Speter	break;
373818334Speter
373918334Speter      case '|':
374018334Speter	/* Skip to close brace.  */
374118334Speter	while (*p && *p++ != '}')
374218334Speter	  ;
374318334Speter	break;
374418334Speter
374518334Speter      case '}':
374618334Speter	break;
374718334Speter#endif
374818334Speter
374918334Speter      case '%':
375018334Speter	c = *p++;
375118334Speter	q = &buf[1];
375218334Speter	while ((c >= '0' && c <= '9') || c == '.')
375318334Speter	  {
375418334Speter	    *q++ = c;
375518334Speter	    c = *p++;
375618334Speter	  }
375718334Speter	switch (c)
375818334Speter	  {
375918334Speter	  case '%':
376018334Speter	    fprintf (file, "%%");
376118334Speter	    break;
376218334Speter
376318334Speter	  case 'd':  case 'i':  case 'u':
376418334Speter	  case 'x':  case 'p':  case 'X':
376518334Speter	  case 'o':
376618334Speter	    *q++ = c;
376718334Speter	    *q = 0;
376818334Speter	    fprintf (file, buf, va_arg (argptr, int));
376918334Speter	    break;
377018334Speter
377118334Speter	  case 'w':
377218334Speter	    /* This is a prefix to the 'd', 'i', 'u', 'x', 'p', and 'X' cases,
377318334Speter	       but we do not check for those cases.  It means that the value
377418334Speter	       is a HOST_WIDE_INT, which may be either `int' or `long'.  */
377518334Speter
377650503Sobrien#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
377750503Sobrien#else
377850503Sobrien#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
377918334Speter	    *q++ = 'l';
378050503Sobrien#else
378150503Sobrien	    *q++ = 'l';
378250503Sobrien	    *q++ = 'l';
378318334Speter#endif
378450503Sobrien#endif
378518334Speter
378618334Speter	    *q++ = *p++;
378718334Speter	    *q = 0;
378818334Speter	    fprintf (file, buf, va_arg (argptr, HOST_WIDE_INT));
378918334Speter	    break;
379018334Speter
379118334Speter	  case 'l':
379218334Speter	    *q++ = c;
379318334Speter	    *q++ = *p++;
379418334Speter	    *q = 0;
379518334Speter	    fprintf (file, buf, va_arg (argptr, long));
379618334Speter	    break;
379718334Speter
379818334Speter	  case 'e':
379918334Speter	  case 'f':
380018334Speter	  case 'g':
380118334Speter	    *q++ = c;
380218334Speter	    *q = 0;
380318334Speter	    fprintf (file, buf, va_arg (argptr, double));
380418334Speter	    break;
380518334Speter
380618334Speter	  case 's':
380718334Speter	    *q++ = c;
380818334Speter	    *q = 0;
380918334Speter	    fprintf (file, buf, va_arg (argptr, char *));
381018334Speter	    break;
381118334Speter
381218334Speter	  case 'O':
381318334Speter#ifdef ASM_OUTPUT_OPCODE
381418334Speter	    ASM_OUTPUT_OPCODE (asm_out_file, p);
381518334Speter#endif
381618334Speter	    break;
381718334Speter
381818334Speter	  case 'R':
381918334Speter#ifdef REGISTER_PREFIX
382018334Speter	    fprintf (file, "%s", REGISTER_PREFIX);
382118334Speter#endif
382218334Speter	    break;
382318334Speter
382418334Speter	  case 'I':
382518334Speter#ifdef IMMEDIATE_PREFIX
382618334Speter	    fprintf (file, "%s", IMMEDIATE_PREFIX);
382718334Speter#endif
382818334Speter	    break;
382918334Speter
383018334Speter	  case 'L':
383118334Speter#ifdef LOCAL_LABEL_PREFIX
383218334Speter	    fprintf (file, "%s", LOCAL_LABEL_PREFIX);
383318334Speter#endif
383418334Speter	    break;
383518334Speter
383618334Speter	  case 'U':
383752515Sobrien	    fputs (user_label_prefix, file);
383818334Speter	    break;
383918334Speter
384018334Speter	  default:
384118334Speter	    abort ();
384218334Speter	  }
384318334Speter	break;
384418334Speter
384518334Speter      default:
384618334Speter	fputc (c, file);
384718334Speter      }
384818334Speter}
384918334Speter
385018334Speter/* Split up a CONST_DOUBLE or integer constant rtx
385118334Speter   into two rtx's for single words,
385218334Speter   storing in *FIRST the word that comes first in memory in the target
385318334Speter   and in *SECOND the other.  */
385418334Speter
385518334Spetervoid
385618334Spetersplit_double (value, first, second)
385718334Speter     rtx value;
385818334Speter     rtx *first, *second;
385918334Speter{
386018334Speter  if (GET_CODE (value) == CONST_INT)
386118334Speter    {
386218334Speter      if (HOST_BITS_PER_WIDE_INT >= (2 * BITS_PER_WORD))
386318334Speter	{
386418334Speter	  /* In this case the CONST_INT holds both target words.
386550503Sobrien	     Extract the bits from it into two word-sized pieces.
386650503Sobrien	     Sign extend each half to HOST_WIDE_INT.  */
386718334Speter	  rtx low, high;
386850503Sobrien	  /* On machines where HOST_BITS_PER_WIDE_INT == BITS_PER_WORD
386950503Sobrien	     the shift below will cause a compiler warning, even though
387050503Sobrien	     this code won't be executed.  So put the shift amounts in
387150503Sobrien	     variables to avoid the warning.  */
387250503Sobrien	  int rshift = HOST_BITS_PER_WIDE_INT - BITS_PER_WORD;
387350503Sobrien	  int lshift = HOST_BITS_PER_WIDE_INT - 2 * BITS_PER_WORD;
387418334Speter
387550503Sobrien	  low = GEN_INT ((INTVAL (value) << rshift) >> rshift);
387650503Sobrien	  high = GEN_INT ((INTVAL (value) << lshift) >> rshift);
387718334Speter	  if (WORDS_BIG_ENDIAN)
387818334Speter	    {
387918334Speter	      *first = high;
388018334Speter	      *second = low;
388118334Speter	    }
388218334Speter	  else
388318334Speter	    {
388418334Speter	      *first = low;
388518334Speter	      *second = high;
388618334Speter	    }
388718334Speter	}
388818334Speter      else
388918334Speter	{
389018334Speter	  /* The rule for using CONST_INT for a wider mode
389118334Speter	     is that we regard the value as signed.
389218334Speter	     So sign-extend it.  */
389318334Speter	  rtx high = (INTVAL (value) < 0 ? constm1_rtx : const0_rtx);
389418334Speter	  if (WORDS_BIG_ENDIAN)
389518334Speter	    {
389618334Speter	      *first = high;
389718334Speter	      *second = value;
389818334Speter	    }
389918334Speter	  else
390018334Speter	    {
390118334Speter	      *first = value;
390218334Speter	      *second = high;
390318334Speter	    }
390418334Speter	}
390518334Speter    }
390618334Speter  else if (GET_CODE (value) != CONST_DOUBLE)
390718334Speter    {
390818334Speter      if (WORDS_BIG_ENDIAN)
390918334Speter	{
391018334Speter	  *first = const0_rtx;
391118334Speter	  *second = value;
391218334Speter	}
391318334Speter      else
391418334Speter	{
391518334Speter	  *first = value;
391618334Speter	  *second = const0_rtx;
391718334Speter	}
391818334Speter    }
391918334Speter  else if (GET_MODE (value) == VOIDmode
392018334Speter	   /* This is the old way we did CONST_DOUBLE integers.  */
392118334Speter	   || GET_MODE_CLASS (GET_MODE (value)) == MODE_INT)
392218334Speter    {
392318334Speter      /* In an integer, the words are defined as most and least significant.
392418334Speter	 So order them by the target's convention.  */
392518334Speter      if (WORDS_BIG_ENDIAN)
392618334Speter	{
392718334Speter	  *first = GEN_INT (CONST_DOUBLE_HIGH (value));
392818334Speter	  *second = GEN_INT (CONST_DOUBLE_LOW (value));
392918334Speter	}
393018334Speter      else
393118334Speter	{
393218334Speter	  *first = GEN_INT (CONST_DOUBLE_LOW (value));
393318334Speter	  *second = GEN_INT (CONST_DOUBLE_HIGH (value));
393418334Speter	}
393518334Speter    }
393618334Speter  else
393718334Speter    {
393818334Speter#ifdef REAL_ARITHMETIC
393918334Speter      REAL_VALUE_TYPE r; long l[2];
394018334Speter      REAL_VALUE_FROM_CONST_DOUBLE (r, value);
394118334Speter
394218334Speter      /* Note, this converts the REAL_VALUE_TYPE to the target's
394318334Speter	 format, splits up the floating point double and outputs
394418334Speter	 exactly 32 bits of it into each of l[0] and l[1] --
394550503Sobrien	 not necessarily BITS_PER_WORD bits.  */
394618334Speter      REAL_VALUE_TO_TARGET_DOUBLE (r, l);
394718334Speter
394852515Sobrien      /* If 32 bits is an entire word for the target, but not for the host,
394952515Sobrien	 then sign-extend on the host so that the number will look the same
395052515Sobrien	 way on the host that it would on the target.  See for instance
395152515Sobrien	 simplify_unary_operation.  The #if is needed to avoid compiler
395252515Sobrien	 warnings.  */
395352515Sobrien
395452515Sobrien#if HOST_BITS_PER_LONG > 32
395552515Sobrien      if (BITS_PER_WORD < HOST_BITS_PER_LONG && BITS_PER_WORD == 32)
395652515Sobrien	{
395752515Sobrien	  if (l[0] & ((long) 1 << 31))
395852515Sobrien	    l[0] |= ((long) (-1) << 32);
395952515Sobrien	  if (l[1] & ((long) 1 << 31))
396052515Sobrien	    l[1] |= ((long) (-1) << 32);
396152515Sobrien	}
396252515Sobrien#endif
396352515Sobrien
396418334Speter      *first = GEN_INT ((HOST_WIDE_INT) l[0]);
396518334Speter      *second = GEN_INT ((HOST_WIDE_INT) l[1]);
396618334Speter#else
396718334Speter      if ((HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
396818334Speter	   || HOST_BITS_PER_WIDE_INT != BITS_PER_WORD)
396918334Speter	  && ! flag_pretend_float)
397018334Speter      abort ();
397118334Speter
397218334Speter      if (
397318334Speter#ifdef HOST_WORDS_BIG_ENDIAN
397418334Speter	  WORDS_BIG_ENDIAN
397518334Speter#else
397618334Speter	  ! WORDS_BIG_ENDIAN
397718334Speter#endif
397818334Speter	  )
397918334Speter	{
398018334Speter	  /* Host and target agree => no need to swap.  */
398118334Speter	  *first = GEN_INT (CONST_DOUBLE_LOW (value));
398218334Speter	  *second = GEN_INT (CONST_DOUBLE_HIGH (value));
398318334Speter	}
398418334Speter      else
398518334Speter	{
398618334Speter	  *second = GEN_INT (CONST_DOUBLE_LOW (value));
398718334Speter	  *first = GEN_INT (CONST_DOUBLE_HIGH (value));
398818334Speter	}
398918334Speter#endif /* no REAL_ARITHMETIC */
399018334Speter    }
399118334Speter}
399218334Speter
399318334Speter/* Return nonzero if this function has no function calls.  */
399418334Speter
399518334Speterint
399618334Speterleaf_function_p ()
399718334Speter{
399818334Speter  rtx insn;
399918334Speter
400050503Sobrien  if (profile_flag || profile_block_flag || profile_arc_flag)
400118334Speter    return 0;
400218334Speter
400318334Speter  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
400418334Speter    {
400518334Speter      if (GET_CODE (insn) == CALL_INSN)
400618334Speter	return 0;
400718334Speter      if (GET_CODE (insn) == INSN
400818334Speter	  && GET_CODE (PATTERN (insn)) == SEQUENCE
400918334Speter	  && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN)
401018334Speter	return 0;
401118334Speter    }
401218334Speter  for (insn = current_function_epilogue_delay_list; insn; insn = XEXP (insn, 1))
401318334Speter    {
401418334Speter      if (GET_CODE (XEXP (insn, 0)) == CALL_INSN)
401518334Speter	return 0;
401618334Speter      if (GET_CODE (XEXP (insn, 0)) == INSN
401718334Speter	  && GET_CODE (PATTERN (XEXP (insn, 0))) == SEQUENCE
401818334Speter	  && GET_CODE (XVECEXP (PATTERN (XEXP (insn, 0)), 0, 0)) == CALL_INSN)
401918334Speter	return 0;
402018334Speter    }
402118334Speter
402218334Speter  return 1;
402318334Speter}
402418334Speter
402518334Speter/* On some machines, a function with no call insns
402618334Speter   can run faster if it doesn't create its own register window.
402718334Speter   When output, the leaf function should use only the "output"
402818334Speter   registers.  Ordinarily, the function would be compiled to use
402918334Speter   the "input" registers to find its arguments; it is a candidate
403018334Speter   for leaf treatment if it uses only the "input" registers.
403118334Speter   Leaf function treatment means renumbering so the function
403218334Speter   uses the "output" registers instead.  */
403318334Speter
403418334Speter#ifdef LEAF_REGISTERS
403518334Speter
403618334Speterstatic char permitted_reg_in_leaf_functions[] = LEAF_REGISTERS;
403718334Speter
403818334Speter/* Return 1 if this function uses only the registers that can be
403918334Speter   safely renumbered.  */
404018334Speter
404118334Speterint
404218334Speteronly_leaf_regs_used ()
404318334Speter{
404418334Speter  int i;
404518334Speter
404618334Speter  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
404750503Sobrien    if ((regs_ever_live[i] || global_regs[i])
404850503Sobrien	&& ! permitted_reg_in_leaf_functions[i])
404950503Sobrien      return 0;
405050503Sobrien
405150503Sobrien  if (current_function_uses_pic_offset_table
405250503Sobrien      && pic_offset_table_rtx != 0
405350503Sobrien      && GET_CODE (pic_offset_table_rtx) == REG
405450503Sobrien      && ! permitted_reg_in_leaf_functions[REGNO (pic_offset_table_rtx)])
405550503Sobrien    return 0;
405650503Sobrien
405718334Speter  return 1;
405818334Speter}
405918334Speter
406018334Speter/* Scan all instructions and renumber all registers into those
406118334Speter   available in leaf functions.  */
406218334Speter
406318334Speterstatic void
406418334Speterleaf_renumber_regs (first)
406518334Speter     rtx first;
406618334Speter{
406718334Speter  rtx insn;
406818334Speter
406918334Speter  /* Renumber only the actual patterns.
407018334Speter     The reg-notes can contain frame pointer refs,
407118334Speter     and renumbering them could crash, and should not be needed.  */
407218334Speter  for (insn = first; insn; insn = NEXT_INSN (insn))
407318334Speter    if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
407418334Speter      leaf_renumber_regs_insn (PATTERN (insn));
407518334Speter  for (insn = current_function_epilogue_delay_list; insn; insn = XEXP (insn, 1))
407618334Speter    if (GET_RTX_CLASS (GET_CODE (XEXP (insn, 0))) == 'i')
407718334Speter      leaf_renumber_regs_insn (PATTERN (XEXP (insn, 0)));
407818334Speter}
407918334Speter
408018334Speter/* Scan IN_RTX and its subexpressions, and renumber all regs into those
408118334Speter   available in leaf functions.  */
408218334Speter
408318334Spetervoid
408418334Speterleaf_renumber_regs_insn (in_rtx)
408518334Speter     register rtx in_rtx;
408618334Speter{
408718334Speter  register int i, j;
408818334Speter  register char *format_ptr;
408918334Speter
409018334Speter  if (in_rtx == 0)
409118334Speter    return;
409218334Speter
409318334Speter  /* Renumber all input-registers into output-registers.
409418334Speter     renumbered_regs would be 1 for an output-register;
409518334Speter     they  */
409618334Speter
409718334Speter  if (GET_CODE (in_rtx) == REG)
409818334Speter    {
409918334Speter      int newreg;
410018334Speter
410118334Speter      /* Don't renumber the same reg twice.  */
410218334Speter      if (in_rtx->used)
410318334Speter	return;
410418334Speter
410518334Speter      newreg = REGNO (in_rtx);
410618334Speter      /* Don't try to renumber pseudo regs.  It is possible for a pseudo reg
410718334Speter	 to reach here as part of a REG_NOTE.  */
410818334Speter      if (newreg >= FIRST_PSEUDO_REGISTER)
410918334Speter	{
411018334Speter	  in_rtx->used = 1;
411118334Speter	  return;
411218334Speter	}
411318334Speter      newreg = LEAF_REG_REMAP (newreg);
411418334Speter      if (newreg < 0)
411518334Speter	abort ();
411618334Speter      regs_ever_live[REGNO (in_rtx)] = 0;
411718334Speter      regs_ever_live[newreg] = 1;
411818334Speter      REGNO (in_rtx) = newreg;
411918334Speter      in_rtx->used = 1;
412018334Speter    }
412118334Speter
412218334Speter  if (GET_RTX_CLASS (GET_CODE (in_rtx)) == 'i')
412318334Speter    {
412418334Speter      /* Inside a SEQUENCE, we find insns.
412518334Speter	 Renumber just the patterns of these insns,
412618334Speter	 just as we do for the top-level insns.  */
412718334Speter      leaf_renumber_regs_insn (PATTERN (in_rtx));
412818334Speter      return;
412918334Speter    }
413018334Speter
413118334Speter  format_ptr = GET_RTX_FORMAT (GET_CODE (in_rtx));
413218334Speter
413318334Speter  for (i = 0; i < GET_RTX_LENGTH (GET_CODE (in_rtx)); i++)
413418334Speter    switch (*format_ptr++)
413518334Speter      {
413618334Speter      case 'e':
413718334Speter	leaf_renumber_regs_insn (XEXP (in_rtx, i));
413818334Speter	break;
413918334Speter
414018334Speter      case 'E':
414118334Speter	if (NULL != XVEC (in_rtx, i))
414218334Speter	  {
414318334Speter	    for (j = 0; j < XVECLEN (in_rtx, i); j++)
414418334Speter	      leaf_renumber_regs_insn (XVECEXP (in_rtx, i, j));
414518334Speter	  }
414618334Speter	break;
414718334Speter
414818334Speter      case 'S':
414918334Speter      case 's':
415018334Speter      case '0':
415118334Speter      case 'i':
415218334Speter      case 'w':
415318334Speter      case 'n':
415418334Speter      case 'u':
415518334Speter	break;
415618334Speter
415718334Speter      default:
415818334Speter	abort ();
415918334Speter      }
416018334Speter}
416118334Speter#endif
4162