final.c revision 96281
118334Speter/* Convert RTL to assembler code and output it, for GNU compiler.
290087Sobrien   Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
390087Sobrien   1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
418334Speter
590087SobrienThis file is part of GCC.
618334Speter
790087SobrienGCC is free software; you can redistribute it and/or modify it under
890087Sobrienthe terms of the GNU General Public License as published by the Free
990087SobrienSoftware Foundation; either version 2, or (at your option) any later
1090087Sobrienversion.
1118334Speter
1290087SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY
1390087SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or
1490087SobrienFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1590087Sobrienfor more details.
1618334Speter
1718334SpeterYou should have received a copy of the GNU General Public License
1890087Sobrienalong with GCC; see the file COPYING.  If not, write to the Free
1990087SobrienSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA
2090087Sobrien02111-1307, USA.  */
2118334Speter
2252515Sobrien/* $FreeBSD: head/contrib/gcc/final.c 96281 2002-05-09 21:41:12Z obrien $ */
2318334Speter
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
4690087Sobrien   directly in assembler by the target functions function_prologue and
4790087Sobrien   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"
5490087Sobrien#include "tm_p.h"
5518334Speter#include "regs.h"
5618334Speter#include "insn-config.h"
5718334Speter#include "insn-attr.h"
5818334Speter#include "recog.h"
5918334Speter#include "conditions.h"
6018334Speter#include "flags.h"
6118334Speter#include "real.h"
6218334Speter#include "hard-reg-set.h"
6318334Speter#include "output.h"
6450503Sobrien#include "except.h"
6590087Sobrien#include "function.h"
6650503Sobrien#include "toplev.h"
6750503Sobrien#include "reload.h"
6852515Sobrien#include "intl.h"
6990087Sobrien#include "basic-block.h"
7090087Sobrien#include "target.h"
7190087Sobrien#include "debug.h"
7290087Sobrien#include "expr.h"
7318334Speter
7418334Speter#ifdef XCOFF_DEBUGGING_INFO
7590087Sobrien#include "xcoffout.h"		/* Needed for external data
7690087Sobrien				   declarations for e.g. AIX 4.x.  */
7718334Speter#endif
7818334Speter
7950503Sobrien#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
8050503Sobrien#include "dwarf2out.h"
8150503Sobrien#endif
8250503Sobrien
8318334Speter/* If we aren't using cc0, CC_STATUS_INIT shouldn't exist.  So define a
8418334Speter   null default for it to save conditionalization later.  */
8518334Speter#ifndef CC_STATUS_INIT
8618334Speter#define CC_STATUS_INIT
8718334Speter#endif
8818334Speter
8918334Speter/* How to start an assembler comment.  */
9018334Speter#ifndef ASM_COMMENT_START
9118334Speter#define ASM_COMMENT_START ";#"
9218334Speter#endif
9318334Speter
9418334Speter/* Is the given character a logical line separator for the assembler?  */
9518334Speter#ifndef IS_ASM_LOGICAL_LINE_SEPARATOR
9618334Speter#define IS_ASM_LOGICAL_LINE_SEPARATOR(C) ((C) == ';')
9718334Speter#endif
9818334Speter
9950503Sobrien#ifndef JUMP_TABLES_IN_TEXT_SECTION
10050503Sobrien#define JUMP_TABLES_IN_TEXT_SECTION 0
10150503Sobrien#endif
10250503Sobrien
10318334Speter/* Last insn processed by final_scan_insn.  */
10490087Sobrienstatic rtx debug_insn;
10590087Sobrienrtx current_output_insn;
10618334Speter
10718334Speter/* Line number of last NOTE.  */
10818334Speterstatic int last_linenum;
10918334Speter
11018334Speter/* Highest line number in current block.  */
11118334Speterstatic int high_block_linenum;
11218334Speter
11318334Speter/* Likewise for function.  */
11418334Speterstatic int high_function_linenum;
11518334Speter
11618334Speter/* Filename of last NOTE.  */
11790087Sobrienstatic const char *last_filename;
11818334Speter
11950503Sobrien/* Number of instrumented arcs when profile_arc_flag is set.  */
12090087Sobrienextern int count_instrumented_edges;
12150503Sobrien
12250503Sobrienextern int length_unit_log; /* This is defined in insn-attrtab.c.  */
12350503Sobrien
12418334Speter/* Nonzero while outputting an `asm' with operands.
12518334Speter   This means that inconsistencies are the user's fault, so don't abort.
12618334Speter   The precise value is the insn being output, to pass to error_for_asm.  */
12718334Speterstatic rtx this_is_asm_operands;
12818334Speter
12918334Speter/* Number of operands of this insn, for an `asm' with operands.  */
13050503Sobrienstatic unsigned int insn_noperands;
13118334Speter
13218334Speter/* Compare optimization flag.  */
13318334Speter
13418334Speterstatic rtx last_ignored_compare = 0;
13518334Speter
13618334Speter/* Flag indicating this insn is the start of a new basic block.  */
13718334Speter
13818334Speterstatic int new_block = 1;
13918334Speter
14018334Speter/* Assign a unique number to each insn that is output.
14118334Speter   This can be used to generate unique local labels.  */
14218334Speter
14318334Speterstatic int insn_counter = 0;
14418334Speter
14518334Speter#ifdef HAVE_cc0
14618334Speter/* This variable contains machine-dependent flags (defined in tm.h)
14718334Speter   set and examined by output routines
14818334Speter   that describe how to interpret the condition codes properly.  */
14918334Speter
15018334SpeterCC_STATUS cc_status;
15118334Speter
15218334Speter/* During output of an insn, this contains a copy of cc_status
15318334Speter   from before the insn.  */
15418334Speter
15518334SpeterCC_STATUS cc_prev_status;
15618334Speter#endif
15718334Speter
15818334Speter/* Indexed by hardware reg number, is 1 if that register is ever
15918334Speter   used in the current function.
16018334Speter
16118334Speter   In life_analysis, or in stupid_life_analysis, this is set
16218334Speter   up to record the hard regs used explicitly.  Reload adds
16318334Speter   in the hard regs used for holding pseudo regs.  Final uses
16418334Speter   it to generate the code in the function prologue and epilogue
16518334Speter   to save and restore registers as needed.  */
16618334Speter
16718334Speterchar regs_ever_live[FIRST_PSEUDO_REGISTER];
16818334Speter
16918334Speter/* Nonzero means current function must be given a frame pointer.
17018334Speter   Set in stmt.c if anything is allocated on the stack there.
17118334Speter   Set in reload1.c if anything is allocated on the stack there.  */
17218334Speter
17318334Speterint frame_pointer_needed;
17418334Speter
17590087Sobrien/* Number of unmatched NOTE_INSN_BLOCK_BEG notes we have seen.  */
17618334Speter
17718334Speterstatic int block_depth;
17818334Speter
17918334Speter/* Nonzero if have enabled APP processing of our assembler output.  */
18018334Speter
18118334Speterstatic int app_on;
18218334Speter
18318334Speter/* If we are outputting an insn sequence, this contains the sequence rtx.
18418334Speter   Zero otherwise.  */
18518334Speter
18618334Speterrtx final_sequence;
18718334Speter
18818334Speter#ifdef ASSEMBLER_DIALECT
18918334Speter
19018334Speter/* Number of the assembler dialect to use, starting at 0.  */
19118334Speterstatic int dialect_number;
19218334Speter#endif
19318334Speter
19418334Speter/* Indexed by line number, nonzero if there is a note for that line.  */
19518334Speter
19618334Speterstatic char *line_note_exists;
19718334Speter
19890087Sobrien#ifdef HAVE_conditional_execution
19990087Sobrien/* Nonnull if the insn currently being emitted was a COND_EXEC pattern.  */
20090087Sobrienrtx current_insn_predicate;
20190087Sobrien#endif
20218334Speter
20350503Sobrien#ifdef HAVE_ATTR_length
20490087Sobrienstatic int asm_insn_count	PARAMS ((rtx));
20550503Sobrien#endif
20690087Sobrienstatic void profile_function	PARAMS ((FILE *));
20790087Sobrienstatic void profile_after_prologue PARAMS ((FILE *));
20890087Sobrienstatic void notice_source_line	PARAMS ((rtx));
20990087Sobrienstatic rtx walk_alter_subreg	PARAMS ((rtx *));
21090087Sobrienstatic void output_asm_name	PARAMS ((void));
21190087Sobrienstatic tree get_mem_expr_from_op	PARAMS ((rtx, int *));
21290087Sobrienstatic void output_asm_operand_names PARAMS ((rtx *, int *, int));
21390087Sobrienstatic void output_operand	PARAMS ((rtx, int));
21450503Sobrien#ifdef LEAF_REGISTERS
21590087Sobrienstatic void leaf_renumber_regs	PARAMS ((rtx));
21650503Sobrien#endif
21750503Sobrien#ifdef HAVE_cc0
21890087Sobrienstatic int alter_cond		PARAMS ((rtx));
21950503Sobrien#endif
22090087Sobrien#ifndef ADDR_VEC_ALIGN
22190087Sobrienstatic int final_addr_vec_align PARAMS ((rtx));
22290087Sobrien#endif
22390087Sobrien#ifdef HAVE_ATTR_length
22490087Sobrienstatic int align_fuzz		PARAMS ((rtx, rtx, int, unsigned));
22590087Sobrien#endif
22618334Speter
22718334Speter/* Initialize data in final at the beginning of a compilation.  */
22818334Speter
22918334Spetervoid
23018334Speterinit_final (filename)
23190087Sobrien     const char *filename ATTRIBUTE_UNUSED;
23218334Speter{
23318334Speter  app_on = 0;
23418334Speter  final_sequence = 0;
23518334Speter
23618334Speter#ifdef ASSEMBLER_DIALECT
23718334Speter  dialect_number = ASSEMBLER_DIALECT;
23818334Speter#endif
23918334Speter}
24018334Speter
24118334Speter/* Called at end of source file,
24218334Speter   to output the block-profiling table for this entire compilation.  */
24318334Speter
24418334Spetervoid
24518334Speterend_final (filename)
24690087Sobrien     const char *filename;
24718334Speter{
24890087Sobrien  if (profile_arc_flag)
24918334Speter    {
25018334Speter      char name[20];
25118334Speter      int align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
25250503Sobrien      int size, rounded;
25350503Sobrien      int long_bytes = LONG_TYPE_SIZE / BITS_PER_UNIT;
25490087Sobrien      int gcov_type_bytes = GCOV_TYPE_SIZE / BITS_PER_UNIT;
25550503Sobrien      int pointer_bytes = POINTER_SIZE / BITS_PER_UNIT;
25690087Sobrien      unsigned int align2 = LONG_TYPE_SIZE;
25718334Speter
25890087Sobrien      size = gcov_type_bytes * count_instrumented_edges;
25950503Sobrien      rounded = size;
26050503Sobrien
26118334Speter      rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;
26218334Speter      rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
26318334Speter		 * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
26418334Speter
26590087Sobrien      /* ??? This _really_ ought to be done with a structure layout
26690087Sobrien	 and with assemble_constructor.  If long_bytes != pointer_bytes
26790087Sobrien	 we'll be emitting unaligned data at some point.  */
26890087Sobrien      if (long_bytes != pointer_bytes)
26990087Sobrien	abort ();
27090087Sobrien
27118334Speter      data_section ();
27218334Speter
27350503Sobrien      /* Output the main header, of 11 words:
27450503Sobrien	 0:  1 if this file is initialized, else 0.
27518334Speter	 1:  address of file name (LPBX1).
27618334Speter	 2:  address of table of counts (LPBX2).
27718334Speter	 3:  number of counts in the table.
27818334Speter	 4:  always 0, for compatibility with Sun.
27918334Speter
28018334Speter         The following are GNU extensions:
28118334Speter
28218334Speter	 5:  address of table of start addrs of basic blocks (LPBX3).
28318334Speter	 6:  Number of bytes in this header.
28418334Speter	 7:  address of table of function names (LPBX4).
28518334Speter	 8:  address of table of line numbers (LPBX5) or 0.
28650503Sobrien	 9:  address of table of file names (LPBX6) or 0.
28750503Sobrien	10:  space reserved for basic block profiling.  */
28818334Speter
28918334Speter      ASM_OUTPUT_ALIGN (asm_out_file, align);
29018334Speter
29118334Speter      ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 0);
29218334Speter
29390087Sobrien      /* Zero word.  */
29490087Sobrien      assemble_integer (const0_rtx, long_bytes, align2, 1);
29590087Sobrien
29690087Sobrien      /* Address of filename.  */
29718334Speter      ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 1);
29890087Sobrien      assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes,
29990087Sobrien			align2, 1);
30018334Speter
30190087Sobrien      /* Address of count table.  */
30218334Speter      ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2);
30390087Sobrien      assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes,
30490087Sobrien			align2, 1);
30518334Speter
30690087Sobrien      /* Count of the # of instrumented arcs.  */
30790087Sobrien      assemble_integer (GEN_INT (count_instrumented_edges),
30890087Sobrien			long_bytes, align2, 1);
30918334Speter
31090087Sobrien      /* Zero word (link field).  */
31190087Sobrien      assemble_integer (const0_rtx, pointer_bytes, align2, 1);
31218334Speter
31390087Sobrien      assemble_integer (const0_rtx, pointer_bytes, align2, 1);
31418334Speter
31590087Sobrien      /* Byte count for extended structure.  */
31690087Sobrien      assemble_integer (GEN_INT (11 * UNITS_PER_WORD), long_bytes, align2, 1);
31718334Speter
31890087Sobrien      /* Address of function name table.  */
31990087Sobrien      assemble_integer (const0_rtx, pointer_bytes, align2, 1);
32018334Speter
32190087Sobrien      /* Address of line number and filename tables if debugging.  */
32290087Sobrien      assemble_integer (const0_rtx, pointer_bytes, align2, 1);
32390087Sobrien      assemble_integer (const0_rtx, pointer_bytes, align2, 1);
32418334Speter
32590087Sobrien      /* Space for extension ptr (link field).  */
32690087Sobrien      assemble_integer (const0_rtx, UNITS_PER_WORD, align2, 1);
32750503Sobrien
32890087Sobrien      /* Output the file name changing the suffix to .d for
32990087Sobrien	 Sun tcov compatibility.  */
33018334Speter      ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 1);
33118334Speter      {
33218334Speter	char *cwd = getpwd ();
33318334Speter	int len = strlen (filename) + strlen (cwd) + 1;
33418334Speter	char *data_file = (char *) alloca (len + 4);
33518334Speter
33618334Speter	strcpy (data_file, cwd);
33718334Speter	strcat (data_file, "/");
33818334Speter	strcat (data_file, filename);
33918334Speter	strip_off_ending (data_file, len);
34090087Sobrien	strcat (data_file, ".da");
34118334Speter	assemble_string (data_file, strlen (data_file) + 1);
34218334Speter      }
34318334Speter
34418334Speter      /* Make space for the table of counts.  */
34550503Sobrien      if (size == 0)
34618334Speter	{
34718334Speter	  /* Realign data section.  */
34818334Speter	  ASM_OUTPUT_ALIGN (asm_out_file, align);
34918334Speter	  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 2);
35018334Speter	  if (size != 0)
35118334Speter	    assemble_zeros (size);
35218334Speter	}
35318334Speter      else
35418334Speter	{
35518334Speter	  ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2);
35618334Speter#ifdef ASM_OUTPUT_SHARED_LOCAL
35718334Speter	  if (flag_shared_data)
35818334Speter	    ASM_OUTPUT_SHARED_LOCAL (asm_out_file, name, size, rounded);
35918334Speter	  else
36018334Speter#endif
36150503Sobrien#ifdef ASM_OUTPUT_ALIGNED_DECL_LOCAL
36290087Sobrien	    ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, NULL_TREE, name,
36390087Sobrien					   size, BIGGEST_ALIGNMENT);
36450503Sobrien#else
36518334Speter#ifdef ASM_OUTPUT_ALIGNED_LOCAL
36618334Speter	    ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size,
36718334Speter				      BIGGEST_ALIGNMENT);
36818334Speter#else
36918334Speter	    ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
37018334Speter#endif
37150503Sobrien#endif
37218334Speter	}
37390087Sobrien    }
37490087Sobrien}
37518334Speter
37690087Sobrien/* Default target function prologue and epilogue assembler output.
37718334Speter
37890087Sobrien   If not overridden for epilogue code, then the function body itself
37990087Sobrien   contains return instructions wherever needed.  */
38090087Sobrienvoid
38190087Sobriendefault_function_pro_epilogue (file, size)
38290087Sobrien     FILE *file ATTRIBUTE_UNUSED;
38390087Sobrien     HOST_WIDE_INT size ATTRIBUTE_UNUSED;
38490087Sobrien{
38590087Sobrien}
38618334Speter
38790087Sobrien/* Default target hook that outputs nothing to a stream.  */
38890087Sobrienvoid
38990087Sobrienno_asm_to_stream (file)
39090087Sobrien     FILE *file ATTRIBUTE_UNUSED;
39190087Sobrien{
39218334Speter}
39318334Speter
39418334Speter/* Enable APP processing of subsequent output.
39518334Speter   Used before the output from an `asm' statement.  */
39618334Speter
39718334Spetervoid
39818334Speterapp_enable ()
39918334Speter{
40018334Speter  if (! app_on)
40118334Speter    {
40250503Sobrien      fputs (ASM_APP_ON, asm_out_file);
40318334Speter      app_on = 1;
40418334Speter    }
40518334Speter}
40618334Speter
40718334Speter/* Disable APP processing of subsequent output.
40818334Speter   Called from varasm.c before most kinds of output.  */
40918334Speter
41018334Spetervoid
41118334Speterapp_disable ()
41218334Speter{
41318334Speter  if (app_on)
41418334Speter    {
41550503Sobrien      fputs (ASM_APP_OFF, asm_out_file);
41618334Speter      app_on = 0;
41718334Speter    }
41818334Speter}
41918334Speter
42090087Sobrien/* Return the number of slots filled in the current
42118334Speter   delayed branch sequence (we don't count the insn needing the
42218334Speter   delay slot).   Zero if not in a delayed branch sequence.  */
42318334Speter
42418334Speter#ifdef DELAY_SLOTS
42518334Speterint
42618334Speterdbr_sequence_length ()
42718334Speter{
42818334Speter  if (final_sequence != 0)
42918334Speter    return XVECLEN (final_sequence, 0) - 1;
43018334Speter  else
43118334Speter    return 0;
43218334Speter}
43318334Speter#endif
43418334Speter
43518334Speter/* The next two pages contain routines used to compute the length of an insn
43618334Speter   and to shorten branches.  */
43718334Speter
43818334Speter/* Arrays for insn lengths, and addresses.  The latter is referenced by
43918334Speter   `insn_current_length'.  */
44018334Speter
44190087Sobrienstatic int *insn_lengths;
44218334Speter
44390087Sobrien#ifdef HAVE_ATTR_length
44490087Sobrienvarray_type insn_addresses_;
44590087Sobrien#endif
44690087Sobrien
44752515Sobrien/* Max uid for which the above arrays are valid.  */
44852515Sobrienstatic int insn_lengths_max_uid;
44952515Sobrien
45018334Speter/* Address of insn being processed.  Used by `insn_current_length'.  */
45118334Speterint insn_current_address;
45218334Speter
45350503Sobrien/* Address of insn being processed in previous iteration.  */
45450503Sobrienint insn_last_address;
45550503Sobrien
45690087Sobrien/* known invariant alignment of insn being processed.  */
45750503Sobrienint insn_current_align;
45850503Sobrien
45950503Sobrien/* After shorten_branches, for any insn, uid_align[INSN_UID (insn)]
46050503Sobrien   gives the next following alignment insn that increases the known
46150503Sobrien   alignment, or NULL_RTX if there is no such insn.
46250503Sobrien   For any alignment obtained this way, we can again index uid_align with
46350503Sobrien   its uid to obtain the next following align that in turn increases the
46450503Sobrien   alignment, till we reach NULL_RTX; the sequence obtained this way
46550503Sobrien   for each insn we'll call the alignment chain of this insn in the following
46650503Sobrien   comments.  */
46750503Sobrien
46890087Sobrienstruct label_alignment
46990087Sobrien{
47050503Sobrien  short alignment;
47150503Sobrien  short max_skip;
47250503Sobrien};
47350503Sobrien
47450503Sobrienstatic rtx *uid_align;
47550503Sobrienstatic int *uid_shuid;
47650503Sobrienstatic struct label_alignment *label_align;
47750503Sobrien
47818334Speter/* Indicate that branch shortening hasn't yet been done.  */
47918334Speter
48018334Spetervoid
48118334Speterinit_insn_lengths ()
48218334Speter{
48350503Sobrien  if (uid_shuid)
48450503Sobrien    {
48550503Sobrien      free (uid_shuid);
48650503Sobrien      uid_shuid = 0;
48750503Sobrien    }
48850503Sobrien  if (insn_lengths)
48950503Sobrien    {
49050503Sobrien      free (insn_lengths);
49150503Sobrien      insn_lengths = 0;
49252515Sobrien      insn_lengths_max_uid = 0;
49350503Sobrien    }
49490087Sobrien#ifdef HAVE_ATTR_length
49590087Sobrien  INSN_ADDRESSES_FREE ();
49690087Sobrien#endif
49750503Sobrien  if (uid_align)
49850503Sobrien    {
49950503Sobrien      free (uid_align);
50050503Sobrien      uid_align = 0;
50150503Sobrien    }
50218334Speter}
50318334Speter
50418334Speter/* Obtain the current length of an insn.  If branch shortening has been done,
50518334Speter   get its actual length.  Otherwise, get its maximum length.  */
50618334Speter
50718334Speterint
50818334Speterget_attr_length (insn)
50990087Sobrien     rtx insn ATTRIBUTE_UNUSED;
51018334Speter{
51118334Speter#ifdef HAVE_ATTR_length
51218334Speter  rtx body;
51318334Speter  int i;
51418334Speter  int length = 0;
51518334Speter
51652515Sobrien  if (insn_lengths_max_uid > INSN_UID (insn))
51718334Speter    return insn_lengths[INSN_UID (insn)];
51818334Speter  else
51918334Speter    switch (GET_CODE (insn))
52018334Speter      {
52118334Speter      case NOTE:
52218334Speter      case BARRIER:
52318334Speter      case CODE_LABEL:
52418334Speter	return 0;
52518334Speter
52618334Speter      case CALL_INSN:
52718334Speter	length = insn_default_length (insn);
52818334Speter	break;
52918334Speter
53018334Speter      case JUMP_INSN:
53118334Speter	body = PATTERN (insn);
53218334Speter        if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
53318334Speter	  {
53450503Sobrien	    /* Alignment is machine-dependent and should be handled by
53550503Sobrien	       ADDR_VEC_ALIGN.  */
53618334Speter	  }
53718334Speter	else
53818334Speter	  length = insn_default_length (insn);
53918334Speter	break;
54018334Speter
54118334Speter      case INSN:
54218334Speter	body = PATTERN (insn);
54318334Speter	if (GET_CODE (body) == USE || GET_CODE (body) == CLOBBER)
54418334Speter	  return 0;
54518334Speter
54618334Speter	else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0)
54718334Speter	  length = asm_insn_count (body) * insn_default_length (insn);
54818334Speter	else if (GET_CODE (body) == SEQUENCE)
54918334Speter	  for (i = 0; i < XVECLEN (body, 0); i++)
55018334Speter	    length += get_attr_length (XVECEXP (body, 0, i));
55118334Speter	else
55218334Speter	  length = insn_default_length (insn);
55350503Sobrien	break;
55450503Sobrien
55550503Sobrien      default:
55650503Sobrien	break;
55718334Speter      }
55818334Speter
55918334Speter#ifdef ADJUST_INSN_LENGTH
56018334Speter  ADJUST_INSN_LENGTH (insn, length);
56118334Speter#endif
56218334Speter  return length;
56318334Speter#else /* not HAVE_ATTR_length */
56418334Speter  return 0;
56518334Speter#endif /* not HAVE_ATTR_length */
56618334Speter}
56718334Speter
56850503Sobrien/* Code to handle alignment inside shorten_branches.  */
56950503Sobrien
57050503Sobrien/* Here is an explanation how the algorithm in align_fuzz can give
57150503Sobrien   proper results:
57250503Sobrien
57350503Sobrien   Call a sequence of instructions beginning with alignment point X
57450503Sobrien   and continuing until the next alignment point `block X'.  When `X'
57590087Sobrien   is used in an expression, it means the alignment value of the
57650503Sobrien   alignment point.
57790087Sobrien
57850503Sobrien   Call the distance between the start of the first insn of block X, and
57950503Sobrien   the end of the last insn of block X `IX', for the `inner size of X'.
58050503Sobrien   This is clearly the sum of the instruction lengths.
58190087Sobrien
58250503Sobrien   Likewise with the next alignment-delimited block following X, which we
58350503Sobrien   shall call block Y.
58490087Sobrien
58550503Sobrien   Call the distance between the start of the first insn of block X, and
58650503Sobrien   the start of the first insn of block Y `OX', for the `outer size of X'.
58790087Sobrien
58850503Sobrien   The estimated padding is then OX - IX.
58990087Sobrien
59050503Sobrien   OX can be safely estimated as
59190087Sobrien
59250503Sobrien           if (X >= Y)
59350503Sobrien                   OX = round_up(IX, Y)
59450503Sobrien           else
59550503Sobrien                   OX = round_up(IX, X) + Y - X
59690087Sobrien
59750503Sobrien   Clearly est(IX) >= real(IX), because that only depends on the
59850503Sobrien   instruction lengths, and those being overestimated is a given.
59990087Sobrien
60050503Sobrien   Clearly round_up(foo, Z) >= round_up(bar, Z) if foo >= bar, so
60150503Sobrien   we needn't worry about that when thinking about OX.
60290087Sobrien
60350503Sobrien   When X >= Y, the alignment provided by Y adds no uncertainty factor
60450503Sobrien   for branch ranges starting before X, so we can just round what we have.
60550503Sobrien   But when X < Y, we don't know anything about the, so to speak,
60650503Sobrien   `middle bits', so we have to assume the worst when aligning up from an
60750503Sobrien   address mod X to one mod Y, which is Y - X.  */
60850503Sobrien
60950503Sobrien#ifndef LABEL_ALIGN
61090087Sobrien#define LABEL_ALIGN(LABEL) align_labels_log
61150503Sobrien#endif
61250503Sobrien
61350503Sobrien#ifndef LABEL_ALIGN_MAX_SKIP
61490087Sobrien#define LABEL_ALIGN_MAX_SKIP align_labels_max_skip
61550503Sobrien#endif
61650503Sobrien
61750503Sobrien#ifndef LOOP_ALIGN
61890087Sobrien#define LOOP_ALIGN(LABEL) align_loops_log
61950503Sobrien#endif
62050503Sobrien
62150503Sobrien#ifndef LOOP_ALIGN_MAX_SKIP
62290087Sobrien#define LOOP_ALIGN_MAX_SKIP align_loops_max_skip
62350503Sobrien#endif
62450503Sobrien
62550503Sobrien#ifndef LABEL_ALIGN_AFTER_BARRIER
62650503Sobrien#define LABEL_ALIGN_AFTER_BARRIER(LABEL) 0
62750503Sobrien#endif
62850503Sobrien
62950503Sobrien#ifndef LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP
63050503Sobrien#define LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP 0
63150503Sobrien#endif
63250503Sobrien
63390087Sobrien#ifndef JUMP_ALIGN
63490087Sobrien#define JUMP_ALIGN(LABEL) align_jumps_log
63590087Sobrien#endif
63690087Sobrien
63790087Sobrien#ifndef JUMP_ALIGN_MAX_SKIP
63890087Sobrien#define JUMP_ALIGN_MAX_SKIP align_jumps_max_skip
63990087Sobrien#endif
64090087Sobrien
64150503Sobrien#ifndef ADDR_VEC_ALIGN
64290087Sobrienstatic int
64350503Sobrienfinal_addr_vec_align (addr_vec)
64450503Sobrien     rtx addr_vec;
64550503Sobrien{
64690087Sobrien  int align = GET_MODE_SIZE (GET_MODE (PATTERN (addr_vec)));
64750503Sobrien
64850503Sobrien  if (align > BIGGEST_ALIGNMENT / BITS_PER_UNIT)
64950503Sobrien    align = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
65090087Sobrien  return exact_log2 (align);
65150503Sobrien
65250503Sobrien}
65390087Sobrien
65450503Sobrien#define ADDR_VEC_ALIGN(ADDR_VEC) final_addr_vec_align (ADDR_VEC)
65550503Sobrien#endif
65650503Sobrien
65750503Sobrien#ifndef INSN_LENGTH_ALIGNMENT
65850503Sobrien#define INSN_LENGTH_ALIGNMENT(INSN) length_unit_log
65950503Sobrien#endif
66050503Sobrien
66150503Sobrien#define INSN_SHUID(INSN) (uid_shuid[INSN_UID (INSN)])
66250503Sobrien
66350503Sobrienstatic int min_labelno, max_labelno;
66450503Sobrien
66550503Sobrien#define LABEL_TO_ALIGNMENT(LABEL) \
66650503Sobrien  (label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno].alignment)
66750503Sobrien
66850503Sobrien#define LABEL_TO_MAX_SKIP(LABEL) \
66950503Sobrien  (label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno].max_skip)
67050503Sobrien
67150503Sobrien/* For the benefit of port specific code do this also as a function.  */
67290087Sobrien
67350503Sobrienint
67450503Sobrienlabel_to_alignment (label)
67550503Sobrien     rtx label;
67650503Sobrien{
67750503Sobrien  return LABEL_TO_ALIGNMENT (label);
67850503Sobrien}
67950503Sobrien
68050503Sobrien#ifdef HAVE_ATTR_length
68150503Sobrien/* The differences in addresses
68250503Sobrien   between a branch and its target might grow or shrink depending on
68350503Sobrien   the alignment the start insn of the range (the branch for a forward
68450503Sobrien   branch or the label for a backward branch) starts out on; if these
68550503Sobrien   differences are used naively, they can even oscillate infinitely.
68650503Sobrien   We therefore want to compute a 'worst case' address difference that
68750503Sobrien   is independent of the alignment the start insn of the range end
68850503Sobrien   up on, and that is at least as large as the actual difference.
68950503Sobrien   The function align_fuzz calculates the amount we have to add to the
69050503Sobrien   naively computed difference, by traversing the part of the alignment
69150503Sobrien   chain of the start insn of the range that is in front of the end insn
69250503Sobrien   of the range, and considering for each alignment the maximum amount
69350503Sobrien   that it might contribute to a size increase.
69450503Sobrien
69550503Sobrien   For casesi tables, we also want to know worst case minimum amounts of
69650503Sobrien   address difference, in case a machine description wants to introduce
69750503Sobrien   some common offset that is added to all offsets in a table.
69890087Sobrien   For this purpose, align_fuzz with a growth argument of 0 computes the
69950503Sobrien   appropriate adjustment.  */
70050503Sobrien
70150503Sobrien/* Compute the maximum delta by which the difference of the addresses of
70250503Sobrien   START and END might grow / shrink due to a different address for start
70350503Sobrien   which changes the size of alignment insns between START and END.
70450503Sobrien   KNOWN_ALIGN_LOG is the alignment known for START.
70550503Sobrien   GROWTH should be ~0 if the objective is to compute potential code size
70650503Sobrien   increase, and 0 if the objective is to compute potential shrink.
70750503Sobrien   The return value is undefined for any other value of GROWTH.  */
70890087Sobrien
70990087Sobrienstatic int
71050503Sobrienalign_fuzz (start, end, known_align_log, growth)
71150503Sobrien     rtx start, end;
71250503Sobrien     int known_align_log;
71350503Sobrien     unsigned growth;
71450503Sobrien{
71550503Sobrien  int uid = INSN_UID (start);
71650503Sobrien  rtx align_label;
71750503Sobrien  int known_align = 1 << known_align_log;
71850503Sobrien  int end_shuid = INSN_SHUID (end);
71950503Sobrien  int fuzz = 0;
72050503Sobrien
72150503Sobrien  for (align_label = uid_align[uid]; align_label; align_label = uid_align[uid])
72250503Sobrien    {
72350503Sobrien      int align_addr, new_align;
72450503Sobrien
72550503Sobrien      uid = INSN_UID (align_label);
72690087Sobrien      align_addr = INSN_ADDRESSES (uid) - insn_lengths[uid];
72750503Sobrien      if (uid_shuid[uid] > end_shuid)
72850503Sobrien	break;
72950503Sobrien      known_align_log = LABEL_TO_ALIGNMENT (align_label);
73050503Sobrien      new_align = 1 << known_align_log;
73150503Sobrien      if (new_align < known_align)
73250503Sobrien	continue;
73350503Sobrien      fuzz += (-align_addr ^ growth) & (new_align - known_align);
73450503Sobrien      known_align = new_align;
73550503Sobrien    }
73650503Sobrien  return fuzz;
73750503Sobrien}
73850503Sobrien
73950503Sobrien/* Compute a worst-case reference address of a branch so that it
74050503Sobrien   can be safely used in the presence of aligned labels.  Since the
74150503Sobrien   size of the branch itself is unknown, the size of the branch is
74250503Sobrien   not included in the range.  I.e. for a forward branch, the reference
74350503Sobrien   address is the end address of the branch as known from the previous
74450503Sobrien   branch shortening pass, minus a value to account for possible size
74550503Sobrien   increase due to alignment.  For a backward branch, it is the start
74650503Sobrien   address of the branch as known from the current pass, plus a value
74750503Sobrien   to account for possible size increase due to alignment.
74850503Sobrien   NB.: Therefore, the maximum offset allowed for backward branches needs
74950503Sobrien   to exclude the branch size.  */
75090087Sobrien
75150503Sobrienint
75250503Sobrieninsn_current_reference_address (branch)
75350503Sobrien     rtx branch;
75450503Sobrien{
75590087Sobrien  rtx dest, seq;
75690087Sobrien  int seq_uid;
75790087Sobrien
75890087Sobrien  if (! INSN_ADDRESSES_SET_P ())
75990087Sobrien    return 0;
76090087Sobrien
76190087Sobrien  seq = NEXT_INSN (PREV_INSN (branch));
76290087Sobrien  seq_uid = INSN_UID (seq);
76350503Sobrien  if (GET_CODE (branch) != JUMP_INSN)
76450503Sobrien    /* This can happen for example on the PA; the objective is to know the
76550503Sobrien       offset to address something in front of the start of the function.
76650503Sobrien       Thus, we can treat it like a backward branch.
76750503Sobrien       We assume here that FUNCTION_BOUNDARY / BITS_PER_UNIT is larger than
76850503Sobrien       any alignment we'd encounter, so we skip the call to align_fuzz.  */
76950503Sobrien    return insn_current_address;
77050503Sobrien  dest = JUMP_LABEL (branch);
77190087Sobrien
77290087Sobrien  /* BRANCH has no proper alignment chain set, so use SEQ.
77390087Sobrien     BRANCH also has no INSN_SHUID.  */
77490087Sobrien  if (INSN_SHUID (seq) < INSN_SHUID (dest))
77550503Sobrien    {
77690087Sobrien      /* Forward branch.  */
77750503Sobrien      return (insn_last_address + insn_lengths[seq_uid]
77850503Sobrien	      - align_fuzz (seq, dest, length_unit_log, ~0));
77950503Sobrien    }
78050503Sobrien  else
78150503Sobrien    {
78290087Sobrien      /* Backward branch.  */
78350503Sobrien      return (insn_current_address
78450503Sobrien	      + align_fuzz (dest, seq, length_unit_log, ~0));
78550503Sobrien    }
78650503Sobrien}
78750503Sobrien#endif /* HAVE_ATTR_length */
78850503Sobrien
78990087Sobrienvoid
79090087Sobriencompute_alignments ()
79190087Sobrien{
79290087Sobrien  int i;
79390087Sobrien  int log, max_skip, max_log;
79490087Sobrien
79590087Sobrien  if (label_align)
79690087Sobrien    {
79790087Sobrien      free (label_align);
79890087Sobrien      label_align = 0;
79990087Sobrien    }
80090087Sobrien
80190087Sobrien  max_labelno = max_label_num ();
80290087Sobrien  min_labelno = get_first_label_num ();
80390087Sobrien  label_align = (struct label_alignment *)
80490087Sobrien    xcalloc (max_labelno - min_labelno + 1, sizeof (struct label_alignment));
80590087Sobrien
80690087Sobrien  /* If not optimizing or optimizing for size, don't assign any alignments.  */
80790087Sobrien  if (! optimize || optimize_size)
80890087Sobrien    return;
80990087Sobrien
81090087Sobrien  for (i = 0; i < n_basic_blocks; i++)
81190087Sobrien    {
81290087Sobrien      basic_block bb = BASIC_BLOCK (i);
81390087Sobrien      rtx label = bb->head;
81490087Sobrien      int fallthru_frequency = 0, branch_frequency = 0, has_fallthru = 0;
81590087Sobrien      edge e;
81690087Sobrien
81790087Sobrien      if (GET_CODE (label) != CODE_LABEL)
81890087Sobrien	continue;
81990087Sobrien      max_log = LABEL_ALIGN (label);
82090087Sobrien      max_skip = LABEL_ALIGN_MAX_SKIP;
82190087Sobrien
82290087Sobrien      for (e = bb->pred; e; e = e->pred_next)
82390087Sobrien	{
82490087Sobrien	  if (e->flags & EDGE_FALLTHRU)
82590087Sobrien	    has_fallthru = 1, fallthru_frequency += EDGE_FREQUENCY (e);
82690087Sobrien	  else
82790087Sobrien	    branch_frequency += EDGE_FREQUENCY (e);
82890087Sobrien	}
82990087Sobrien
83090087Sobrien      /* There are two purposes to align block with no fallthru incoming edge:
83190087Sobrien	 1) to avoid fetch stalls when branch destination is near cache boundary
83290087Sobrien	 2) to improve cache efficiency in case the previous block is not executed
83390087Sobrien	    (so it does not need to be in the cache).
83490087Sobrien
83590087Sobrien	 We to catch first case, we align frequently executed blocks.
83690087Sobrien	 To catch the second, we align blocks that are executed more frequently
83790087Sobrien	 than the predecessor and the predecessor is likely to not be executed
83890087Sobrien	 when function is called.  */
83990087Sobrien
84090087Sobrien      if (!has_fallthru
84190087Sobrien	  && (branch_frequency > BB_FREQ_MAX / 10
84290087Sobrien	      || (bb->frequency > BASIC_BLOCK (i - 1)->frequency * 10
84390087Sobrien		  && (BASIC_BLOCK (i - 1)->frequency
84490087Sobrien		      <= ENTRY_BLOCK_PTR->frequency / 2))))
84590087Sobrien	{
84690087Sobrien	  log = JUMP_ALIGN (label);
84790087Sobrien	  if (max_log < log)
84890087Sobrien	    {
84990087Sobrien	      max_log = log;
85090087Sobrien	      max_skip = JUMP_ALIGN_MAX_SKIP;
85190087Sobrien	    }
85290087Sobrien	}
85390087Sobrien      /* In case block is frequent and reached mostly by non-fallthru edge,
85490087Sobrien	 align it.  It is most likely an first block of loop.  */
85590087Sobrien      if (has_fallthru
85690087Sobrien	  && branch_frequency + fallthru_frequency > BB_FREQ_MAX / 10
85790087Sobrien	  && branch_frequency > fallthru_frequency * 5)
85890087Sobrien	{
85990087Sobrien	  log = LOOP_ALIGN (label);
86090087Sobrien	  if (max_log < log)
86190087Sobrien	    {
86290087Sobrien	      max_log = log;
86390087Sobrien	      max_skip = LOOP_ALIGN_MAX_SKIP;
86490087Sobrien	    }
86590087Sobrien	}
86690087Sobrien      LABEL_TO_ALIGNMENT (label) = max_log;
86790087Sobrien      LABEL_TO_MAX_SKIP (label) = max_skip;
86890087Sobrien    }
86990087Sobrien}
87090087Sobrien
87118334Speter/* Make a pass over all insns and compute their actual lengths by shortening
87218334Speter   any branches of variable length if possible.  */
87318334Speter
87418334Speter/* Give a default value for the lowest address in a function.  */
87518334Speter
87618334Speter#ifndef FIRST_INSN_ADDRESS
87718334Speter#define FIRST_INSN_ADDRESS 0
87818334Speter#endif
87918334Speter
88050503Sobrien/* shorten_branches might be called multiple times:  for example, the SH
88150503Sobrien   port splits out-of-range conditional branches in MACHINE_DEPENDENT_REORG.
88250503Sobrien   In order to do this, it needs proper length information, which it obtains
88350503Sobrien   by calling shorten_branches.  This cannot be collapsed with
88490087Sobrien   shorten_branches itself into a single pass unless we also want to integrate
88550503Sobrien   reorg.c, since the branch splitting exposes new instructions with delay
88650503Sobrien   slots.  */
88750503Sobrien
88818334Spetervoid
88918334Spetershorten_branches (first)
89090087Sobrien     rtx first ATTRIBUTE_UNUSED;
89118334Speter{
89250503Sobrien  rtx insn;
89350503Sobrien  int max_uid;
89450503Sobrien  int i;
89550503Sobrien  int max_log;
89650503Sobrien  int max_skip;
89718334Speter#ifdef HAVE_ATTR_length
89850503Sobrien#define MAX_CODE_ALIGN 16
89950503Sobrien  rtx seq;
90018334Speter  int something_changed = 1;
90118334Speter  char *varying_length;
90218334Speter  rtx body;
90318334Speter  int uid;
90450503Sobrien  rtx align_tab[MAX_CODE_ALIGN];
90518334Speter
90650503Sobrien#endif
90718334Speter
90850503Sobrien  /* Compute maximum UID and allocate label_align / uid_shuid.  */
90950503Sobrien  max_uid = get_max_uid ();
91050503Sobrien
91150503Sobrien  uid_shuid = (int *) xmalloc (max_uid * sizeof *uid_shuid);
91250503Sobrien
91390087Sobrien  if (max_labelno != max_label_num ())
91490087Sobrien    {
91590087Sobrien      int old = max_labelno;
91690087Sobrien      int n_labels;
91790087Sobrien      int n_old_labels;
91890087Sobrien
91990087Sobrien      max_labelno = max_label_num ();
92090087Sobrien
92190087Sobrien      n_labels = max_labelno - min_labelno + 1;
92290087Sobrien      n_old_labels = old - min_labelno + 1;
92390087Sobrien
92490087Sobrien      label_align = (struct label_alignment *) xrealloc
92590087Sobrien	(label_align, n_labels * sizeof (struct label_alignment));
92690087Sobrien
92790087Sobrien      /* Range of labels grows monotonically in the function.  Abort here
92890087Sobrien         means that the initialization of array got lost.  */
92990087Sobrien      if (n_old_labels > n_labels)
93090087Sobrien	abort ();
93190087Sobrien
93290087Sobrien      memset (label_align + n_old_labels, 0,
93390087Sobrien	      (n_labels - n_old_labels) * sizeof (struct label_alignment));
93490087Sobrien    }
93590087Sobrien
93650503Sobrien  /* Initialize label_align and set up uid_shuid to be strictly
93750503Sobrien     monotonically rising with insn order.  */
93850503Sobrien  /* We use max_log here to keep track of the maximum alignment we want to
93950503Sobrien     impose on the next CODE_LABEL (or the current one if we are processing
94050503Sobrien     the CODE_LABEL itself).  */
94190087Sobrien
94250503Sobrien  max_log = 0;
94350503Sobrien  max_skip = 0;
94450503Sobrien
94550503Sobrien  for (insn = get_insns (), i = 1; insn; insn = NEXT_INSN (insn))
94650503Sobrien    {
94750503Sobrien      int log;
94850503Sobrien
94950503Sobrien      INSN_SHUID (insn) = i++;
95090087Sobrien      if (INSN_P (insn))
95150503Sobrien	{
95250503Sobrien	  /* reorg might make the first insn of a loop being run once only,
95350503Sobrien             and delete the label in front of it.  Then we want to apply
95450503Sobrien             the loop alignment to the new label created by reorg, which
95550503Sobrien             is separated by the former loop start insn from the
95650503Sobrien	     NOTE_INSN_LOOP_BEG.  */
95750503Sobrien	}
95850503Sobrien      else if (GET_CODE (insn) == CODE_LABEL)
95950503Sobrien	{
96050503Sobrien	  rtx next;
96150503Sobrien
96290087Sobrien	  /* Merge in alignments computed by compute_alignments.  */
96390087Sobrien	  log = LABEL_TO_ALIGNMENT (insn);
96490087Sobrien	  if (max_log < log)
96590087Sobrien	    {
96690087Sobrien	      max_log = log;
96790087Sobrien	      max_skip = LABEL_TO_MAX_SKIP (insn);
96890087Sobrien	    }
96990087Sobrien
97050503Sobrien	  log = LABEL_ALIGN (insn);
97150503Sobrien	  if (max_log < log)
97250503Sobrien	    {
97350503Sobrien	      max_log = log;
97450503Sobrien	      max_skip = LABEL_ALIGN_MAX_SKIP;
97550503Sobrien	    }
97650503Sobrien	  next = NEXT_INSN (insn);
97750503Sobrien	  /* ADDR_VECs only take room if read-only data goes into the text
97850503Sobrien	     section.  */
97950503Sobrien	  if (JUMP_TABLES_IN_TEXT_SECTION
98050503Sobrien#if !defined(READONLY_DATA_SECTION)
98150503Sobrien	      || 1
98250503Sobrien#endif
98350503Sobrien	      )
98450503Sobrien	    if (next && GET_CODE (next) == JUMP_INSN)
98550503Sobrien	      {
98650503Sobrien		rtx nextbody = PATTERN (next);
98750503Sobrien		if (GET_CODE (nextbody) == ADDR_VEC
98850503Sobrien		    || GET_CODE (nextbody) == ADDR_DIFF_VEC)
98950503Sobrien		  {
99050503Sobrien		    log = ADDR_VEC_ALIGN (next);
99150503Sobrien		    if (max_log < log)
99250503Sobrien		      {
99350503Sobrien			max_log = log;
99450503Sobrien			max_skip = LABEL_ALIGN_MAX_SKIP;
99550503Sobrien		      }
99650503Sobrien		  }
99750503Sobrien	      }
99850503Sobrien	  LABEL_TO_ALIGNMENT (insn) = max_log;
99950503Sobrien	  LABEL_TO_MAX_SKIP (insn) = max_skip;
100050503Sobrien	  max_log = 0;
100150503Sobrien	  max_skip = 0;
100250503Sobrien	}
100350503Sobrien      else if (GET_CODE (insn) == BARRIER)
100450503Sobrien	{
100550503Sobrien	  rtx label;
100650503Sobrien
100790087Sobrien	  for (label = insn; label && ! INSN_P (label);
100850503Sobrien	       label = NEXT_INSN (label))
100950503Sobrien	    if (GET_CODE (label) == CODE_LABEL)
101050503Sobrien	      {
101150503Sobrien		log = LABEL_ALIGN_AFTER_BARRIER (insn);
101250503Sobrien		if (max_log < log)
101350503Sobrien		  {
101450503Sobrien		    max_log = log;
101550503Sobrien		    max_skip = LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP;
101650503Sobrien		  }
101750503Sobrien		break;
101850503Sobrien	      }
101950503Sobrien	}
102050503Sobrien    }
102150503Sobrien#ifdef HAVE_ATTR_length
102250503Sobrien
102350503Sobrien  /* Allocate the rest of the arrays.  */
102490087Sobrien  insn_lengths = (int *) xmalloc (max_uid * sizeof (*insn_lengths));
102552515Sobrien  insn_lengths_max_uid = max_uid;
102650503Sobrien  /* Syntax errors can lead to labels being outside of the main insn stream.
102750503Sobrien     Initialize insn_addresses, so that we get reproducible results.  */
102890087Sobrien  INSN_ADDRESSES_ALLOC (max_uid);
102950503Sobrien
103090087Sobrien  varying_length = (char *) xcalloc (max_uid, sizeof (char));
103150503Sobrien
103250503Sobrien  /* Initialize uid_align.  We scan instructions
103350503Sobrien     from end to start, and keep in align_tab[n] the last seen insn
103450503Sobrien     that does an alignment of at least n+1, i.e. the successor
103550503Sobrien     in the alignment chain for an insn that does / has a known
103650503Sobrien     alignment of n.  */
103790087Sobrien  uid_align = (rtx *) xcalloc (max_uid, sizeof *uid_align);
103850503Sobrien
103990087Sobrien  for (i = MAX_CODE_ALIGN; --i >= 0;)
104050503Sobrien    align_tab[i] = NULL_RTX;
104150503Sobrien  seq = get_last_insn ();
104250503Sobrien  for (; seq; seq = PREV_INSN (seq))
104350503Sobrien    {
104450503Sobrien      int uid = INSN_UID (seq);
104550503Sobrien      int log;
104650503Sobrien      log = (GET_CODE (seq) == CODE_LABEL ? LABEL_TO_ALIGNMENT (seq) : 0);
104750503Sobrien      uid_align[uid] = align_tab[0];
104850503Sobrien      if (log)
104950503Sobrien	{
105050503Sobrien	  /* Found an alignment label.  */
105150503Sobrien	  uid_align[uid] = align_tab[log];
105250503Sobrien	  for (i = log - 1; i >= 0; i--)
105350503Sobrien	    align_tab[i] = seq;
105450503Sobrien	}
105550503Sobrien    }
105650503Sobrien#ifdef CASE_VECTOR_SHORTEN_MODE
105750503Sobrien  if (optimize)
105850503Sobrien    {
105950503Sobrien      /* Look for ADDR_DIFF_VECs, and initialize their minimum and maximum
106050503Sobrien         label fields.  */
106150503Sobrien
106250503Sobrien      int min_shuid = INSN_SHUID (get_insns ()) - 1;
106350503Sobrien      int max_shuid = INSN_SHUID (get_last_insn ()) + 1;
106450503Sobrien      int rel;
106550503Sobrien
106650503Sobrien      for (insn = first; insn != 0; insn = NEXT_INSN (insn))
106750503Sobrien	{
106850503Sobrien	  rtx min_lab = NULL_RTX, max_lab = NULL_RTX, pat;
106950503Sobrien	  int len, i, min, max, insn_shuid;
107050503Sobrien	  int min_align;
107150503Sobrien	  addr_diff_vec_flags flags;
107250503Sobrien
107350503Sobrien	  if (GET_CODE (insn) != JUMP_INSN
107450503Sobrien	      || GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC)
107550503Sobrien	    continue;
107650503Sobrien	  pat = PATTERN (insn);
107750503Sobrien	  len = XVECLEN (pat, 1);
107850503Sobrien	  if (len <= 0)
107950503Sobrien	    abort ();
108050503Sobrien	  min_align = MAX_CODE_ALIGN;
108150503Sobrien	  for (min = max_shuid, max = min_shuid, i = len - 1; i >= 0; i--)
108250503Sobrien	    {
108350503Sobrien	      rtx lab = XEXP (XVECEXP (pat, 1, i), 0);
108450503Sobrien	      int shuid = INSN_SHUID (lab);
108550503Sobrien	      if (shuid < min)
108650503Sobrien		{
108750503Sobrien		  min = shuid;
108850503Sobrien		  min_lab = lab;
108950503Sobrien		}
109050503Sobrien	      if (shuid > max)
109150503Sobrien		{
109250503Sobrien		  max = shuid;
109350503Sobrien		  max_lab = lab;
109450503Sobrien		}
109550503Sobrien	      if (min_align > LABEL_TO_ALIGNMENT (lab))
109650503Sobrien		min_align = LABEL_TO_ALIGNMENT (lab);
109750503Sobrien	    }
109850503Sobrien	  XEXP (pat, 2) = gen_rtx_LABEL_REF (VOIDmode, min_lab);
109950503Sobrien	  XEXP (pat, 3) = gen_rtx_LABEL_REF (VOIDmode, max_lab);
110050503Sobrien	  insn_shuid = INSN_SHUID (insn);
110150503Sobrien	  rel = INSN_SHUID (XEXP (XEXP (pat, 0), 0));
110250503Sobrien	  flags.min_align = min_align;
110350503Sobrien	  flags.base_after_vec = rel > insn_shuid;
110450503Sobrien	  flags.min_after_vec  = min > insn_shuid;
110550503Sobrien	  flags.max_after_vec  = max > insn_shuid;
110650503Sobrien	  flags.min_after_base = min > rel;
110750503Sobrien	  flags.max_after_base = max > rel;
110850503Sobrien	  ADDR_DIFF_VEC_FLAGS (pat) = flags;
110950503Sobrien	}
111050503Sobrien    }
111150503Sobrien#endif /* CASE_VECTOR_SHORTEN_MODE */
111250503Sobrien
111318334Speter  /* Compute initial lengths, addresses, and varying flags for each insn.  */
111418334Speter  for (insn_current_address = FIRST_INSN_ADDRESS, insn = first;
111518334Speter       insn != 0;
111618334Speter       insn_current_address += insn_lengths[uid], insn = NEXT_INSN (insn))
111718334Speter    {
111818334Speter      uid = INSN_UID (insn);
111950503Sobrien
112050503Sobrien      insn_lengths[uid] = 0;
112150503Sobrien
112250503Sobrien      if (GET_CODE (insn) == CODE_LABEL)
112350503Sobrien	{
112450503Sobrien	  int log = LABEL_TO_ALIGNMENT (insn);
112550503Sobrien	  if (log)
112650503Sobrien	    {
112750503Sobrien	      int align = 1 << log;
112850503Sobrien	      int new_address = (insn_current_address + align - 1) & -align;
112950503Sobrien	      insn_lengths[uid] = new_address - insn_current_address;
113050503Sobrien	    }
113150503Sobrien	}
113250503Sobrien
113390087Sobrien      INSN_ADDRESSES (uid) = insn_current_address;
113490087Sobrien
113518334Speter      if (GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER
113618334Speter	  || GET_CODE (insn) == CODE_LABEL)
113718334Speter	continue;
113850503Sobrien      if (INSN_DELETED_P (insn))
113950503Sobrien	continue;
114018334Speter
114118334Speter      body = PATTERN (insn);
114218334Speter      if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
114318334Speter	{
114418334Speter	  /* This only takes room if read-only data goes into the text
114518334Speter	     section.  */
114650503Sobrien	  if (JUMP_TABLES_IN_TEXT_SECTION
114750503Sobrien#if !defined(READONLY_DATA_SECTION)
114850503Sobrien	      || 1
114918334Speter#endif
115050503Sobrien	      )
115150503Sobrien	    insn_lengths[uid] = (XVECLEN (body,
115250503Sobrien					  GET_CODE (body) == ADDR_DIFF_VEC)
115350503Sobrien				 * GET_MODE_SIZE (GET_MODE (body)));
115450503Sobrien	  /* Alignment is handled by ADDR_VEC_ALIGN.  */
115518334Speter	}
115690087Sobrien      else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0)
115718334Speter	insn_lengths[uid] = asm_insn_count (body) * insn_default_length (insn);
115818334Speter      else if (GET_CODE (body) == SEQUENCE)
115918334Speter	{
116018334Speter	  int i;
116118334Speter	  int const_delay_slots;
116218334Speter#ifdef DELAY_SLOTS
116318334Speter	  const_delay_slots = const_num_delay_slots (XVECEXP (body, 0, 0));
116418334Speter#else
116518334Speter	  const_delay_slots = 0;
116618334Speter#endif
116718334Speter	  /* Inside a delay slot sequence, we do not do any branch shortening
116818334Speter	     if the shortening could change the number of delay slots
116950503Sobrien	     of the branch.  */
117018334Speter	  for (i = 0; i < XVECLEN (body, 0); i++)
117118334Speter	    {
117218334Speter	      rtx inner_insn = XVECEXP (body, 0, i);
117318334Speter	      int inner_uid = INSN_UID (inner_insn);
117418334Speter	      int inner_length;
117518334Speter
117690087Sobrien	      if (GET_CODE (body) == ASM_INPUT
117790087Sobrien		  || asm_noperands (PATTERN (XVECEXP (body, 0, i))) >= 0)
117818334Speter		inner_length = (asm_insn_count (PATTERN (inner_insn))
117918334Speter				* insn_default_length (inner_insn));
118018334Speter	      else
118118334Speter		inner_length = insn_default_length (inner_insn);
118290087Sobrien
118318334Speter	      insn_lengths[inner_uid] = inner_length;
118418334Speter	      if (const_delay_slots)
118518334Speter		{
118618334Speter		  if ((varying_length[inner_uid]
118718334Speter		       = insn_variable_length_p (inner_insn)) != 0)
118818334Speter		    varying_length[uid] = 1;
118990087Sobrien		  INSN_ADDRESSES (inner_uid) = (insn_current_address
119090087Sobrien						+ insn_lengths[uid]);
119118334Speter		}
119218334Speter	      else
119318334Speter		varying_length[inner_uid] = 0;
119418334Speter	      insn_lengths[uid] += inner_length;
119518334Speter	    }
119618334Speter	}
119718334Speter      else if (GET_CODE (body) != USE && GET_CODE (body) != CLOBBER)
119818334Speter	{
119918334Speter	  insn_lengths[uid] = insn_default_length (insn);
120018334Speter	  varying_length[uid] = insn_variable_length_p (insn);
120118334Speter	}
120218334Speter
120318334Speter      /* If needed, do any adjustment.  */
120418334Speter#ifdef ADJUST_INSN_LENGTH
120518334Speter      ADJUST_INSN_LENGTH (insn, insn_lengths[uid]);
120652515Sobrien      if (insn_lengths[uid] < 0)
120790087Sobrien	fatal_insn ("negative insn length", insn);
120818334Speter#endif
120918334Speter    }
121018334Speter
121118334Speter  /* Now loop over all the insns finding varying length insns.  For each,
121218334Speter     get the current insn length.  If it has changed, reflect the change.
121318334Speter     When nothing changes for a full pass, we are done.  */
121418334Speter
121518334Speter  while (something_changed)
121618334Speter    {
121718334Speter      something_changed = 0;
121850503Sobrien      insn_current_align = MAX_CODE_ALIGN - 1;
121918334Speter      for (insn_current_address = FIRST_INSN_ADDRESS, insn = first;
122018334Speter	   insn != 0;
122118334Speter	   insn = NEXT_INSN (insn))
122218334Speter	{
122318334Speter	  int new_length;
122450503Sobrien#ifdef ADJUST_INSN_LENGTH
122518334Speter	  int tmp_length;
122650503Sobrien#endif
122750503Sobrien	  int length_align;
122818334Speter
122918334Speter	  uid = INSN_UID (insn);
123050503Sobrien
123150503Sobrien	  if (GET_CODE (insn) == CODE_LABEL)
123250503Sobrien	    {
123350503Sobrien	      int log = LABEL_TO_ALIGNMENT (insn);
123450503Sobrien	      if (log > insn_current_align)
123550503Sobrien		{
123650503Sobrien		  int align = 1 << log;
123750503Sobrien		  int new_address= (insn_current_address + align - 1) & -align;
123850503Sobrien		  insn_lengths[uid] = new_address - insn_current_address;
123950503Sobrien		  insn_current_align = log;
124050503Sobrien		  insn_current_address = new_address;
124150503Sobrien		}
124250503Sobrien	      else
124350503Sobrien		insn_lengths[uid] = 0;
124490087Sobrien	      INSN_ADDRESSES (uid) = insn_current_address;
124550503Sobrien	      continue;
124650503Sobrien	    }
124750503Sobrien
124850503Sobrien	  length_align = INSN_LENGTH_ALIGNMENT (insn);
124950503Sobrien	  if (length_align < insn_current_align)
125050503Sobrien	    insn_current_align = length_align;
125150503Sobrien
125290087Sobrien	  insn_last_address = INSN_ADDRESSES (uid);
125390087Sobrien	  INSN_ADDRESSES (uid) = insn_current_address;
125450503Sobrien
125550503Sobrien#ifdef CASE_VECTOR_SHORTEN_MODE
125650503Sobrien	  if (optimize && GET_CODE (insn) == JUMP_INSN
125750503Sobrien	      && GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
125818334Speter	    {
125950503Sobrien	      rtx body = PATTERN (insn);
126050503Sobrien	      int old_length = insn_lengths[uid];
126150503Sobrien	      rtx rel_lab = XEXP (XEXP (body, 0), 0);
126250503Sobrien	      rtx min_lab = XEXP (XEXP (body, 2), 0);
126350503Sobrien	      rtx max_lab = XEXP (XEXP (body, 3), 0);
126490087Sobrien	      int rel_addr = INSN_ADDRESSES (INSN_UID (rel_lab));
126590087Sobrien	      int min_addr = INSN_ADDRESSES (INSN_UID (min_lab));
126690087Sobrien	      int max_addr = INSN_ADDRESSES (INSN_UID (max_lab));
126750503Sobrien	      rtx prev;
126850503Sobrien	      int rel_align = 0;
126990087Sobrien	      addr_diff_vec_flags flags;
127050503Sobrien
127190087Sobrien	      /* Avoid automatic aggregate initialization.  */
127290087Sobrien	      flags = ADDR_DIFF_VEC_FLAGS (body);
127390087Sobrien
127450503Sobrien	      /* Try to find a known alignment for rel_lab.  */
127550503Sobrien	      for (prev = rel_lab;
127650503Sobrien		   prev
127750503Sobrien		   && ! insn_lengths[INSN_UID (prev)]
127850503Sobrien		   && ! (varying_length[INSN_UID (prev)] & 1);
127950503Sobrien		   prev = PREV_INSN (prev))
128050503Sobrien		if (varying_length[INSN_UID (prev)] & 2)
128150503Sobrien		  {
128250503Sobrien		    rel_align = LABEL_TO_ALIGNMENT (prev);
128350503Sobrien		    break;
128450503Sobrien		  }
128550503Sobrien
128650503Sobrien	      /* See the comment on addr_diff_vec_flags in rtl.h for the
128750503Sobrien		 meaning of the flags values.  base: REL_LAB   vec: INSN  */
128850503Sobrien	      /* Anything after INSN has still addresses from the last
128950503Sobrien		 pass; adjust these so that they reflect our current
129050503Sobrien		 estimate for this pass.  */
129150503Sobrien	      if (flags.base_after_vec)
129250503Sobrien		rel_addr += insn_current_address - insn_last_address;
129350503Sobrien	      if (flags.min_after_vec)
129450503Sobrien		min_addr += insn_current_address - insn_last_address;
129550503Sobrien	      if (flags.max_after_vec)
129650503Sobrien		max_addr += insn_current_address - insn_last_address;
129750503Sobrien	      /* We want to know the worst case, i.e. lowest possible value
129850503Sobrien		 for the offset of MIN_LAB.  If MIN_LAB is after REL_LAB,
129950503Sobrien		 its offset is positive, and we have to be wary of code shrink;
130050503Sobrien		 otherwise, it is negative, and we have to be vary of code
130150503Sobrien		 size increase.  */
130250503Sobrien	      if (flags.min_after_base)
130350503Sobrien		{
130450503Sobrien		  /* If INSN is between REL_LAB and MIN_LAB, the size
130550503Sobrien		     changes we are about to make can change the alignment
130650503Sobrien		     within the observed offset, therefore we have to break
130750503Sobrien		     it up into two parts that are independent.  */
130850503Sobrien		  if (! flags.base_after_vec && flags.min_after_vec)
130950503Sobrien		    {
131050503Sobrien		      min_addr -= align_fuzz (rel_lab, insn, rel_align, 0);
131150503Sobrien		      min_addr -= align_fuzz (insn, min_lab, 0, 0);
131250503Sobrien		    }
131350503Sobrien		  else
131450503Sobrien		    min_addr -= align_fuzz (rel_lab, min_lab, rel_align, 0);
131550503Sobrien		}
131650503Sobrien	      else
131750503Sobrien		{
131850503Sobrien		  if (flags.base_after_vec && ! flags.min_after_vec)
131950503Sobrien		    {
132050503Sobrien		      min_addr -= align_fuzz (min_lab, insn, 0, ~0);
132150503Sobrien		      min_addr -= align_fuzz (insn, rel_lab, 0, ~0);
132250503Sobrien		    }
132350503Sobrien		  else
132450503Sobrien		    min_addr -= align_fuzz (min_lab, rel_lab, 0, ~0);
132550503Sobrien		}
132650503Sobrien	      /* Likewise, determine the highest lowest possible value
132750503Sobrien		 for the offset of MAX_LAB.  */
132850503Sobrien	      if (flags.max_after_base)
132950503Sobrien		{
133050503Sobrien		  if (! flags.base_after_vec && flags.max_after_vec)
133150503Sobrien		    {
133250503Sobrien		      max_addr += align_fuzz (rel_lab, insn, rel_align, ~0);
133350503Sobrien		      max_addr += align_fuzz (insn, max_lab, 0, ~0);
133450503Sobrien		    }
133550503Sobrien		  else
133650503Sobrien		    max_addr += align_fuzz (rel_lab, max_lab, rel_align, ~0);
133750503Sobrien		}
133850503Sobrien	      else
133950503Sobrien		{
134050503Sobrien		  if (flags.base_after_vec && ! flags.max_after_vec)
134150503Sobrien		    {
134250503Sobrien		      max_addr += align_fuzz (max_lab, insn, 0, 0);
134350503Sobrien		      max_addr += align_fuzz (insn, rel_lab, 0, 0);
134450503Sobrien		    }
134550503Sobrien		  else
134650503Sobrien		    max_addr += align_fuzz (max_lab, rel_lab, 0, 0);
134750503Sobrien		}
134850503Sobrien	      PUT_MODE (body, CASE_VECTOR_SHORTEN_MODE (min_addr - rel_addr,
134950503Sobrien							max_addr - rel_addr,
135050503Sobrien							body));
135150503Sobrien	      if (JUMP_TABLES_IN_TEXT_SECTION
135250503Sobrien#if !defined(READONLY_DATA_SECTION)
135350503Sobrien		  || 1
135450503Sobrien#endif
135550503Sobrien		  )
135650503Sobrien		{
135750503Sobrien		  insn_lengths[uid]
135850503Sobrien		    = (XVECLEN (body, 1) * GET_MODE_SIZE (GET_MODE (body)));
135950503Sobrien		  insn_current_address += insn_lengths[uid];
136050503Sobrien		  if (insn_lengths[uid] != old_length)
136150503Sobrien		    something_changed = 1;
136250503Sobrien		}
136350503Sobrien
136450503Sobrien	      continue;
136550503Sobrien	    }
136650503Sobrien#endif /* CASE_VECTOR_SHORTEN_MODE */
136750503Sobrien
136850503Sobrien	  if (! (varying_length[uid]))
136950503Sobrien	    {
137090087Sobrien	      if (GET_CODE (insn) == INSN
137190087Sobrien		  && GET_CODE (PATTERN (insn)) == SEQUENCE)
137290087Sobrien		{
137390087Sobrien		  int i;
137490087Sobrien
137590087Sobrien		  body = PATTERN (insn);
137690087Sobrien		  for (i = 0; i < XVECLEN (body, 0); i++)
137790087Sobrien		    {
137890087Sobrien		      rtx inner_insn = XVECEXP (body, 0, i);
137990087Sobrien		      int inner_uid = INSN_UID (inner_insn);
138090087Sobrien
138190087Sobrien		      INSN_ADDRESSES (inner_uid) = insn_current_address;
138290087Sobrien
138390087Sobrien		      insn_current_address += insn_lengths[inner_uid];
138490087Sobrien		    }
138590087Sobrien                }
138690087Sobrien	      else
138790087Sobrien		insn_current_address += insn_lengths[uid];
138890087Sobrien
138918334Speter	      continue;
139018334Speter	    }
139190087Sobrien
139218334Speter	  if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE)
139318334Speter	    {
139418334Speter	      int i;
139590087Sobrien
139618334Speter	      body = PATTERN (insn);
139718334Speter	      new_length = 0;
139818334Speter	      for (i = 0; i < XVECLEN (body, 0); i++)
139918334Speter		{
140018334Speter		  rtx inner_insn = XVECEXP (body, 0, i);
140118334Speter		  int inner_uid = INSN_UID (inner_insn);
140218334Speter		  int inner_length;
140318334Speter
140490087Sobrien		  INSN_ADDRESSES (inner_uid) = insn_current_address;
140518334Speter
140618334Speter		  /* insn_current_length returns 0 for insns with a
140718334Speter		     non-varying length.  */
140818334Speter		  if (! varying_length[inner_uid])
140918334Speter		    inner_length = insn_lengths[inner_uid];
141018334Speter		  else
141118334Speter		    inner_length = insn_current_length (inner_insn);
141218334Speter
141318334Speter		  if (inner_length != insn_lengths[inner_uid])
141418334Speter		    {
141518334Speter		      insn_lengths[inner_uid] = inner_length;
141618334Speter		      something_changed = 1;
141718334Speter		    }
141818334Speter		  insn_current_address += insn_lengths[inner_uid];
141918334Speter		  new_length += inner_length;
142018334Speter		}
142118334Speter	    }
142218334Speter	  else
142318334Speter	    {
142418334Speter	      new_length = insn_current_length (insn);
142518334Speter	      insn_current_address += new_length;
142618334Speter	    }
142718334Speter
142818334Speter#ifdef ADJUST_INSN_LENGTH
142918334Speter	  /* If needed, do any adjustment.  */
143018334Speter	  tmp_length = new_length;
143118334Speter	  ADJUST_INSN_LENGTH (insn, new_length);
143218334Speter	  insn_current_address += (new_length - tmp_length);
143318334Speter#endif
143418334Speter
143518334Speter	  if (new_length != insn_lengths[uid])
143618334Speter	    {
143718334Speter	      insn_lengths[uid] = new_length;
143818334Speter	      something_changed = 1;
143918334Speter	    }
144018334Speter	}
144118334Speter      /* For a non-optimizing compile, do only a single pass.  */
144218334Speter      if (!optimize)
144318334Speter	break;
144418334Speter    }
144550503Sobrien
144650503Sobrien  free (varying_length);
144750503Sobrien
144818334Speter#endif /* HAVE_ATTR_length */
144918334Speter}
145018334Speter
145118334Speter#ifdef HAVE_ATTR_length
145218334Speter/* Given the body of an INSN known to be generated by an ASM statement, return
145318334Speter   the number of machine instructions likely to be generated for this insn.
145418334Speter   This is used to compute its length.  */
145518334Speter
145618334Speterstatic int
145718334Speterasm_insn_count (body)
145818334Speter     rtx body;
145918334Speter{
146090087Sobrien  const char *template;
146118334Speter  int count = 1;
146218334Speter
146318334Speter  if (GET_CODE (body) == ASM_INPUT)
146418334Speter    template = XSTR (body, 0);
146518334Speter  else
146690087Sobrien    template = decode_asm_operands (body, NULL, NULL, NULL, NULL);
146718334Speter
146890087Sobrien  for (; *template; template++)
146990087Sobrien    if (IS_ASM_LOGICAL_LINE_SEPARATOR (*template) || *template == '\n')
147018334Speter      count++;
147118334Speter
147218334Speter  return count;
147318334Speter}
147418334Speter#endif
147518334Speter
147618334Speter/* Output assembler code for the start of a function,
147718334Speter   and initialize some of the variables in this file
147818334Speter   for the new function.  The label for the function and associated
147918334Speter   assembler pseudo-ops have already been output in `assemble_start_function'.
148018334Speter
148118334Speter   FIRST is the first insn of the rtl for the function being compiled.
148218334Speter   FILE is the file to write assembler code to.
148318334Speter   OPTIMIZE is nonzero if we should eliminate redundant
148418334Speter     test and compare insns.  */
148518334Speter
148618334Spetervoid
148718334Speterfinal_start_function (first, file, optimize)
148818334Speter     rtx first;
148918334Speter     FILE *file;
149090087Sobrien     int optimize ATTRIBUTE_UNUSED;
149118334Speter{
149218334Speter  block_depth = 0;
149318334Speter
149418334Speter  this_is_asm_operands = 0;
149518334Speter
149618334Speter#ifdef NON_SAVING_SETJMP
149718334Speter  /* A function that calls setjmp should save and restore all the
149818334Speter     call-saved registers on a system where longjmp clobbers them.  */
149918334Speter  if (NON_SAVING_SETJMP && current_function_calls_setjmp)
150018334Speter    {
150118334Speter      int i;
150218334Speter
150318334Speter      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
150452515Sobrien	if (!call_used_regs[i])
150518334Speter	  regs_ever_live[i] = 1;
150618334Speter    }
150718334Speter#endif
150890087Sobrien
150918334Speter  if (NOTE_LINE_NUMBER (first) != NOTE_INSN_DELETED)
151090087Sobrien    notice_source_line (first);
151190087Sobrien  high_block_linenum = high_function_linenum = last_linenum;
151218334Speter
151390087Sobrien  (*debug_hooks->begin_prologue) (last_linenum, last_filename);
151450503Sobrien
151590087Sobrien#if defined (DWARF2_UNWIND_INFO) || defined (IA64_UNWIND_INFO)
151690087Sobrien  if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG)
151790087Sobrien    dwarf2out_begin_prologue (0, NULL);
151818334Speter#endif
151918334Speter
152018334Speter#ifdef LEAF_REG_REMAP
152152515Sobrien  if (current_function_uses_only_leaf_regs)
152218334Speter    leaf_renumber_regs (first);
152318334Speter#endif
152418334Speter
152518334Speter  /* The Sun386i and perhaps other machines don't work right
152618334Speter     if the profiling code comes after the prologue.  */
152718334Speter#ifdef PROFILE_BEFORE_PROLOGUE
152890087Sobrien  if (current_function_profile)
152918334Speter    profile_function (file);
153018334Speter#endif /* PROFILE_BEFORE_PROLOGUE */
153118334Speter
153250503Sobrien#if defined (DWARF2_UNWIND_INFO) && defined (HAVE_prologue)
153350503Sobrien  if (dwarf2out_do_frame ())
153450503Sobrien    dwarf2out_frame_debug (NULL_RTX);
153550503Sobrien#endif
153650503Sobrien
153790087Sobrien  /* If debugging, assign block numbers to all of the blocks in this
153890087Sobrien     function.  */
153990087Sobrien  if (write_symbols)
154090087Sobrien    {
154190087Sobrien      remove_unnecessary_notes ();
154290087Sobrien      reorder_blocks ();
154390087Sobrien      number_blocks (current_function_decl);
154490087Sobrien      /* We never actually put out begin/end notes for the top-level
154590087Sobrien	 block in the function.  But, conceptually, that block is
154690087Sobrien	 always needed.  */
154790087Sobrien      TREE_ASM_WRITTEN (DECL_INITIAL (current_function_decl)) = 1;
154890087Sobrien    }
154990087Sobrien
155018334Speter  /* First output the function prologue: code to set up the stack frame.  */
155190087Sobrien  (*targetm.asm_out.function_prologue) (file, get_frame_size ());
155218334Speter
155390087Sobrien#ifdef VMS_DEBUGGING_INFO
155490087Sobrien  /* Output label after the prologue of the function.  */
155590087Sobrien  if (write_symbols == VMS_DEBUG || write_symbols == VMS_AND_DWARF2_DEBUG)
155690087Sobrien    vmsdbgout_after_prologue ();
155718334Speter#endif
155818334Speter
155918334Speter  /* If the machine represents the prologue as RTL, the profiling code must
156018334Speter     be emitted when NOTE_INSN_PROLOGUE_END is scanned.  */
156118334Speter#ifdef HAVE_prologue
156218334Speter  if (! HAVE_prologue)
156318334Speter#endif
156418334Speter    profile_after_prologue (file);
156518334Speter}
156618334Speter
156718334Speterstatic void
156818334Speterprofile_after_prologue (file)
156990087Sobrien     FILE *file ATTRIBUTE_UNUSED;
157018334Speter{
157118334Speter#ifndef PROFILE_BEFORE_PROLOGUE
157290087Sobrien  if (current_function_profile)
157318334Speter    profile_function (file);
157418334Speter#endif /* not PROFILE_BEFORE_PROLOGUE */
157518334Speter}
157618334Speter
157718334Speterstatic void
157818334Speterprofile_function (file)
157990087Sobrien     FILE *file ATTRIBUTE_UNUSED;
158018334Speter{
158174478Sobrien#ifndef NO_PROFILE_COUNTERS
158250503Sobrien  int align = MIN (BIGGEST_ALIGNMENT, LONG_TYPE_SIZE);
158374478Sobrien#endif
158450503Sobrien#if defined(ASM_OUTPUT_REG_PUSH)
158550503Sobrien#if defined(STRUCT_VALUE_INCOMING_REGNUM) || defined(STRUCT_VALUE_REGNUM)
158618334Speter  int sval = current_function_returns_struct;
158750503Sobrien#endif
158850503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) || defined(STATIC_CHAIN_REGNUM)
158918334Speter  int cxt = current_function_needs_context;
159050503Sobrien#endif
159150503Sobrien#endif /* ASM_OUTPUT_REG_PUSH */
159218334Speter
159374478Sobrien#ifndef NO_PROFILE_COUNTERS
159418334Speter  data_section ();
159518334Speter  ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
159696281Sobrien  ASM_OUTPUT_INTERNAL_LABEL (file, "LP", current_function_profile_label_no);
159790087Sobrien  assemble_integer (const0_rtx, LONG_TYPE_SIZE / BITS_PER_UNIT, align, 1);
159874478Sobrien#endif
159918334Speter
160050503Sobrien  function_section (current_function_decl);
160118334Speter
160250503Sobrien#if defined(STRUCT_VALUE_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
160318334Speter  if (sval)
160418334Speter    ASM_OUTPUT_REG_PUSH (file, STRUCT_VALUE_INCOMING_REGNUM);
160518334Speter#else
160650503Sobrien#if defined(STRUCT_VALUE_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
160718334Speter  if (sval)
160850503Sobrien    {
160950503Sobrien      ASM_OUTPUT_REG_PUSH (file, STRUCT_VALUE_REGNUM);
161050503Sobrien    }
161118334Speter#endif
161218334Speter#endif
161318334Speter
161450503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
161518334Speter  if (cxt)
161618334Speter    ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_INCOMING_REGNUM);
161718334Speter#else
161850503Sobrien#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
161918334Speter  if (cxt)
162050503Sobrien    {
162150503Sobrien      ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_REGNUM);
162250503Sobrien    }
162318334Speter#endif
162418334Speter#endif
162518334Speter
162696281Sobrien  FUNCTION_PROFILER (file, current_function_profile_label_no);
162718334Speter
162850503Sobrien#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
162918334Speter  if (cxt)
163018334Speter    ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_INCOMING_REGNUM);
163118334Speter#else
163250503Sobrien#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
163318334Speter  if (cxt)
163450503Sobrien    {
163550503Sobrien      ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_REGNUM);
163650503Sobrien    }
163718334Speter#endif
163818334Speter#endif
163918334Speter
164050503Sobrien#if defined(STRUCT_VALUE_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
164118334Speter  if (sval)
164218334Speter    ASM_OUTPUT_REG_POP (file, STRUCT_VALUE_INCOMING_REGNUM);
164318334Speter#else
164450503Sobrien#if defined(STRUCT_VALUE_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
164518334Speter  if (sval)
164650503Sobrien    {
164750503Sobrien      ASM_OUTPUT_REG_POP (file, STRUCT_VALUE_REGNUM);
164850503Sobrien    }
164918334Speter#endif
165018334Speter#endif
165118334Speter}
165218334Speter
165318334Speter/* Output assembler code for the end of a function.
165418334Speter   For clarity, args are same as those of `final_start_function'
165518334Speter   even though not all of them are needed.  */
165618334Speter
165718334Spetervoid
165890087Sobrienfinal_end_function ()
165918334Speter{
166090087Sobrien  app_disable ();
166118334Speter
166290087Sobrien  (*debug_hooks->end_function) (high_function_linenum);
166318334Speter
166418334Speter  /* Finally, output the function epilogue:
166518334Speter     code to restore the stack frame and return to the caller.  */
166690087Sobrien  (*targetm.asm_out.function_epilogue) (asm_out_file, get_frame_size ());
166718334Speter
166890087Sobrien  /* And debug output.  */
166990087Sobrien  (*debug_hooks->end_epilogue) ();
167090087Sobrien
167190087Sobrien#if defined (DWARF2_UNWIND_INFO)
167290087Sobrien  if (write_symbols != DWARF2_DEBUG && write_symbols != VMS_AND_DWARF2_DEBUG
167390087Sobrien      && dwarf2out_do_frame ())
167450503Sobrien    dwarf2out_end_epilogue ();
167550503Sobrien#endif
167618334Speter}
167718334Speter
167818334Speter/* Output assembler code for some insns: all or part of a function.
167918334Speter   For description of args, see `final_start_function', above.
168018334Speter
168118334Speter   PRESCAN is 1 if we are not really outputting,
168218334Speter     just scanning as if we were outputting.
168318334Speter   Prescanning deletes and rearranges insns just like ordinary output.
168418334Speter   PRESCAN is -2 if we are outputting after having prescanned.
168518334Speter   In this case, don't try to delete or rearrange insns
168618334Speter   because that has already been done.
168718334Speter   Prescanning is done only on certain machines.  */
168818334Speter
168918334Spetervoid
169018334Speterfinal (first, file, optimize, prescan)
169118334Speter     rtx first;
169218334Speter     FILE *file;
169318334Speter     int optimize;
169418334Speter     int prescan;
169518334Speter{
169690087Sobrien  rtx insn;
169718334Speter  int max_line = 0;
169850503Sobrien  int max_uid = 0;
169918334Speter
170018334Speter  last_ignored_compare = 0;
170118334Speter  new_block = 1;
170218334Speter
170318334Speter  /* Make a map indicating which line numbers appear in this function.
170418334Speter     When producing SDB debugging info, delete troublesome line number
170518334Speter     notes from inlined functions in other files as well as duplicate
170618334Speter     line number notes.  */
170718334Speter#ifdef SDB_DEBUGGING_INFO
170818334Speter  if (write_symbols == SDB_DEBUG)
170918334Speter    {
171018334Speter      rtx last = 0;
171118334Speter      for (insn = first; insn; insn = NEXT_INSN (insn))
171218334Speter	if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
171318334Speter	  {
171418334Speter	    if ((RTX_INTEGRATED_P (insn)
171518334Speter		 && strcmp (NOTE_SOURCE_FILE (insn), main_input_filename) != 0)
171618334Speter		 || (last != 0
171718334Speter		     && NOTE_LINE_NUMBER (insn) == NOTE_LINE_NUMBER (last)
171818334Speter		     && NOTE_SOURCE_FILE (insn) == NOTE_SOURCE_FILE (last)))
171918334Speter	      {
172090087Sobrien		delete_insn (insn);	/* Use delete_note.  */
172118334Speter		continue;
172218334Speter	      }
172318334Speter	    last = insn;
172418334Speter	    if (NOTE_LINE_NUMBER (insn) > max_line)
172518334Speter	      max_line = NOTE_LINE_NUMBER (insn);
172618334Speter	  }
172718334Speter    }
172818334Speter  else
172918334Speter#endif
173018334Speter    {
173118334Speter      for (insn = first; insn; insn = NEXT_INSN (insn))
173218334Speter	if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > max_line)
173318334Speter	  max_line = NOTE_LINE_NUMBER (insn);
173418334Speter    }
173518334Speter
173690087Sobrien  line_note_exists = (char *) xcalloc (max_line + 1, sizeof (char));
173718334Speter
173818334Speter  for (insn = first; insn; insn = NEXT_INSN (insn))
173950503Sobrien    {
174050503Sobrien      if (INSN_UID (insn) > max_uid)       /* find largest UID */
174190087Sobrien	max_uid = INSN_UID (insn);
174250503Sobrien      if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
174390087Sobrien	line_note_exists[NOTE_LINE_NUMBER (insn)] = 1;
174452515Sobrien#ifdef HAVE_cc0
174552515Sobrien      /* If CC tracking across branches is enabled, record the insn which
174652515Sobrien	 jumps to each branch only reached from one place.  */
174752515Sobrien      if (optimize && GET_CODE (insn) == JUMP_INSN)
174852515Sobrien	{
174952515Sobrien	  rtx lab = JUMP_LABEL (insn);
175052515Sobrien	  if (lab && LABEL_NUSES (lab) == 1)
175152515Sobrien	    {
175252515Sobrien	      LABEL_REFS (lab) = insn;
175352515Sobrien	    }
175452515Sobrien	}
175552515Sobrien#endif
175650503Sobrien    }
175718334Speter
175818334Speter  init_recog ();
175918334Speter
176018334Speter  CC_STATUS_INIT;
176118334Speter
176218334Speter  /* Output the insns.  */
176318334Speter  for (insn = NEXT_INSN (first); insn;)
176450503Sobrien    {
176550503Sobrien#ifdef HAVE_ATTR_length
176690087Sobrien      if ((unsigned) INSN_UID (insn) >= INSN_ADDRESSES_SIZE ())
176790087Sobrien	{
176890087Sobrien#ifdef STACK_REGS
176990087Sobrien	  /* Irritatingly, the reg-stack pass is creating new instructions
177090087Sobrien	     and because of REG_DEAD note abuse it has to run after
177190087Sobrien	     shorten_branches.  Fake address of -1 then.  */
177290087Sobrien	  insn_current_address = -1;
177390087Sobrien#else
177490087Sobrien	  /* This can be triggered by bugs elsewhere in the compiler if
177590087Sobrien	     new insns are created after init_insn_lengths is called.  */
177690087Sobrien	  abort ();
177750503Sobrien#endif
177890087Sobrien	}
177990087Sobrien      else
178090087Sobrien	insn_current_address = INSN_ADDRESSES (INSN_UID (insn));
178190087Sobrien#endif /* HAVE_ATTR_length */
178290087Sobrien
178350503Sobrien      insn = final_scan_insn (insn, file, optimize, prescan, 0);
178450503Sobrien    }
178518334Speter
178690087Sobrien  free (line_note_exists);
178790087Sobrien  line_note_exists = NULL;
178890087Sobrien}
178990087Sobrien
179090087Sobrienconst char *
179190087Sobrienget_insn_template (code, insn)
179290087Sobrien     int code;
179390087Sobrien     rtx insn;
179490087Sobrien{
179590087Sobrien  const void *output = insn_data[code].output;
179690087Sobrien  switch (insn_data[code].output_format)
179790087Sobrien    {
179890087Sobrien    case INSN_OUTPUT_FORMAT_SINGLE:
179990087Sobrien      return (const char *) output;
180090087Sobrien    case INSN_OUTPUT_FORMAT_MULTI:
180190087Sobrien      return ((const char *const *) output)[which_alternative];
180290087Sobrien    case INSN_OUTPUT_FORMAT_FUNCTION:
180390087Sobrien      if (insn == NULL)
180490087Sobrien	abort ();
180590087Sobrien      return (*(insn_output_fn) output) (recog_data.operand, insn);
180650503Sobrien
180790087Sobrien    default:
180890087Sobrien      abort ();
180990087Sobrien    }
181018334Speter}
181190087Sobrien
181218334Speter/* The final scan for one insn, INSN.
181318334Speter   Args are same as in `final', except that INSN
181418334Speter   is the insn being scanned.
181518334Speter   Value returned is the next insn to be scanned.
181618334Speter
181718334Speter   NOPEEPHOLES is the flag to disallow peephole processing (currently
181818334Speter   used for within delayed branch sequence output).  */
181918334Speter
182018334Speterrtx
182118334Speterfinal_scan_insn (insn, file, optimize, prescan, nopeepholes)
182218334Speter     rtx insn;
182318334Speter     FILE *file;
182490087Sobrien     int optimize ATTRIBUTE_UNUSED;
182518334Speter     int prescan;
182690087Sobrien     int nopeepholes ATTRIBUTE_UNUSED;
182718334Speter{
182850503Sobrien#ifdef HAVE_cc0
182950503Sobrien  rtx set;
183050503Sobrien#endif
183150503Sobrien
183218334Speter  insn_counter++;
183318334Speter
183418334Speter  /* Ignore deleted insns.  These can occur when we split insns (due to a
183518334Speter     template of "#") while not optimizing.  */
183618334Speter  if (INSN_DELETED_P (insn))
183718334Speter    return NEXT_INSN (insn);
183818334Speter
183918334Speter  switch (GET_CODE (insn))
184018334Speter    {
184118334Speter    case NOTE:
184218334Speter      if (prescan > 0)
184318334Speter	break;
184418334Speter
184590087Sobrien      switch (NOTE_LINE_NUMBER (insn))
184618334Speter	{
184790087Sobrien	case NOTE_INSN_DELETED:
184890087Sobrien	case NOTE_INSN_LOOP_BEG:
184990087Sobrien	case NOTE_INSN_LOOP_END:
185096281Sobrien	case NOTE_INSN_LOOP_END_TOP_COND:
185190087Sobrien	case NOTE_INSN_LOOP_CONT:
185290087Sobrien	case NOTE_INSN_LOOP_VTOP:
185390087Sobrien	case NOTE_INSN_FUNCTION_END:
185490087Sobrien	case NOTE_INSN_REPEATED_LINE_NUMBER:
185590087Sobrien	case NOTE_INSN_RANGE_BEG:
185690087Sobrien	case NOTE_INSN_RANGE_END:
185790087Sobrien	case NOTE_INSN_LIVE:
185890087Sobrien	case NOTE_INSN_EXPECTED_VALUE:
185918334Speter	  break;
186018334Speter
186190087Sobrien	case NOTE_INSN_BASIC_BLOCK:
186290087Sobrien#ifdef IA64_UNWIND_INFO
186390087Sobrien	  IA64_UNWIND_EMIT (asm_out_file, insn);
186450503Sobrien#endif
186590087Sobrien	  if (flag_debug_asm)
186690087Sobrien	    fprintf (asm_out_file, "\t%s basic block %d\n",
186790087Sobrien		     ASM_COMMENT_START, NOTE_BASIC_BLOCK (insn)->index);
186850503Sobrien	  break;
186950503Sobrien
187090087Sobrien	case NOTE_INSN_EH_REGION_BEG:
187190087Sobrien	  ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LEHB",
187290087Sobrien				  NOTE_EH_HANDLER (insn));
187390087Sobrien	  break;
187490087Sobrien
187590087Sobrien	case NOTE_INSN_EH_REGION_END:
187690087Sobrien	  ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LEHE",
187790087Sobrien				  NOTE_EH_HANDLER (insn));
187890087Sobrien	  break;
187990087Sobrien
188090087Sobrien	case NOTE_INSN_PROLOGUE_END:
188190087Sobrien	  (*targetm.asm_out.function_end_prologue) (file);
188218334Speter	  profile_after_prologue (file);
188318334Speter	  break;
188418334Speter
188590087Sobrien	case NOTE_INSN_EPILOGUE_BEG:
188690087Sobrien	  (*targetm.asm_out.function_begin_epilogue) (file);
188718334Speter	  break;
188818334Speter
188990087Sobrien	case NOTE_INSN_FUNCTION_BEG:
189090087Sobrien	  app_disable ();
189190087Sobrien	  (*debug_hooks->end_prologue) (last_linenum);
189218334Speter	  break;
189390087Sobrien
189490087Sobrien	case NOTE_INSN_BLOCK_BEG:
189590087Sobrien	  if (debug_info_level == DINFO_LEVEL_NORMAL
189618334Speter	      || debug_info_level == DINFO_LEVEL_VERBOSE
189718334Speter	      || write_symbols == DWARF_DEBUG
189890087Sobrien	      || write_symbols == DWARF2_DEBUG
189990087Sobrien	      || write_symbols == VMS_AND_DWARF2_DEBUG
190090087Sobrien	      || write_symbols == VMS_DEBUG)
190190087Sobrien	    {
190290087Sobrien	      int n = BLOCK_NUMBER (NOTE_BLOCK (insn));
190318334Speter
190490087Sobrien	      app_disable ();
190590087Sobrien	      ++block_depth;
190690087Sobrien	      high_block_linenum = last_linenum;
190790087Sobrien
190890087Sobrien	      /* Output debugging info about the symbol-block beginning.  */
190990087Sobrien	      (*debug_hooks->begin_block) (last_linenum, n);
191090087Sobrien
191190087Sobrien	      /* Mark this block as output.  */
191290087Sobrien	      TREE_ASM_WRITTEN (NOTE_BLOCK (insn)) = 1;
191318334Speter	    }
191490087Sobrien	  break;
191518334Speter
191690087Sobrien	case NOTE_INSN_BLOCK_END:
191790087Sobrien	  if (debug_info_level == DINFO_LEVEL_NORMAL
191890087Sobrien	      || debug_info_level == DINFO_LEVEL_VERBOSE
191990087Sobrien	      || write_symbols == DWARF_DEBUG
192090087Sobrien	      || write_symbols == DWARF2_DEBUG
192190087Sobrien	      || write_symbols == VMS_AND_DWARF2_DEBUG
192290087Sobrien	      || write_symbols == VMS_DEBUG)
192390087Sobrien	    {
192490087Sobrien	      int n = BLOCK_NUMBER (NOTE_BLOCK (insn));
192518334Speter
192690087Sobrien	      app_disable ();
192718334Speter
192890087Sobrien	      /* End of a symbol-block.  */
192990087Sobrien	      --block_depth;
193090087Sobrien	      if (block_depth < 0)
193190087Sobrien		abort ();
193218334Speter
193390087Sobrien	      (*debug_hooks->end_block) (high_block_linenum, n);
193490087Sobrien	    }
193590087Sobrien	  break;
193618334Speter
193790087Sobrien	case NOTE_INSN_DELETED_LABEL:
193890087Sobrien	  /* Emit the label.  We may have deleted the CODE_LABEL because
193990087Sobrien	     the label could be proved to be unreachable, though still
194090087Sobrien	     referenced (in the form of having its address taken.  */
194190087Sobrien	  ASM_OUTPUT_DEBUG_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
194290087Sobrien	  break;
194318334Speter
194490087Sobrien	case 0:
194590087Sobrien	  break;
194618334Speter
194790087Sobrien	default:
194890087Sobrien	  if (NOTE_LINE_NUMBER (insn) <= 0)
194990087Sobrien	    abort ();
195018334Speter
195190087Sobrien	  /* This note is a line-number.  */
195290087Sobrien	  {
195390087Sobrien	    rtx note;
195490087Sobrien	    int note_after = 0;
195518334Speter
195690087Sobrien	    /* If there is anything real after this note, output it.
195790087Sobrien	       If another line note follows, omit this one.  */
195890087Sobrien	    for (note = NEXT_INSN (insn); note; note = NEXT_INSN (note))
195990087Sobrien	      {
196090087Sobrien		if (GET_CODE (note) != NOTE && GET_CODE (note) != CODE_LABEL)
196118334Speter		  break;
196218334Speter
196390087Sobrien		/* These types of notes can be significant
196490087Sobrien		   so make sure the preceding line number stays.  */
196590087Sobrien		else if (GET_CODE (note) == NOTE
196690087Sobrien			 && (NOTE_LINE_NUMBER (note) == NOTE_INSN_BLOCK_BEG
196790087Sobrien			     || NOTE_LINE_NUMBER (note) == NOTE_INSN_BLOCK_END
196890087Sobrien			     || NOTE_LINE_NUMBER (note) == NOTE_INSN_FUNCTION_BEG))
196990087Sobrien		  break;
197090087Sobrien		else if (GET_CODE (note) == NOTE && NOTE_LINE_NUMBER (note) > 0)
197190087Sobrien		  {
197290087Sobrien		    /* Another line note follows; we can delete this note
197390087Sobrien		       if no intervening line numbers have notes elsewhere.  */
197490087Sobrien		    int num;
197590087Sobrien		    for (num = NOTE_LINE_NUMBER (insn) + 1;
197690087Sobrien		         num < NOTE_LINE_NUMBER (note);
197790087Sobrien		         num++)
197890087Sobrien		      if (line_note_exists[num])
197990087Sobrien			break;
198090087Sobrien
198190087Sobrien		    if (num >= NOTE_LINE_NUMBER (note))
198290087Sobrien		      note_after = 1;
198390087Sobrien		    break;
198490087Sobrien		  }
198590087Sobrien	      }
198690087Sobrien
198790087Sobrien	    /* Output this line note if it is the first or the last line
198890087Sobrien	       note in a row.  */
198990087Sobrien	    if (!note_after)
199090087Sobrien	      {
199190087Sobrien		notice_source_line (insn);
199290087Sobrien		(*debug_hooks->source_line) (last_linenum, last_filename);
199390087Sobrien	      }
199490087Sobrien	  }
199590087Sobrien	  break;
199618334Speter	}
199718334Speter      break;
199818334Speter
199918334Speter    case BARRIER:
200090087Sobrien#if defined (DWARF2_UNWIND_INFO)
200190087Sobrien      if (dwarf2out_do_frame ())
200290087Sobrien	dwarf2out_frame_debug (insn);
200318334Speter#endif
200418334Speter      break;
200518334Speter
200618334Speter    case CODE_LABEL:
200750503Sobrien      /* The target port might emit labels in the output function for
200850503Sobrien	 some insn, e.g. sh.c output_branchy_insn.  */
200950503Sobrien      if (CODE_LABEL_NUMBER (insn) <= max_labelno)
201050503Sobrien	{
201150503Sobrien	  int align = LABEL_TO_ALIGNMENT (insn);
201250503Sobrien#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
201350503Sobrien	  int max_skip = LABEL_TO_MAX_SKIP (insn);
201450503Sobrien#endif
201550503Sobrien
201650503Sobrien	  if (align && NEXT_INSN (insn))
201790087Sobrien	    {
201850503Sobrien#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
201990087Sobrien	      ASM_OUTPUT_MAX_SKIP_ALIGN (file, align, max_skip);
202050503Sobrien#else
202190087Sobrien	      ASM_OUTPUT_ALIGN (file, align);
202250503Sobrien#endif
202390087Sobrien	    }
202450503Sobrien	}
202552515Sobrien#ifdef HAVE_cc0
202618334Speter      CC_STATUS_INIT;
202752515Sobrien      /* If this label is reached from only one place, set the condition
202852515Sobrien	 codes from the instruction just before the branch.  */
202952515Sobrien
203052515Sobrien      /* Disabled because some insns set cc_status in the C output code
203152515Sobrien	 and NOTICE_UPDATE_CC alone can set incorrect status.  */
203252515Sobrien      if (0 /* optimize && LABEL_NUSES (insn) == 1*/)
203352515Sobrien	{
203452515Sobrien	  rtx jump = LABEL_REFS (insn);
203552515Sobrien	  rtx barrier = prev_nonnote_insn (insn);
203652515Sobrien	  rtx prev;
203752515Sobrien	  /* If the LABEL_REFS field of this label has been set to point
203852515Sobrien	     at a branch, the predecessor of the branch is a regular
203952515Sobrien	     insn, and that branch is the only way to reach this label,
204052515Sobrien	     set the condition codes based on the branch and its
204152515Sobrien	     predecessor.  */
204252515Sobrien	  if (barrier && GET_CODE (barrier) == BARRIER
204352515Sobrien	      && jump && GET_CODE (jump) == JUMP_INSN
204452515Sobrien	      && (prev = prev_nonnote_insn (jump))
204552515Sobrien	      && GET_CODE (prev) == INSN)
204652515Sobrien	    {
204752515Sobrien	      NOTICE_UPDATE_CC (PATTERN (prev), prev);
204852515Sobrien	      NOTICE_UPDATE_CC (PATTERN (jump), jump);
204952515Sobrien	    }
205052515Sobrien	}
205152515Sobrien#endif
205218334Speter      if (prescan > 0)
205318334Speter	break;
205418334Speter      new_block = 1;
205550503Sobrien
205650503Sobrien#ifdef FINAL_PRESCAN_LABEL
205790087Sobrien      FINAL_PRESCAN_INSN (insn, NULL, 0);
205850503Sobrien#endif
205950503Sobrien
206090087Sobrien      if (LABEL_NAME (insn))
206190087Sobrien	(*debug_hooks->label) (insn);
206290087Sobrien
206318334Speter      if (app_on)
206418334Speter	{
206550503Sobrien	  fputs (ASM_APP_OFF, file);
206618334Speter	  app_on = 0;
206718334Speter	}
206818334Speter      if (NEXT_INSN (insn) != 0
206918334Speter	  && GET_CODE (NEXT_INSN (insn)) == JUMP_INSN)
207018334Speter	{
207118334Speter	  rtx nextbody = PATTERN (NEXT_INSN (insn));
207218334Speter
207318334Speter	  /* If this label is followed by a jump-table,
207418334Speter	     make sure we put the label in the read-only section.  Also
207518334Speter	     possibly write the label and jump table together.  */
207618334Speter
207718334Speter	  if (GET_CODE (nextbody) == ADDR_VEC
207818334Speter	      || GET_CODE (nextbody) == ADDR_DIFF_VEC)
207918334Speter	    {
208052515Sobrien#if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)
208152515Sobrien	      /* In this case, the case vector is being moved by the
208252515Sobrien		 target, so don't output the label at all.  Leave that
208352515Sobrien		 to the back end macros.  */
208452515Sobrien#else
208550503Sobrien	      if (! JUMP_TABLES_IN_TEXT_SECTION)
208650503Sobrien		{
208790087Sobrien		  int log_align;
208890087Sobrien
208950503Sobrien		  readonly_data_section ();
209090087Sobrien
209190087Sobrien#ifdef ADDR_VEC_ALIGN
209290087Sobrien		  log_align = ADDR_VEC_ALIGN (NEXT_INSN (insn));
209390087Sobrien#else
209490087Sobrien		  log_align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
209590087Sobrien#endif
209690087Sobrien		  ASM_OUTPUT_ALIGN (file, log_align);
209750503Sobrien		}
209850503Sobrien	      else
209950503Sobrien		function_section (current_function_decl);
210050503Sobrien
210118334Speter#ifdef ASM_OUTPUT_CASE_LABEL
210218334Speter	      ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn),
210318334Speter				     NEXT_INSN (insn));
210418334Speter#else
210590087Sobrien	      if (LABEL_ALTERNATE_NAME (insn))
210690087Sobrien		ASM_OUTPUT_ALTERNATE_LABEL_NAME (file, insn);
210790087Sobrien	      else
210890087Sobrien		ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
210918334Speter#endif
211052515Sobrien#endif
211118334Speter	      break;
211218334Speter	    }
211318334Speter	}
211490087Sobrien      if (LABEL_ALTERNATE_NAME (insn))
211590087Sobrien	ASM_OUTPUT_ALTERNATE_LABEL_NAME (file, insn);
211690087Sobrien      else
211790087Sobrien	ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (insn));
211818334Speter      break;
211918334Speter
212018334Speter    default:
212118334Speter      {
212290087Sobrien	rtx body = PATTERN (insn);
212318334Speter	int insn_code_number;
212452515Sobrien	const char *template;
212518334Speter	rtx note;
212618334Speter
212718334Speter	/* An INSN, JUMP_INSN or CALL_INSN.
212818334Speter	   First check for special kinds that recog doesn't recognize.  */
212918334Speter
213018334Speter	if (GET_CODE (body) == USE /* These are just declarations */
213118334Speter	    || GET_CODE (body) == CLOBBER)
213218334Speter	  break;
213318334Speter
213418334Speter#ifdef HAVE_cc0
213518334Speter	/* If there is a REG_CC_SETTER note on this insn, it means that
213618334Speter	   the setting of the condition code was done in the delay slot
213718334Speter	   of the insn that branched here.  So recover the cc status
213818334Speter	   from the insn that set it.  */
213918334Speter
214018334Speter	note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX);
214118334Speter	if (note)
214218334Speter	  {
214318334Speter	    NOTICE_UPDATE_CC (PATTERN (XEXP (note, 0)), XEXP (note, 0));
214418334Speter	    cc_prev_status = cc_status;
214518334Speter	  }
214618334Speter#endif
214718334Speter
214818334Speter	/* Detect insns that are really jump-tables
214918334Speter	   and output them as such.  */
215018334Speter
215118334Speter	if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
215218334Speter	  {
215352515Sobrien#if !(defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC))
215490087Sobrien	    int vlen, idx;
215552515Sobrien#endif
215618334Speter
215718334Speter	    if (prescan > 0)
215818334Speter	      break;
215918334Speter
216018334Speter	    if (app_on)
216118334Speter	      {
216250503Sobrien		fputs (ASM_APP_OFF, file);
216318334Speter		app_on = 0;
216418334Speter	      }
216518334Speter
216652515Sobrien#if defined(ASM_OUTPUT_ADDR_VEC) || defined(ASM_OUTPUT_ADDR_DIFF_VEC)
216752515Sobrien	    if (GET_CODE (body) == ADDR_VEC)
216852515Sobrien	      {
216952515Sobrien#ifdef ASM_OUTPUT_ADDR_VEC
217052515Sobrien		ASM_OUTPUT_ADDR_VEC (PREV_INSN (insn), body);
217152515Sobrien#else
217290087Sobrien		abort ();
217352515Sobrien#endif
217452515Sobrien	      }
217552515Sobrien	    else
217652515Sobrien	      {
217752515Sobrien#ifdef ASM_OUTPUT_ADDR_DIFF_VEC
217852515Sobrien		ASM_OUTPUT_ADDR_DIFF_VEC (PREV_INSN (insn), body);
217952515Sobrien#else
218090087Sobrien		abort ();
218152515Sobrien#endif
218252515Sobrien	      }
218352515Sobrien#else
218418334Speter	    vlen = XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC);
218518334Speter	    for (idx = 0; idx < vlen; idx++)
218618334Speter	      {
218718334Speter		if (GET_CODE (body) == ADDR_VEC)
218818334Speter		  {
218918334Speter#ifdef ASM_OUTPUT_ADDR_VEC_ELT
219018334Speter		    ASM_OUTPUT_ADDR_VEC_ELT
219118334Speter		      (file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0)));
219218334Speter#else
219318334Speter		    abort ();
219418334Speter#endif
219518334Speter		  }
219618334Speter		else
219718334Speter		  {
219818334Speter#ifdef ASM_OUTPUT_ADDR_DIFF_ELT
219918334Speter		    ASM_OUTPUT_ADDR_DIFF_ELT
220018334Speter		      (file,
220150503Sobrien		       body,
220218334Speter		       CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)),
220318334Speter		       CODE_LABEL_NUMBER (XEXP (XEXP (body, 0), 0)));
220418334Speter#else
220518334Speter		    abort ();
220618334Speter#endif
220718334Speter		  }
220818334Speter	      }
220918334Speter#ifdef ASM_OUTPUT_CASE_END
221018334Speter	    ASM_OUTPUT_CASE_END (file,
221118334Speter				 CODE_LABEL_NUMBER (PREV_INSN (insn)),
221218334Speter				 insn);
221318334Speter#endif
221452515Sobrien#endif
221518334Speter
221618334Speter	    function_section (current_function_decl);
221718334Speter
221818334Speter	    break;
221918334Speter	  }
222018334Speter
222118334Speter	if (GET_CODE (body) == ASM_INPUT)
222218334Speter	  {
222390087Sobrien	    const char *string = XSTR (body, 0);
222490087Sobrien
222518334Speter	    /* There's no telling what that did to the condition codes.  */
222618334Speter	    CC_STATUS_INIT;
222718334Speter	    if (prescan > 0)
222818334Speter	      break;
222990087Sobrien
223090087Sobrien	    if (string[0])
223118334Speter	      {
223290087Sobrien		if (! app_on)
223390087Sobrien		  {
223490087Sobrien		    fputs (ASM_APP_ON, file);
223590087Sobrien		    app_on = 1;
223690087Sobrien		  }
223790087Sobrien		fprintf (asm_out_file, "\t%s\n", string);
223818334Speter	      }
223918334Speter	    break;
224018334Speter	  }
224118334Speter
224218334Speter	/* Detect `asm' construct with operands.  */
224318334Speter	if (asm_noperands (body) >= 0)
224418334Speter	  {
224550503Sobrien	    unsigned int noperands = asm_noperands (body);
224618334Speter	    rtx *ops = (rtx *) alloca (noperands * sizeof (rtx));
224790087Sobrien	    const char *string;
224818334Speter
224918334Speter	    /* There's no telling what that did to the condition codes.  */
225018334Speter	    CC_STATUS_INIT;
225118334Speter	    if (prescan > 0)
225218334Speter	      break;
225318334Speter
225418334Speter	    /* Get out the operand values.  */
225590087Sobrien	    string = decode_asm_operands (body, ops, NULL, NULL, NULL);
225618334Speter	    /* Inhibit aborts on what would otherwise be compiler bugs.  */
225718334Speter	    insn_noperands = noperands;
225818334Speter	    this_is_asm_operands = insn;
225918334Speter
226018334Speter	    /* Output the insn using them.  */
226190087Sobrien	    if (string[0])
226290087Sobrien	      {
226390087Sobrien		if (! app_on)
226490087Sobrien		  {
226590087Sobrien		    fputs (ASM_APP_ON, file);
226690087Sobrien		    app_on = 1;
226790087Sobrien		  }
226890087Sobrien	        output_asm_insn (string, ops);
226990087Sobrien	      }
227090087Sobrien
227118334Speter	    this_is_asm_operands = 0;
227218334Speter	    break;
227318334Speter	  }
227418334Speter
227518334Speter	if (prescan <= 0 && app_on)
227618334Speter	  {
227750503Sobrien	    fputs (ASM_APP_OFF, file);
227818334Speter	    app_on = 0;
227918334Speter	  }
228018334Speter
228118334Speter	if (GET_CODE (body) == SEQUENCE)
228218334Speter	  {
228318334Speter	    /* A delayed-branch sequence */
228490087Sobrien	    int i;
228518334Speter	    rtx next;
228618334Speter
228718334Speter	    if (prescan > 0)
228818334Speter	      break;
228918334Speter	    final_sequence = body;
229018334Speter
229118334Speter	    /* The first insn in this SEQUENCE might be a JUMP_INSN that will
229218334Speter	       force the restoration of a comparison that was previously
229318334Speter	       thought unnecessary.  If that happens, cancel this sequence
229418334Speter	       and cause that insn to be restored.  */
229518334Speter
229618334Speter	    next = final_scan_insn (XVECEXP (body, 0, 0), file, 0, prescan, 1);
229718334Speter	    if (next != XVECEXP (body, 0, 1))
229818334Speter	      {
229918334Speter		final_sequence = 0;
230018334Speter		return next;
230118334Speter	      }
230218334Speter
230318334Speter	    for (i = 1; i < XVECLEN (body, 0); i++)
230418334Speter	      {
230518334Speter		rtx insn = XVECEXP (body, 0, i);
230618334Speter		rtx next = NEXT_INSN (insn);
230718334Speter		/* We loop in case any instruction in a delay slot gets
230818334Speter		   split.  */
230918334Speter		do
231018334Speter		  insn = final_scan_insn (insn, file, 0, prescan, 1);
231118334Speter		while (insn != next);
231218334Speter	      }
231318334Speter#ifdef DBR_OUTPUT_SEQEND
231418334Speter	    DBR_OUTPUT_SEQEND (file);
231518334Speter#endif
231618334Speter	    final_sequence = 0;
231718334Speter
231818334Speter	    /* If the insn requiring the delay slot was a CALL_INSN, the
231918334Speter	       insns in the delay slot are actually executed before the
232018334Speter	       called function.  Hence we don't preserve any CC-setting
232118334Speter	       actions in these insns and the CC must be marked as being
232218334Speter	       clobbered by the function.  */
232318334Speter	    if (GET_CODE (XVECEXP (body, 0, 0)) == CALL_INSN)
232450503Sobrien	      {
232550503Sobrien		CC_STATUS_INIT;
232650503Sobrien	      }
232718334Speter	    break;
232818334Speter	  }
232918334Speter
233018334Speter	/* We have a real machine instruction as rtl.  */
233118334Speter
233218334Speter	body = PATTERN (insn);
233318334Speter
233418334Speter#ifdef HAVE_cc0
233590087Sobrien	set = single_set (insn);
233650503Sobrien
233718334Speter	/* Check for redundant test and compare instructions
233818334Speter	   (when the condition codes are already set up as desired).
233918334Speter	   This is done only when optimizing; if not optimizing,
234018334Speter	   it should be possible for the user to alter a variable
234118334Speter	   with the debugger in between statements
234218334Speter	   and the next statement should reexamine the variable
234318334Speter	   to compute the condition codes.  */
234418334Speter
234550503Sobrien	if (optimize)
234618334Speter	  {
234750503Sobrien#if 0
234890087Sobrien	    rtx set = single_set (insn);
234950503Sobrien#endif
235050503Sobrien
235150503Sobrien	    if (set
235250503Sobrien		&& GET_CODE (SET_DEST (set)) == CC0
235350503Sobrien		&& insn != last_ignored_compare)
235418334Speter	      {
235550503Sobrien		if (GET_CODE (SET_SRC (set)) == SUBREG)
235690087Sobrien		  SET_SRC (set) = alter_subreg (&SET_SRC (set));
235750503Sobrien		else if (GET_CODE (SET_SRC (set)) == COMPARE)
235818334Speter		  {
235950503Sobrien		    if (GET_CODE (XEXP (SET_SRC (set), 0)) == SUBREG)
236050503Sobrien		      XEXP (SET_SRC (set), 0)
236190087Sobrien			= alter_subreg (&XEXP (SET_SRC (set), 0));
236250503Sobrien		    if (GET_CODE (XEXP (SET_SRC (set), 1)) == SUBREG)
236350503Sobrien		      XEXP (SET_SRC (set), 1)
236490087Sobrien			= alter_subreg (&XEXP (SET_SRC (set), 1));
236518334Speter		  }
236650503Sobrien		if ((cc_status.value1 != 0
236750503Sobrien		     && rtx_equal_p (SET_SRC (set), cc_status.value1))
236850503Sobrien		    || (cc_status.value2 != 0
236950503Sobrien			&& rtx_equal_p (SET_SRC (set), cc_status.value2)))
237050503Sobrien		  {
237150503Sobrien		    /* Don't delete insn if it has an addressing side-effect.  */
237290087Sobrien		    if (! FIND_REG_INC_NOTE (insn, NULL_RTX)
237350503Sobrien			/* or if anything in it is volatile.  */
237450503Sobrien			&& ! volatile_refs_p (PATTERN (insn)))
237550503Sobrien		      {
237650503Sobrien			/* We don't really delete the insn; just ignore it.  */
237750503Sobrien			last_ignored_compare = insn;
237850503Sobrien			break;
237950503Sobrien		      }
238050503Sobrien		  }
238118334Speter	      }
238218334Speter	  }
238318334Speter#endif
238418334Speter
238518334Speter#ifndef STACK_REGS
238618334Speter	/* Don't bother outputting obvious no-ops, even without -O.
238718334Speter	   This optimization is fast and doesn't interfere with debugging.
238818334Speter	   Don't do this if the insn is in a delay slot, since this
238918334Speter	   will cause an improper number of delay insns to be written.  */
239018334Speter	if (final_sequence == 0
239118334Speter	    && prescan >= 0
239218334Speter	    && GET_CODE (insn) == INSN && GET_CODE (body) == SET
239318334Speter	    && GET_CODE (SET_SRC (body)) == REG
239418334Speter	    && GET_CODE (SET_DEST (body)) == REG
239518334Speter	    && REGNO (SET_SRC (body)) == REGNO (SET_DEST (body)))
239618334Speter	  break;
239718334Speter#endif
239818334Speter
239918334Speter#ifdef HAVE_cc0
240018334Speter	/* If this is a conditional branch, maybe modify it
240118334Speter	   if the cc's are in a nonstandard state
240218334Speter	   so that it accomplishes the same thing that it would
240318334Speter	   do straightforwardly if the cc's were set up normally.  */
240418334Speter
240518334Speter	if (cc_status.flags != 0
240618334Speter	    && GET_CODE (insn) == JUMP_INSN
240718334Speter	    && GET_CODE (body) == SET
240818334Speter	    && SET_DEST (body) == pc_rtx
240918334Speter	    && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE
241018334Speter	    && GET_RTX_CLASS (GET_CODE (XEXP (SET_SRC (body), 0))) == '<'
241118334Speter	    && XEXP (XEXP (SET_SRC (body), 0), 0) == cc0_rtx
241218334Speter	    /* This is done during prescan; it is not done again
241318334Speter	       in final scan when prescan has been done.  */
241418334Speter	    && prescan >= 0)
241518334Speter	  {
241618334Speter	    /* This function may alter the contents of its argument
241718334Speter	       and clear some of the cc_status.flags bits.
241818334Speter	       It may also return 1 meaning condition now always true
241918334Speter	       or -1 meaning condition now always false
242018334Speter	       or 2 meaning condition nontrivial but altered.  */
242190087Sobrien	    int result = alter_cond (XEXP (SET_SRC (body), 0));
242218334Speter	    /* If condition now has fixed value, replace the IF_THEN_ELSE
242318334Speter	       with its then-operand or its else-operand.  */
242418334Speter	    if (result == 1)
242518334Speter	      SET_SRC (body) = XEXP (SET_SRC (body), 1);
242618334Speter	    if (result == -1)
242718334Speter	      SET_SRC (body) = XEXP (SET_SRC (body), 2);
242818334Speter
242918334Speter	    /* The jump is now either unconditional or a no-op.
243018334Speter	       If it has become a no-op, don't try to output it.
243118334Speter	       (It would not be recognized.)  */
243218334Speter	    if (SET_SRC (body) == pc_rtx)
243318334Speter	      {
243490087Sobrien	        delete_insn (insn);
243518334Speter		break;
243618334Speter	      }
243718334Speter	    else if (GET_CODE (SET_SRC (body)) == RETURN)
243818334Speter	      /* Replace (set (pc) (return)) with (return).  */
243918334Speter	      PATTERN (insn) = body = SET_SRC (body);
244018334Speter
244118334Speter	    /* Rerecognize the instruction if it has changed.  */
244218334Speter	    if (result != 0)
244318334Speter	      INSN_CODE (insn) = -1;
244418334Speter	  }
244518334Speter
244618334Speter	/* Make same adjustments to instructions that examine the
244750503Sobrien	   condition codes without jumping and instructions that
244850503Sobrien	   handle conditional moves (if this machine has either one).  */
244918334Speter
245018334Speter	if (cc_status.flags != 0
245150503Sobrien	    && set != 0)
245218334Speter	  {
245350503Sobrien	    rtx cond_rtx, then_rtx, else_rtx;
245490087Sobrien
245550503Sobrien	    if (GET_CODE (insn) != JUMP_INSN
245650503Sobrien		&& GET_CODE (SET_SRC (set)) == IF_THEN_ELSE)
245718334Speter	      {
245850503Sobrien		cond_rtx = XEXP (SET_SRC (set), 0);
245950503Sobrien		then_rtx = XEXP (SET_SRC (set), 1);
246050503Sobrien		else_rtx = XEXP (SET_SRC (set), 2);
246150503Sobrien	      }
246250503Sobrien	    else
246350503Sobrien	      {
246450503Sobrien		cond_rtx = SET_SRC (set);
246550503Sobrien		then_rtx = const_true_rtx;
246650503Sobrien		else_rtx = const0_rtx;
246750503Sobrien	      }
246890087Sobrien
246950503Sobrien	    switch (GET_CODE (cond_rtx))
247050503Sobrien	      {
247118334Speter	      case GTU:
247218334Speter	      case GT:
247318334Speter	      case LTU:
247418334Speter	      case LT:
247518334Speter	      case GEU:
247618334Speter	      case GE:
247718334Speter	      case LEU:
247818334Speter	      case LE:
247918334Speter	      case EQ:
248018334Speter	      case NE:
248118334Speter		{
248290087Sobrien		  int result;
248350503Sobrien		  if (XEXP (cond_rtx, 0) != cc0_rtx)
248418334Speter		    break;
248550503Sobrien		  result = alter_cond (cond_rtx);
248618334Speter		  if (result == 1)
248750503Sobrien		    validate_change (insn, &SET_SRC (set), then_rtx, 0);
248818334Speter		  else if (result == -1)
248950503Sobrien		    validate_change (insn, &SET_SRC (set), else_rtx, 0);
249018334Speter		  else if (result == 2)
249118334Speter		    INSN_CODE (insn) = -1;
249250503Sobrien		  if (SET_DEST (set) == SET_SRC (set))
249390087Sobrien		    delete_insn (insn);
249418334Speter		}
249550503Sobrien		break;
249650503Sobrien
249750503Sobrien	      default:
249850503Sobrien		break;
249918334Speter	      }
250018334Speter	  }
250150503Sobrien
250218334Speter#endif
250318334Speter
250490087Sobrien#ifdef HAVE_peephole
250518334Speter	/* Do machine-specific peephole optimizations if desired.  */
250618334Speter
250718334Speter	if (optimize && !flag_no_peephole && !nopeepholes)
250818334Speter	  {
250918334Speter	    rtx next = peephole (insn);
251018334Speter	    /* When peepholing, if there were notes within the peephole,
251118334Speter	       emit them before the peephole.  */
251218334Speter	    if (next != 0 && next != NEXT_INSN (insn))
251318334Speter	      {
251418334Speter		rtx prev = PREV_INSN (insn);
251518334Speter
251618334Speter		for (note = NEXT_INSN (insn); note != next;
251718334Speter		     note = NEXT_INSN (note))
251818334Speter		  final_scan_insn (note, file, optimize, prescan, nopeepholes);
251918334Speter
252018334Speter		/* In case this is prescan, put the notes
252118334Speter		   in proper position for later rescan.  */
252218334Speter		note = NEXT_INSN (insn);
252318334Speter		PREV_INSN (note) = prev;
252418334Speter		NEXT_INSN (prev) = note;
252518334Speter		NEXT_INSN (PREV_INSN (next)) = insn;
252618334Speter		PREV_INSN (insn) = PREV_INSN (next);
252718334Speter		NEXT_INSN (insn) = next;
252818334Speter		PREV_INSN (next) = insn;
252918334Speter	      }
253018334Speter
253118334Speter	    /* PEEPHOLE might have changed this.  */
253218334Speter	    body = PATTERN (insn);
253318334Speter	  }
253490087Sobrien#endif
253518334Speter
253618334Speter	/* Try to recognize the instruction.
253718334Speter	   If successful, verify that the operands satisfy the
253818334Speter	   constraints for the instruction.  Crash if they don't,
253918334Speter	   since `reload' should have changed them so that they do.  */
254018334Speter
254118334Speter	insn_code_number = recog_memoized (insn);
254252515Sobrien	cleanup_subreg_operands (insn);
254318334Speter
254490087Sobrien       /* Dump the insn in the assembly for debugging.  */
254590087Sobrien       if (flag_dump_rtl_in_asm)
254690087Sobrien         {
254790087Sobrien           print_rtx_head = ASM_COMMENT_START;
254890087Sobrien           print_rtl_single (asm_out_file, insn);
254990087Sobrien           print_rtx_head = "";
255090087Sobrien         }
255190087Sobrien
255290087Sobrien	if (! constrain_operands_cached (1))
255318334Speter	  fatal_insn_not_found (insn);
255418334Speter
255518334Speter	/* Some target machines need to prescan each insn before
255618334Speter	   it is output.  */
255718334Speter
255818334Speter#ifdef FINAL_PRESCAN_INSN
255990087Sobrien	FINAL_PRESCAN_INSN (insn, recog_data.operand, recog_data.n_operands);
256018334Speter#endif
256118334Speter
256290087Sobrien#ifdef HAVE_conditional_execution
256390087Sobrien	if (GET_CODE (PATTERN (insn)) == COND_EXEC)
256490087Sobrien	  current_insn_predicate = COND_EXEC_TEST (PATTERN (insn));
256590087Sobrien	else
256690087Sobrien	  current_insn_predicate = NULL_RTX;
256790087Sobrien#endif
256890087Sobrien
256918334Speter#ifdef HAVE_cc0
257018334Speter	cc_prev_status = cc_status;
257118334Speter
257218334Speter	/* Update `cc_status' for this instruction.
257318334Speter	   The instruction's output routine may change it further.
257418334Speter	   If the output routine for a jump insn needs to depend
257518334Speter	   on the cc status, it should look at cc_prev_status.  */
257618334Speter
257718334Speter	NOTICE_UPDATE_CC (body, insn);
257818334Speter#endif
257918334Speter
258090087Sobrien	current_output_insn = debug_insn = insn;
258118334Speter
258290087Sobrien#if defined (DWARF2_UNWIND_INFO)
258350503Sobrien	if (GET_CODE (insn) == CALL_INSN && dwarf2out_do_frame ())
258450503Sobrien	  dwarf2out_frame_debug (insn);
258550503Sobrien#endif
258650503Sobrien
258790087Sobrien	/* Find the proper template for this insn.  */
258890087Sobrien	template = get_insn_template (insn_code_number, insn);
258918334Speter
259090087Sobrien	/* If the C code returns 0, it means that it is a jump insn
259190087Sobrien	   which follows a deleted test insn, and that test insn
259290087Sobrien	   needs to be reinserted.  */
259318334Speter	if (template == 0)
259418334Speter	  {
259590087Sobrien	    rtx prev;
259618334Speter
259790087Sobrien	    if (prev_nonnote_insn (insn) != last_ignored_compare)
259890087Sobrien	      abort ();
259990087Sobrien	    new_block = 0;
260090087Sobrien
260190087Sobrien	    /* We have already processed the notes between the setter and
260290087Sobrien	       the user.  Make sure we don't process them again, this is
260390087Sobrien	       particularly important if one of the notes is a block
260490087Sobrien	       scope note or an EH note.  */
260590087Sobrien	    for (prev = insn;
260690087Sobrien		 prev != last_ignored_compare;
260790087Sobrien		 prev = PREV_INSN (prev))
260818334Speter	      {
260990087Sobrien		if (GET_CODE (prev) == NOTE)
261090087Sobrien		  delete_insn (prev);	/* Use delete_note.  */
261118334Speter	      }
261290087Sobrien
261390087Sobrien	    return prev;
261418334Speter	  }
261518334Speter
261618334Speter	/* If the template is the string "#", it means that this insn must
261718334Speter	   be split.  */
261818334Speter	if (template[0] == '#' && template[1] == '\0')
261918334Speter	  {
262018334Speter	    rtx new = try_split (body, insn, 0);
262118334Speter
262218334Speter	    /* If we didn't split the insn, go away.  */
262318334Speter	    if (new == insn && PATTERN (new) == body)
262490087Sobrien	      fatal_insn ("could not split insn", insn);
262590087Sobrien
262650503Sobrien#ifdef HAVE_ATTR_length
262750503Sobrien	    /* This instruction should have been split in shorten_branches,
262850503Sobrien	       to ensure that we would have valid length info for the
262950503Sobrien	       splitees.  */
263050503Sobrien	    abort ();
263150503Sobrien#endif
263250503Sobrien
263318334Speter	    new_block = 0;
263418334Speter	    return new;
263518334Speter	  }
263690087Sobrien
263718334Speter	if (prescan > 0)
263818334Speter	  break;
263918334Speter
264090087Sobrien#ifdef IA64_UNWIND_INFO
264190087Sobrien	IA64_UNWIND_EMIT (asm_out_file, insn);
264290087Sobrien#endif
264318334Speter	/* Output assembler code from the template.  */
264418334Speter
264590087Sobrien	output_asm_insn (template, recog_data.operand);
264618334Speter
264750503Sobrien#if defined (DWARF2_UNWIND_INFO)
264890087Sobrien#if defined (HAVE_prologue)
264950503Sobrien	if (GET_CODE (insn) == INSN && dwarf2out_do_frame ())
265050503Sobrien	  dwarf2out_frame_debug (insn);
265150503Sobrien#else
265290087Sobrien	if (!ACCUMULATE_OUTGOING_ARGS
265390087Sobrien	    && GET_CODE (insn) == INSN
265490087Sobrien	    && dwarf2out_do_frame ())
265550503Sobrien	  dwarf2out_frame_debug (insn);
265650503Sobrien#endif
265750503Sobrien#endif
265850503Sobrien
265918334Speter#if 0
266018334Speter	/* It's not at all clear why we did this and doing so interferes
266118334Speter	   with tests we'd like to do to use REG_WAS_0 notes, so let's try
266218334Speter	   with this out.  */
266318334Speter
266418334Speter	/* Mark this insn as having been output.  */
266518334Speter	INSN_DELETED_P (insn) = 1;
266618334Speter#endif
266718334Speter
266890087Sobrien	/* Emit information for vtable gc.  */
266990087Sobrien	note = find_reg_note (insn, REG_VTABLE_REF, NULL_RTX);
267090087Sobrien	if (note)
267190087Sobrien	  assemble_vtable_entry (XEXP (XEXP (note, 0), 0),
267290087Sobrien				 INTVAL (XEXP (XEXP (note, 0), 1)));
267390087Sobrien
267490087Sobrien	current_output_insn = debug_insn = 0;
267518334Speter      }
267618334Speter    }
267718334Speter  return NEXT_INSN (insn);
267818334Speter}
267918334Speter
268018334Speter/* Output debugging info to the assembler file FILE
268118334Speter   based on the NOTE-insn INSN, assumed to be a line number.  */
268218334Speter
268318334Speterstatic void
268490087Sobriennotice_source_line (insn)
268518334Speter     rtx insn;
268618334Speter{
268790087Sobrien  const char *filename = NOTE_SOURCE_FILE (insn);
268818334Speter
268918334Speter  last_filename = filename;
269018334Speter  last_linenum = NOTE_LINE_NUMBER (insn);
269118334Speter  high_block_linenum = MAX (last_linenum, high_block_linenum);
269218334Speter  high_function_linenum = MAX (last_linenum, high_function_linenum);
269318334Speter}
269418334Speter
269552515Sobrien/* For each operand in INSN, simplify (subreg (reg)) so that it refers
269652515Sobrien   directly to the desired hard register.  */
269790087Sobrien
269852515Sobrienvoid
269952515Sobriencleanup_subreg_operands (insn)
270052515Sobrien     rtx insn;
270152515Sobrien{
270252515Sobrien  int i;
270390087Sobrien  extract_insn_cached (insn);
270490087Sobrien  for (i = 0; i < recog_data.n_operands; i++)
270552515Sobrien    {
270690087Sobrien      /* The following test cannot use recog_data.operand when tesing
270790087Sobrien	 for a SUBREG: the underlying object might have been changed
270890087Sobrien	 already if we are inside a match_operator expression that
270990087Sobrien	 matches the else clause.  Instead we test the underlying
271090087Sobrien	 expression directly.  */
271190087Sobrien      if (GET_CODE (*recog_data.operand_loc[i]) == SUBREG)
271290087Sobrien	recog_data.operand[i] = alter_subreg (recog_data.operand_loc[i]);
271390087Sobrien      else if (GET_CODE (recog_data.operand[i]) == PLUS
271490087Sobrien	       || GET_CODE (recog_data.operand[i]) == MULT
271590087Sobrien	       || GET_CODE (recog_data.operand[i]) == MEM)
271690087Sobrien	recog_data.operand[i] = walk_alter_subreg (recog_data.operand_loc[i]);
271752515Sobrien    }
271852515Sobrien
271990087Sobrien  for (i = 0; i < recog_data.n_dups; i++)
272052515Sobrien    {
272190087Sobrien      if (GET_CODE (*recog_data.dup_loc[i]) == SUBREG)
272290087Sobrien	*recog_data.dup_loc[i] = alter_subreg (recog_data.dup_loc[i]);
272390087Sobrien      else if (GET_CODE (*recog_data.dup_loc[i]) == PLUS
272490087Sobrien	       || GET_CODE (*recog_data.dup_loc[i]) == MULT
272590087Sobrien	       || GET_CODE (*recog_data.dup_loc[i]) == MEM)
272690087Sobrien	*recog_data.dup_loc[i] = walk_alter_subreg (recog_data.dup_loc[i]);
272752515Sobrien    }
272852515Sobrien}
272952515Sobrien
273018334Speter/* If X is a SUBREG, replace it with a REG or a MEM,
273118334Speter   based on the thing it is a subreg of.  */
273218334Speter
273318334Speterrtx
273490087Sobrienalter_subreg (xp)
273590087Sobrien     rtx *xp;
273618334Speter{
273790087Sobrien  rtx x = *xp;
273890087Sobrien  rtx y = SUBREG_REG (x);
273950503Sobrien
274090087Sobrien  /* simplify_subreg does not remove subreg from volatile references.
274190087Sobrien     We are required to.  */
274290087Sobrien  if (GET_CODE (y) == MEM)
274390087Sobrien    *xp = adjust_address (y, GET_MODE (x), SUBREG_BYTE (x));
274490087Sobrien  else
274518334Speter    {
274690087Sobrien      rtx new = simplify_subreg (GET_MODE (x), y, GET_MODE (y),
274790087Sobrien				 SUBREG_BYTE (x));
274850503Sobrien
274990087Sobrien      if (new != 0)
275090087Sobrien	*xp = new;
275190087Sobrien      /* Simplify_subreg can't handle some REG cases, but we have to.  */
275290087Sobrien      else if (GET_CODE (y) == REG)
275390087Sobrien	{
275490087Sobrien	  unsigned int regno = subreg_hard_regno (x, 1);
275590087Sobrien	  PUT_CODE (x, REG);
275690087Sobrien	  REGNO (x) = regno;
275790087Sobrien	  ORIGINAL_REGNO (x) = ORIGINAL_REGNO (y);
275890087Sobrien	  /* This field has a different meaning for REGs and SUBREGs.  Make
275990087Sobrien	     sure to clear it!  */
276090087Sobrien	  x->used = 0;
276190087Sobrien	}
276290087Sobrien      else
276390087Sobrien	abort ();
276418334Speter    }
276518334Speter
276690087Sobrien  return *xp;
276718334Speter}
276818334Speter
276918334Speter/* Do alter_subreg on all the SUBREGs contained in X.  */
277018334Speter
277118334Speterstatic rtx
277290087Sobrienwalk_alter_subreg (xp)
277390087Sobrien     rtx *xp;
277418334Speter{
277590087Sobrien  rtx x = *xp;
277618334Speter  switch (GET_CODE (x))
277718334Speter    {
277818334Speter    case PLUS:
277918334Speter    case MULT:
278090087Sobrien      XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0));
278190087Sobrien      XEXP (x, 1) = walk_alter_subreg (&XEXP (x, 1));
278218334Speter      break;
278318334Speter
278418334Speter    case MEM:
278590087Sobrien      XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0));
278618334Speter      break;
278718334Speter
278818334Speter    case SUBREG:
278990087Sobrien      return alter_subreg (xp);
279090087Sobrien
279150503Sobrien    default:
279250503Sobrien      break;
279318334Speter    }
279418334Speter
279590087Sobrien  return *xp;
279618334Speter}
279718334Speter
279818334Speter#ifdef HAVE_cc0
279918334Speter
280018334Speter/* Given BODY, the body of a jump instruction, alter the jump condition
280118334Speter   as required by the bits that are set in cc_status.flags.
280218334Speter   Not all of the bits there can be handled at this level in all cases.
280318334Speter
280418334Speter   The value is normally 0.
280518334Speter   1 means that the condition has become always true.
280618334Speter   -1 means that the condition has become always false.
280718334Speter   2 means that COND has been altered.  */
280818334Speter
280918334Speterstatic int
281018334Speteralter_cond (cond)
281190087Sobrien     rtx cond;
281218334Speter{
281318334Speter  int value = 0;
281418334Speter
281518334Speter  if (cc_status.flags & CC_REVERSED)
281618334Speter    {
281718334Speter      value = 2;
281818334Speter      PUT_CODE (cond, swap_condition (GET_CODE (cond)));
281918334Speter    }
282018334Speter
282118334Speter  if (cc_status.flags & CC_INVERTED)
282218334Speter    {
282318334Speter      value = 2;
282418334Speter      PUT_CODE (cond, reverse_condition (GET_CODE (cond)));
282518334Speter    }
282618334Speter
282718334Speter  if (cc_status.flags & CC_NOT_POSITIVE)
282818334Speter    switch (GET_CODE (cond))
282918334Speter      {
283018334Speter      case LE:
283118334Speter      case LEU:
283218334Speter      case GEU:
283318334Speter	/* Jump becomes unconditional.  */
283418334Speter	return 1;
283518334Speter
283618334Speter      case GT:
283718334Speter      case GTU:
283818334Speter      case LTU:
283918334Speter	/* Jump becomes no-op.  */
284018334Speter	return -1;
284118334Speter
284218334Speter      case GE:
284318334Speter	PUT_CODE (cond, EQ);
284418334Speter	value = 2;
284518334Speter	break;
284618334Speter
284718334Speter      case LT:
284818334Speter	PUT_CODE (cond, NE);
284918334Speter	value = 2;
285018334Speter	break;
285190087Sobrien
285250503Sobrien      default:
285350503Sobrien	break;
285418334Speter      }
285518334Speter
285618334Speter  if (cc_status.flags & CC_NOT_NEGATIVE)
285718334Speter    switch (GET_CODE (cond))
285818334Speter      {
285918334Speter      case GE:
286018334Speter      case GEU:
286118334Speter	/* Jump becomes unconditional.  */
286218334Speter	return 1;
286318334Speter
286418334Speter      case LT:
286518334Speter      case LTU:
286618334Speter	/* Jump becomes no-op.  */
286718334Speter	return -1;
286818334Speter
286918334Speter      case LE:
287018334Speter      case LEU:
287118334Speter	PUT_CODE (cond, EQ);
287218334Speter	value = 2;
287318334Speter	break;
287418334Speter
287518334Speter      case GT:
287618334Speter      case GTU:
287718334Speter	PUT_CODE (cond, NE);
287818334Speter	value = 2;
287918334Speter	break;
288090087Sobrien
288150503Sobrien      default:
288250503Sobrien	break;
288318334Speter      }
288418334Speter
288518334Speter  if (cc_status.flags & CC_NO_OVERFLOW)
288618334Speter    switch (GET_CODE (cond))
288718334Speter      {
288818334Speter      case GEU:
288918334Speter	/* Jump becomes unconditional.  */
289018334Speter	return 1;
289118334Speter
289218334Speter      case LEU:
289318334Speter	PUT_CODE (cond, EQ);
289418334Speter	value = 2;
289518334Speter	break;
289618334Speter
289718334Speter      case GTU:
289818334Speter	PUT_CODE (cond, NE);
289918334Speter	value = 2;
290018334Speter	break;
290118334Speter
290218334Speter      case LTU:
290318334Speter	/* Jump becomes no-op.  */
290418334Speter	return -1;
290590087Sobrien
290650503Sobrien      default:
290750503Sobrien	break;
290818334Speter      }
290918334Speter
291018334Speter  if (cc_status.flags & (CC_Z_IN_NOT_N | CC_Z_IN_N))
291118334Speter    switch (GET_CODE (cond))
291218334Speter      {
291350503Sobrien      default:
291418334Speter	abort ();
291518334Speter
291618334Speter      case NE:
291718334Speter	PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? GE : LT);
291818334Speter	value = 2;
291918334Speter	break;
292018334Speter
292118334Speter      case EQ:
292218334Speter	PUT_CODE (cond, cc_status.flags & CC_Z_IN_N ? LT : GE);
292318334Speter	value = 2;
292418334Speter	break;
292518334Speter      }
292618334Speter
292718334Speter  if (cc_status.flags & CC_NOT_SIGNED)
292818334Speter    /* The flags are valid if signed condition operators are converted
292918334Speter       to unsigned.  */
293018334Speter    switch (GET_CODE (cond))
293118334Speter      {
293218334Speter      case LE:
293318334Speter	PUT_CODE (cond, LEU);
293418334Speter	value = 2;
293518334Speter	break;
293618334Speter
293718334Speter      case LT:
293818334Speter	PUT_CODE (cond, LTU);
293918334Speter	value = 2;
294018334Speter	break;
294118334Speter
294218334Speter      case GT:
294318334Speter	PUT_CODE (cond, GTU);
294418334Speter	value = 2;
294518334Speter	break;
294618334Speter
294718334Speter      case GE:
294818334Speter	PUT_CODE (cond, GEU);
294918334Speter	value = 2;
295018334Speter	break;
295150503Sobrien
295250503Sobrien      default:
295350503Sobrien	break;
295418334Speter      }
295518334Speter
295618334Speter  return value;
295718334Speter}
295818334Speter#endif
295918334Speter
296018334Speter/* Report inconsistency between the assembler template and the operands.
296118334Speter   In an `asm', it's the user's fault; otherwise, the compiler's fault.  */
296218334Speter
296318334Spetervoid
296496281Sobrienoutput_operand_lossage VPARAMS ((const char *msgid, ...))
296518334Speter{
296696281Sobrien  char *fmt_string;
296796281Sobrien  char *new_message;
296896281Sobrien  const char *pfx_str;
296996281Sobrien  VA_OPEN (ap, msgid);
297096281Sobrien  VA_FIXEDARG (ap, const char *, msgid);
297196281Sobrien
297296281Sobrien  pfx_str = this_is_asm_operands ? _("invalid `asm': ") : "output_operand: ";
297396281Sobrien  asprintf (&fmt_string, "%s%s", pfx_str, _(msgid));
297496281Sobrien  vasprintf (&new_message, fmt_string, ap);
297596281Sobrien
297618334Speter  if (this_is_asm_operands)
297796281Sobrien    error_for_asm (this_is_asm_operands, "%s", new_message);
297818334Speter  else
297996281Sobrien    internal_error ("%s", new_message);
298096281Sobrien
298196281Sobrien  free (fmt_string);
298296281Sobrien  free (new_message);
298396281Sobrien  VA_CLOSE (ap);
298418334Speter}
298518334Speter
298618334Speter/* Output of assembler code from a template, and its subroutines.  */
298718334Speter
298890087Sobrien/* Annotate the assembly with a comment describing the pattern and
298990087Sobrien   alternative used.  */
299090087Sobrien
299190087Sobrienstatic void
299290087Sobrienoutput_asm_name ()
299390087Sobrien{
299490087Sobrien  if (debug_insn)
299590087Sobrien    {
299690087Sobrien      int num = INSN_CODE (debug_insn);
299790087Sobrien      fprintf (asm_out_file, "\t%s %d\t%s",
299890087Sobrien	       ASM_COMMENT_START, INSN_UID (debug_insn),
299990087Sobrien	       insn_data[num].name);
300090087Sobrien      if (insn_data[num].n_alternatives > 1)
300190087Sobrien	fprintf (asm_out_file, "/%d", which_alternative + 1);
300290087Sobrien#ifdef HAVE_ATTR_length
300390087Sobrien      fprintf (asm_out_file, "\t[length = %d]",
300490087Sobrien	       get_attr_length (debug_insn));
300590087Sobrien#endif
300690087Sobrien      /* Clear this so only the first assembler insn
300790087Sobrien	 of any rtl insn will get the special comment for -dp.  */
300890087Sobrien      debug_insn = 0;
300990087Sobrien    }
301090087Sobrien}
301190087Sobrien
301290087Sobrien/* If OP is a REG or MEM and we can find a MEM_EXPR corresponding to it
301390087Sobrien   or its address, return that expr .  Set *PADDRESSP to 1 if the expr
301490087Sobrien   corresponds to the address of the object and 0 if to the object.  */
301590087Sobrien
301690087Sobrienstatic tree
301790087Sobrienget_mem_expr_from_op (op, paddressp)
301890087Sobrien     rtx op;
301990087Sobrien     int *paddressp;
302090087Sobrien{
302190087Sobrien  tree expr;
302290087Sobrien  int inner_addressp;
302390087Sobrien
302490087Sobrien  *paddressp = 0;
302590087Sobrien
302690087Sobrien  if (GET_CODE (op) == REG && ORIGINAL_REGNO (op) >= FIRST_PSEUDO_REGISTER)
302790087Sobrien    return REGNO_DECL (ORIGINAL_REGNO (op));
302890087Sobrien  else if (GET_CODE (op) != MEM)
302990087Sobrien    return 0;
303090087Sobrien
303190087Sobrien  if (MEM_EXPR (op) != 0)
303290087Sobrien    return MEM_EXPR (op);
303390087Sobrien
303490087Sobrien  /* Otherwise we have an address, so indicate it and look at the address.  */
303590087Sobrien  *paddressp = 1;
303690087Sobrien  op = XEXP (op, 0);
303790087Sobrien
303890087Sobrien  /* First check if we have a decl for the address, then look at the right side
303990087Sobrien     if it is a PLUS.  Otherwise, strip off arithmetic and keep looking.
304090087Sobrien     But don't allow the address to itself be indirect.  */
304190087Sobrien  if ((expr = get_mem_expr_from_op (op, &inner_addressp)) && ! inner_addressp)
304290087Sobrien    return expr;
304390087Sobrien  else if (GET_CODE (op) == PLUS
304490087Sobrien	   && (expr = get_mem_expr_from_op (XEXP (op, 1), &inner_addressp)))
304590087Sobrien    return expr;
304690087Sobrien
304790087Sobrien  while (GET_RTX_CLASS (GET_CODE (op)) == '1'
304890087Sobrien	 || GET_RTX_CLASS (GET_CODE (op)) == '2')
304990087Sobrien    op = XEXP (op, 0);
305090087Sobrien
305190087Sobrien  expr = get_mem_expr_from_op (op, &inner_addressp);
305290087Sobrien  return inner_addressp ? 0 : expr;
305390087Sobrien}
305490087Sobrien
305590087Sobrien/* Output operand names for assembler instructions.  OPERANDS is the
305690087Sobrien   operand vector, OPORDER is the order to write the operands, and NOPS
305790087Sobrien   is the number of operands to write.  */
305890087Sobrien
305990087Sobrienstatic void
306090087Sobrienoutput_asm_operand_names (operands, oporder, nops)
306190087Sobrien     rtx *operands;
306290087Sobrien     int *oporder;
306390087Sobrien     int nops;
306490087Sobrien{
306590087Sobrien  int wrote = 0;
306690087Sobrien  int i;
306790087Sobrien
306890087Sobrien  for (i = 0; i < nops; i++)
306990087Sobrien    {
307090087Sobrien      int addressp;
307190087Sobrien      tree expr = get_mem_expr_from_op (operands[oporder[i]], &addressp);
307290087Sobrien
307390087Sobrien      if (expr)
307490087Sobrien	{
307590087Sobrien	  fprintf (asm_out_file, "%c%s %s",
307690087Sobrien		   wrote ? ',' : '\t', wrote ? "" : ASM_COMMENT_START,
307790087Sobrien		   addressp ? "*" : "");
307890087Sobrien	  print_mem_expr (asm_out_file, expr);
307990087Sobrien	  wrote = 1;
308090087Sobrien	}
308190087Sobrien    }
308290087Sobrien}
308390087Sobrien
308418334Speter/* Output text from TEMPLATE to the assembler output file,
308518334Speter   obeying %-directions to substitute operands taken from
308618334Speter   the vector OPERANDS.
308718334Speter
308818334Speter   %N (for N a digit) means print operand N in usual manner.
308918334Speter   %lN means require operand N to be a CODE_LABEL or LABEL_REF
309018334Speter      and print the label name with no punctuation.
309118334Speter   %cN means require operand N to be a constant
309218334Speter      and print the constant expression with no punctuation.
309318334Speter   %aN means expect operand N to be a memory address
309418334Speter      (not a memory reference!) and print a reference
309518334Speter      to that address.
309618334Speter   %nN means expect operand N to be a constant
309718334Speter      and print a constant expression for minus the value
309818334Speter      of the operand, with no other punctuation.  */
309918334Speter
310018334Spetervoid
310118334Speteroutput_asm_insn (template, operands)
310252515Sobrien     const char *template;
310318334Speter     rtx *operands;
310418334Speter{
310590087Sobrien  const char *p;
310690087Sobrien  int c;
310790087Sobrien#ifdef ASSEMBLER_DIALECT
310890087Sobrien  int dialect = 0;
310990087Sobrien#endif
311090087Sobrien  int oporder[MAX_RECOG_OPERANDS];
311190087Sobrien  char opoutput[MAX_RECOG_OPERANDS];
311290087Sobrien  int ops = 0;
311318334Speter
311418334Speter  /* An insn may return a null string template
311518334Speter     in a case where no assembler code is needed.  */
311618334Speter  if (*template == 0)
311718334Speter    return;
311818334Speter
311990087Sobrien  memset (opoutput, 0, sizeof opoutput);
312018334Speter  p = template;
312118334Speter  putc ('\t', asm_out_file);
312218334Speter
312318334Speter#ifdef ASM_OUTPUT_OPCODE
312418334Speter  ASM_OUTPUT_OPCODE (asm_out_file, p);
312518334Speter#endif
312618334Speter
312750503Sobrien  while ((c = *p++))
312818334Speter    switch (c)
312918334Speter      {
313018334Speter      case '\n':
313190087Sobrien	if (flag_verbose_asm)
313290087Sobrien	  output_asm_operand_names (operands, oporder, ops);
313390087Sobrien	if (flag_print_asm_name)
313490087Sobrien	  output_asm_name ();
313590087Sobrien
313690087Sobrien	ops = 0;
313790087Sobrien	memset (opoutput, 0, sizeof opoutput);
313890087Sobrien
313918334Speter	putc (c, asm_out_file);
314018334Speter#ifdef ASM_OUTPUT_OPCODE
314118334Speter	while ((c = *p) == '\t')
314218334Speter	  {
314318334Speter	    putc (c, asm_out_file);
314418334Speter	    p++;
314518334Speter	  }
314618334Speter	ASM_OUTPUT_OPCODE (asm_out_file, p);
314718334Speter#endif
314818334Speter	break;
314918334Speter
315018334Speter#ifdef ASSEMBLER_DIALECT
315118334Speter      case '{':
315250503Sobrien	{
315390087Sobrien	  int i;
315490087Sobrien
315590087Sobrien	  if (dialect)
315690087Sobrien	    output_operand_lossage ("nested assembly dialect alternatives");
315790087Sobrien	  else
315890087Sobrien	    dialect = 1;
315990087Sobrien
316050503Sobrien	  /* If we want the first dialect, do nothing.  Otherwise, skip
316150503Sobrien	     DIALECT_NUMBER of strings ending with '|'.  */
316250503Sobrien	  for (i = 0; i < dialect_number; i++)
316350503Sobrien	    {
316490087Sobrien	      while (*p && *p != '}' && *p++ != '|')
316550503Sobrien		;
316690087Sobrien	      if (*p == '}')
316790087Sobrien		break;
316850503Sobrien	      if (*p == '|')
316950503Sobrien		p++;
317050503Sobrien	    }
317190087Sobrien
317290087Sobrien	  if (*p == '\0')
317390087Sobrien	    output_operand_lossage ("unterminated assembly dialect alternative");
317450503Sobrien	}
317518334Speter	break;
317618334Speter
317718334Speter      case '|':
317890087Sobrien	if (dialect)
317990087Sobrien	  {
318090087Sobrien	    /* Skip to close brace.  */
318190087Sobrien	    do
318290087Sobrien	      {
318390087Sobrien		if (*p == '\0')
318490087Sobrien		  {
318590087Sobrien		    output_operand_lossage ("unterminated assembly dialect alternative");
318690087Sobrien		    break;
318790087Sobrien		  }
318890087Sobrien	      }
318990087Sobrien	    while (*p++ != '}');
319090087Sobrien	    dialect = 0;
319190087Sobrien	  }
319290087Sobrien	else
319390087Sobrien	  putc (c, asm_out_file);
319418334Speter	break;
319518334Speter
319618334Speter      case '}':
319790087Sobrien	if (! dialect)
319890087Sobrien	  putc (c, asm_out_file);
319990087Sobrien	dialect = 0;
320018334Speter	break;
320118334Speter#endif
320218334Speter
320318334Speter      case '%':
320418334Speter	/* %% outputs a single %.  */
320518334Speter	if (*p == '%')
320618334Speter	  {
320718334Speter	    p++;
320818334Speter	    putc (c, asm_out_file);
320918334Speter	  }
321018334Speter	/* %= outputs a number which is unique to each insn in the entire
321118334Speter	   compilation.  This is useful for making local labels that are
321218334Speter	   referred to more than once in a given insn.  */
321318334Speter	else if (*p == '=')
321418334Speter	  {
321518334Speter	    p++;
321618334Speter	    fprintf (asm_out_file, "%d", insn_counter);
321718334Speter	  }
321818334Speter	/* % followed by a letter and some digits
321918334Speter	   outputs an operand in a special way depending on the letter.
322018334Speter	   Letters `acln' are implemented directly.
322118334Speter	   Other letters are passed to `output_operand' so that
322218334Speter	   the PRINT_OPERAND macro can define them.  */
322390087Sobrien	else if (ISALPHA (*p))
322418334Speter	  {
322518334Speter	    int letter = *p++;
322618334Speter	    c = atoi (p);
322718334Speter
322890087Sobrien	    if (! ISDIGIT (*p))
322996281Sobrien	      output_operand_lossage ("operand number missing after %%-letter");
323090087Sobrien	    else if (this_is_asm_operands
323190087Sobrien		     && (c < 0 || (unsigned int) c >= insn_noperands))
323218334Speter	      output_operand_lossage ("operand number out of range");
323318334Speter	    else if (letter == 'l')
323418334Speter	      output_asm_label (operands[c]);
323518334Speter	    else if (letter == 'a')
323618334Speter	      output_address (operands[c]);
323718334Speter	    else if (letter == 'c')
323818334Speter	      {
323918334Speter		if (CONSTANT_ADDRESS_P (operands[c]))
324018334Speter		  output_addr_const (asm_out_file, operands[c]);
324118334Speter		else
324218334Speter		  output_operand (operands[c], 'c');
324318334Speter	      }
324418334Speter	    else if (letter == 'n')
324518334Speter	      {
324618334Speter		if (GET_CODE (operands[c]) == CONST_INT)
324750503Sobrien		  fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC,
324818334Speter			   - INTVAL (operands[c]));
324918334Speter		else
325018334Speter		  {
325118334Speter		    putc ('-', asm_out_file);
325218334Speter		    output_addr_const (asm_out_file, operands[c]);
325318334Speter		  }
325418334Speter	      }
325518334Speter	    else
325618334Speter	      output_operand (operands[c], letter);
325790087Sobrien
325890087Sobrien	    if (!opoutput[c])
325990087Sobrien	      oporder[ops++] = c;
326090087Sobrien	    opoutput[c] = 1;
326190087Sobrien
326290087Sobrien	    while (ISDIGIT (c = *p))
326390087Sobrien	      p++;
326418334Speter	  }
326518334Speter	/* % followed by a digit outputs an operand the default way.  */
326690087Sobrien	else if (ISDIGIT (*p))
326718334Speter	  {
326818334Speter	    c = atoi (p);
326990087Sobrien	    if (this_is_asm_operands
327090087Sobrien		&& (c < 0 || (unsigned int) c >= insn_noperands))
327118334Speter	      output_operand_lossage ("operand number out of range");
327218334Speter	    else
327318334Speter	      output_operand (operands[c], 0);
327490087Sobrien
327590087Sobrien	    if (!opoutput[c])
327690087Sobrien	      oporder[ops++] = c;
327790087Sobrien	    opoutput[c] = 1;
327890087Sobrien
327990087Sobrien	    while (ISDIGIT (c = *p))
328090087Sobrien	      p++;
328118334Speter	  }
328218334Speter	/* % followed by punctuation: output something for that
328318334Speter	   punctuation character alone, with no operand.
328418334Speter	   The PRINT_OPERAND macro decides what is actually done.  */
328518334Speter#ifdef PRINT_OPERAND_PUNCT_VALID_P
328690087Sobrien	else if (PRINT_OPERAND_PUNCT_VALID_P ((unsigned char) *p))
328718334Speter	  output_operand (NULL_RTX, *p++);
328818334Speter#endif
328918334Speter	else
329018334Speter	  output_operand_lossage ("invalid %%-code");
329118334Speter	break;
329218334Speter
329318334Speter      default:
329418334Speter	putc (c, asm_out_file);
329518334Speter      }
329618334Speter
329790087Sobrien  /* Write out the variable names for operands, if we know them.  */
329890087Sobrien  if (flag_verbose_asm)
329990087Sobrien    output_asm_operand_names (operands, oporder, ops);
330090087Sobrien  if (flag_print_asm_name)
330190087Sobrien    output_asm_name ();
330218334Speter
330318334Speter  putc ('\n', asm_out_file);
330418334Speter}
330518334Speter
330618334Speter/* Output a LABEL_REF, or a bare CODE_LABEL, as an assembler symbol.  */
330718334Speter
330818334Spetervoid
330918334Speteroutput_asm_label (x)
331018334Speter     rtx x;
331118334Speter{
331218334Speter  char buf[256];
331318334Speter
331418334Speter  if (GET_CODE (x) == LABEL_REF)
331590087Sobrien    x = XEXP (x, 0);
331690087Sobrien  if (GET_CODE (x) == CODE_LABEL
331790087Sobrien      || (GET_CODE (x) == NOTE
331890087Sobrien	  && NOTE_LINE_NUMBER (x) == NOTE_INSN_DELETED_LABEL))
331918334Speter    ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
332018334Speter  else
332196281Sobrien    output_operand_lossage ("`%%l' operand isn't a label");
332218334Speter
332318334Speter  assemble_name (asm_out_file, buf);
332418334Speter}
332518334Speter
332618334Speter/* Print operand X using machine-dependent assembler syntax.
332718334Speter   The macro PRINT_OPERAND is defined just to control this function.
332818334Speter   CODE is a non-digit that preceded the operand-number in the % spec,
332918334Speter   such as 'z' if the spec was `%z3'.  CODE is 0 if there was no char
333018334Speter   between the % and the digits.
333118334Speter   When CODE is a non-letter, X is 0.
333218334Speter
333318334Speter   The meanings of the letters are machine-dependent and controlled
333418334Speter   by PRINT_OPERAND.  */
333518334Speter
333618334Speterstatic void
333718334Speteroutput_operand (x, code)
333818334Speter     rtx x;
333990087Sobrien     int code ATTRIBUTE_UNUSED;
334018334Speter{
334118334Speter  if (x && GET_CODE (x) == SUBREG)
334290087Sobrien    x = alter_subreg (&x);
334318334Speter
334418334Speter  /* If X is a pseudo-register, abort now rather than writing trash to the
334518334Speter     assembler file.  */
334618334Speter
334718334Speter  if (x && GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER)
334818334Speter    abort ();
334918334Speter
335018334Speter  PRINT_OPERAND (asm_out_file, x, code);
335118334Speter}
335218334Speter
335318334Speter/* Print a memory reference operand for address X
335418334Speter   using machine-dependent assembler syntax.
335518334Speter   The macro PRINT_OPERAND_ADDRESS exists just to control this function.  */
335618334Speter
335718334Spetervoid
335818334Speteroutput_address (x)
335918334Speter     rtx x;
336018334Speter{
336190087Sobrien  walk_alter_subreg (&x);
336218334Speter  PRINT_OPERAND_ADDRESS (asm_out_file, x);
336318334Speter}
336418334Speter
336518334Speter/* Print an integer constant expression in assembler syntax.
336618334Speter   Addition and subtraction are the only arithmetic
336718334Speter   that may appear in these expressions.  */
336818334Speter
336918334Spetervoid
337018334Speteroutput_addr_const (file, x)
337118334Speter     FILE *file;
337218334Speter     rtx x;
337318334Speter{
337418334Speter  char buf[256];
337518334Speter
337618334Speter restart:
337718334Speter  switch (GET_CODE (x))
337818334Speter    {
337918334Speter    case PC:
338090087Sobrien      putc ('.', file);
338118334Speter      break;
338218334Speter
338318334Speter    case SYMBOL_REF:
338490087Sobrien#ifdef ASM_OUTPUT_SYMBOL_REF
338590087Sobrien      ASM_OUTPUT_SYMBOL_REF (file, x);
338690087Sobrien#else
338718334Speter      assemble_name (file, XSTR (x, 0));
338890087Sobrien#endif
338918334Speter      break;
339018334Speter
339118334Speter    case LABEL_REF:
339290087Sobrien      x = XEXP (x, 0);
339390087Sobrien      /* Fall through.  */
339418334Speter    case CODE_LABEL:
339518334Speter      ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
339690087Sobrien#ifdef ASM_OUTPUT_LABEL_REF
339790087Sobrien      ASM_OUTPUT_LABEL_REF (file, buf);
339890087Sobrien#else
339918334Speter      assemble_name (file, buf);
340090087Sobrien#endif
340118334Speter      break;
340218334Speter
340318334Speter    case CONST_INT:
340450503Sobrien      fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
340518334Speter      break;
340618334Speter
340718334Speter    case CONST:
340818334Speter      /* This used to output parentheses around the expression,
340918334Speter	 but that does not work on the 386 (either ATT or BSD assembler).  */
341018334Speter      output_addr_const (file, XEXP (x, 0));
341118334Speter      break;
341218334Speter
341318334Speter    case CONST_DOUBLE:
341418334Speter      if (GET_MODE (x) == VOIDmode)
341518334Speter	{
341618334Speter	  /* We can use %d if the number is one word and positive.  */
341718334Speter	  if (CONST_DOUBLE_HIGH (x))
341850503Sobrien	    fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
341918334Speter		     CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x));
342090087Sobrien	  else if (CONST_DOUBLE_LOW (x) < 0)
342150503Sobrien	    fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (x));
342218334Speter	  else
342350503Sobrien	    fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x));
342418334Speter	}
342518334Speter      else
342618334Speter	/* We can't handle floating point constants;
342718334Speter	   PRINT_OPERAND must handle them.  */
342818334Speter	output_operand_lossage ("floating constant misused");
342918334Speter      break;
343018334Speter
343118334Speter    case PLUS:
343218334Speter      /* Some assemblers need integer constants to appear last (eg masm).  */
343318334Speter      if (GET_CODE (XEXP (x, 0)) == CONST_INT)
343418334Speter	{
343518334Speter	  output_addr_const (file, XEXP (x, 1));
343618334Speter	  if (INTVAL (XEXP (x, 0)) >= 0)
343718334Speter	    fprintf (file, "+");
343818334Speter	  output_addr_const (file, XEXP (x, 0));
343918334Speter	}
344018334Speter      else
344118334Speter	{
344218334Speter	  output_addr_const (file, XEXP (x, 0));
344390087Sobrien	  if (GET_CODE (XEXP (x, 1)) != CONST_INT
344490087Sobrien	      || INTVAL (XEXP (x, 1)) >= 0)
344518334Speter	    fprintf (file, "+");
344618334Speter	  output_addr_const (file, XEXP (x, 1));
344718334Speter	}
344818334Speter      break;
344918334Speter
345018334Speter    case MINUS:
345118334Speter      /* Avoid outputting things like x-x or x+5-x,
345218334Speter	 since some assemblers can't handle that.  */
345318334Speter      x = simplify_subtraction (x);
345418334Speter      if (GET_CODE (x) != MINUS)
345518334Speter	goto restart;
345618334Speter
345718334Speter      output_addr_const (file, XEXP (x, 0));
345818334Speter      fprintf (file, "-");
345990087Sobrien      if ((GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) >= 0)
346090087Sobrien	  || GET_CODE (XEXP (x, 1)) == PC
346190087Sobrien	  || GET_CODE (XEXP (x, 1)) == SYMBOL_REF)
346290087Sobrien	output_addr_const (file, XEXP (x, 1));
346390087Sobrien      else
346418334Speter	{
346590087Sobrien	  fputs (targetm.asm_out.open_paren, file);
346618334Speter	  output_addr_const (file, XEXP (x, 1));
346790087Sobrien	  fputs (targetm.asm_out.close_paren, file);
346818334Speter	}
346918334Speter      break;
347018334Speter
347118334Speter    case ZERO_EXTEND:
347218334Speter    case SIGN_EXTEND:
347396281Sobrien    case SUBREG:
347418334Speter      output_addr_const (file, XEXP (x, 0));
347518334Speter      break;
347618334Speter
347718334Speter    default:
347890087Sobrien#ifdef OUTPUT_ADDR_CONST_EXTRA
347990087Sobrien      OUTPUT_ADDR_CONST_EXTRA (file, x, fail);
348090087Sobrien      break;
348190087Sobrien
348290087Sobrien    fail:
348390087Sobrien#endif
348418334Speter      output_operand_lossage ("invalid expression as operand");
348518334Speter    }
348618334Speter}
348718334Speter
348818334Speter/* A poor man's fprintf, with the added features of %I, %R, %L, and %U.
348918334Speter   %R prints the value of REGISTER_PREFIX.
349018334Speter   %L prints the value of LOCAL_LABEL_PREFIX.
349118334Speter   %U prints the value of USER_LABEL_PREFIX.
349218334Speter   %I prints the value of IMMEDIATE_PREFIX.
349318334Speter   %O runs ASM_OUTPUT_OPCODE to transform what follows in the string.
349418334Speter   Also supported are %d, %x, %s, %e, %f, %g and %%.
349518334Speter
349618334Speter   We handle alternate assembler dialects here, just like output_asm_insn.  */
349718334Speter
349818334Spetervoid
349990087Sobrienasm_fprintf VPARAMS ((FILE *file, const char *p, ...))
350018334Speter{
350118334Speter  char buf[10];
350218334Speter  char *q, c;
350318334Speter
350490087Sobrien  VA_OPEN (argptr, p);
350590087Sobrien  VA_FIXEDARG (argptr, FILE *, file);
350690087Sobrien  VA_FIXEDARG (argptr, const char *, p);
350718334Speter
350818334Speter  buf[0] = '%';
350918334Speter
351050503Sobrien  while ((c = *p++))
351118334Speter    switch (c)
351218334Speter      {
351318334Speter#ifdef ASSEMBLER_DIALECT
351418334Speter      case '{':
351550503Sobrien	{
351650503Sobrien	  int i;
351718334Speter
351850503Sobrien	  /* If we want the first dialect, do nothing.  Otherwise, skip
351950503Sobrien	     DIALECT_NUMBER of strings ending with '|'.  */
352050503Sobrien	  for (i = 0; i < dialect_number; i++)
352150503Sobrien	    {
352250503Sobrien	      while (*p && *p++ != '|')
352350503Sobrien		;
352450503Sobrien
352550503Sobrien	      if (*p == '|')
352650503Sobrien		p++;
352790087Sobrien	    }
352850503Sobrien	}
352918334Speter	break;
353018334Speter
353118334Speter      case '|':
353218334Speter	/* Skip to close brace.  */
353318334Speter	while (*p && *p++ != '}')
353418334Speter	  ;
353518334Speter	break;
353618334Speter
353718334Speter      case '}':
353818334Speter	break;
353918334Speter#endif
354018334Speter
354118334Speter      case '%':
354218334Speter	c = *p++;
354318334Speter	q = &buf[1];
354490087Sobrien	while (ISDIGIT (c) || c == '.')
354518334Speter	  {
354618334Speter	    *q++ = c;
354718334Speter	    c = *p++;
354818334Speter	  }
354918334Speter	switch (c)
355018334Speter	  {
355118334Speter	  case '%':
355218334Speter	    fprintf (file, "%%");
355318334Speter	    break;
355418334Speter
355518334Speter	  case 'd':  case 'i':  case 'u':
355618334Speter	  case 'x':  case 'p':  case 'X':
355718334Speter	  case 'o':
355818334Speter	    *q++ = c;
355918334Speter	    *q = 0;
356018334Speter	    fprintf (file, buf, va_arg (argptr, int));
356118334Speter	    break;
356218334Speter
356318334Speter	  case 'w':
356418334Speter	    /* This is a prefix to the 'd', 'i', 'u', 'x', 'p', and 'X' cases,
356518334Speter	       but we do not check for those cases.  It means that the value
356618334Speter	       is a HOST_WIDE_INT, which may be either `int' or `long'.  */
356718334Speter
356850503Sobrien#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
356950503Sobrien#else
357050503Sobrien#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
357118334Speter	    *q++ = 'l';
357250503Sobrien#else
357350503Sobrien	    *q++ = 'l';
357450503Sobrien	    *q++ = 'l';
357518334Speter#endif
357650503Sobrien#endif
357718334Speter
357818334Speter	    *q++ = *p++;
357918334Speter	    *q = 0;
358018334Speter	    fprintf (file, buf, va_arg (argptr, HOST_WIDE_INT));
358118334Speter	    break;
358218334Speter
358318334Speter	  case 'l':
358418334Speter	    *q++ = c;
358518334Speter	    *q++ = *p++;
358618334Speter	    *q = 0;
358718334Speter	    fprintf (file, buf, va_arg (argptr, long));
358818334Speter	    break;
358918334Speter
359018334Speter	  case 'e':
359118334Speter	  case 'f':
359218334Speter	  case 'g':
359318334Speter	    *q++ = c;
359418334Speter	    *q = 0;
359518334Speter	    fprintf (file, buf, va_arg (argptr, double));
359618334Speter	    break;
359718334Speter
359818334Speter	  case 's':
359918334Speter	    *q++ = c;
360018334Speter	    *q = 0;
360118334Speter	    fprintf (file, buf, va_arg (argptr, char *));
360218334Speter	    break;
360318334Speter
360418334Speter	  case 'O':
360518334Speter#ifdef ASM_OUTPUT_OPCODE
360618334Speter	    ASM_OUTPUT_OPCODE (asm_out_file, p);
360718334Speter#endif
360818334Speter	    break;
360918334Speter
361018334Speter	  case 'R':
361118334Speter#ifdef REGISTER_PREFIX
361218334Speter	    fprintf (file, "%s", REGISTER_PREFIX);
361318334Speter#endif
361418334Speter	    break;
361518334Speter
361618334Speter	  case 'I':
361718334Speter#ifdef IMMEDIATE_PREFIX
361818334Speter	    fprintf (file, "%s", IMMEDIATE_PREFIX);
361918334Speter#endif
362018334Speter	    break;
362118334Speter
362218334Speter	  case 'L':
362318334Speter#ifdef LOCAL_LABEL_PREFIX
362418334Speter	    fprintf (file, "%s", LOCAL_LABEL_PREFIX);
362518334Speter#endif
362618334Speter	    break;
362718334Speter
362818334Speter	  case 'U':
362952515Sobrien	    fputs (user_label_prefix, file);
363018334Speter	    break;
363118334Speter
363290087Sobrien#ifdef ASM_FPRINTF_EXTENSIONS
363390087Sobrien	    /* Upper case letters are reserved for general use by asm_fprintf
363490087Sobrien	       and so are not available to target specific code.  In order to
363590087Sobrien	       prevent the ASM_FPRINTF_EXTENSIONS macro from using them then,
363690087Sobrien	       they are defined here.  As they get turned into real extensions
363790087Sobrien	       to asm_fprintf they should be removed from this list.  */
363890087Sobrien	  case 'A': case 'B': case 'C': case 'D': case 'E':
363990087Sobrien	  case 'F': case 'G': case 'H': case 'J': case 'K':
364090087Sobrien	  case 'M': case 'N': case 'P': case 'Q': case 'S':
364190087Sobrien	  case 'T': case 'V': case 'W': case 'Y': case 'Z':
364290087Sobrien	    break;
364390087Sobrien
364490087Sobrien	  ASM_FPRINTF_EXTENSIONS (file, argptr, p)
364590087Sobrien#endif
364618334Speter	  default:
364718334Speter	    abort ();
364818334Speter	  }
364918334Speter	break;
365018334Speter
365118334Speter      default:
365218334Speter	fputc (c, file);
365318334Speter      }
365490087Sobrien  VA_CLOSE (argptr);
365518334Speter}
365618334Speter
365718334Speter/* Split up a CONST_DOUBLE or integer constant rtx
365818334Speter   into two rtx's for single words,
365918334Speter   storing in *FIRST the word that comes first in memory in the target
366018334Speter   and in *SECOND the other.  */
366118334Speter
366218334Spetervoid
366318334Spetersplit_double (value, first, second)
366418334Speter     rtx value;
366518334Speter     rtx *first, *second;
366618334Speter{
366718334Speter  if (GET_CODE (value) == CONST_INT)
366818334Speter    {
366918334Speter      if (HOST_BITS_PER_WIDE_INT >= (2 * BITS_PER_WORD))
367018334Speter	{
367118334Speter	  /* In this case the CONST_INT holds both target words.
367250503Sobrien	     Extract the bits from it into two word-sized pieces.
367350503Sobrien	     Sign extend each half to HOST_WIDE_INT.  */
367490087Sobrien	  unsigned HOST_WIDE_INT low, high;
367590087Sobrien	  unsigned HOST_WIDE_INT mask, sign_bit, sign_extend;
367618334Speter
367790087Sobrien	  /* Set sign_bit to the most significant bit of a word.  */
367890087Sobrien	  sign_bit = 1;
367990087Sobrien	  sign_bit <<= BITS_PER_WORD - 1;
368090087Sobrien
368190087Sobrien	  /* Set mask so that all bits of the word are set.  We could
368290087Sobrien	     have used 1 << BITS_PER_WORD instead of basing the
368390087Sobrien	     calculation on sign_bit.  However, on machines where
368490087Sobrien	     HOST_BITS_PER_WIDE_INT == BITS_PER_WORD, it could cause a
368590087Sobrien	     compiler warning, even though the code would never be
368690087Sobrien	     executed.  */
368790087Sobrien	  mask = sign_bit << 1;
368890087Sobrien	  mask--;
368990087Sobrien
369090087Sobrien	  /* Set sign_extend as any remaining bits.  */
369190087Sobrien	  sign_extend = ~mask;
369290087Sobrien
369390087Sobrien	  /* Pick the lower word and sign-extend it.  */
369490087Sobrien	  low = INTVAL (value);
369590087Sobrien	  low &= mask;
369690087Sobrien	  if (low & sign_bit)
369790087Sobrien	    low |= sign_extend;
369890087Sobrien
369990087Sobrien	  /* Pick the higher word, shifted to the least significant
370090087Sobrien	     bits, and sign-extend it.  */
370190087Sobrien	  high = INTVAL (value);
370290087Sobrien	  high >>= BITS_PER_WORD - 1;
370390087Sobrien	  high >>= 1;
370490087Sobrien	  high &= mask;
370590087Sobrien	  if (high & sign_bit)
370690087Sobrien	    high |= sign_extend;
370790087Sobrien
370890087Sobrien	  /* Store the words in the target machine order.  */
370918334Speter	  if (WORDS_BIG_ENDIAN)
371018334Speter	    {
371190087Sobrien	      *first = GEN_INT (high);
371290087Sobrien	      *second = GEN_INT (low);
371318334Speter	    }
371418334Speter	  else
371518334Speter	    {
371690087Sobrien	      *first = GEN_INT (low);
371790087Sobrien	      *second = GEN_INT (high);
371818334Speter	    }
371918334Speter	}
372018334Speter      else
372118334Speter	{
372218334Speter	  /* The rule for using CONST_INT for a wider mode
372318334Speter	     is that we regard the value as signed.
372418334Speter	     So sign-extend it.  */
372518334Speter	  rtx high = (INTVAL (value) < 0 ? constm1_rtx : const0_rtx);
372618334Speter	  if (WORDS_BIG_ENDIAN)
372718334Speter	    {
372818334Speter	      *first = high;
372918334Speter	      *second = value;
373018334Speter	    }
373118334Speter	  else
373218334Speter	    {
373318334Speter	      *first = value;
373418334Speter	      *second = high;
373518334Speter	    }
373618334Speter	}
373718334Speter    }
373818334Speter  else if (GET_CODE (value) != CONST_DOUBLE)
373918334Speter    {
374018334Speter      if (WORDS_BIG_ENDIAN)
374118334Speter	{
374218334Speter	  *first = const0_rtx;
374318334Speter	  *second = value;
374418334Speter	}
374518334Speter      else
374618334Speter	{
374718334Speter	  *first = value;
374818334Speter	  *second = const0_rtx;
374918334Speter	}
375018334Speter    }
375118334Speter  else if (GET_MODE (value) == VOIDmode
375218334Speter	   /* This is the old way we did CONST_DOUBLE integers.  */
375318334Speter	   || GET_MODE_CLASS (GET_MODE (value)) == MODE_INT)
375418334Speter    {
375518334Speter      /* In an integer, the words are defined as most and least significant.
375618334Speter	 So order them by the target's convention.  */
375718334Speter      if (WORDS_BIG_ENDIAN)
375818334Speter	{
375918334Speter	  *first = GEN_INT (CONST_DOUBLE_HIGH (value));
376018334Speter	  *second = GEN_INT (CONST_DOUBLE_LOW (value));
376118334Speter	}
376218334Speter      else
376318334Speter	{
376418334Speter	  *first = GEN_INT (CONST_DOUBLE_LOW (value));
376518334Speter	  *second = GEN_INT (CONST_DOUBLE_HIGH (value));
376618334Speter	}
376718334Speter    }
376818334Speter  else
376918334Speter    {
377018334Speter#ifdef REAL_ARITHMETIC
377190087Sobrien      REAL_VALUE_TYPE r;
377290087Sobrien      long l[2];
377318334Speter      REAL_VALUE_FROM_CONST_DOUBLE (r, value);
377418334Speter
377518334Speter      /* Note, this converts the REAL_VALUE_TYPE to the target's
377618334Speter	 format, splits up the floating point double and outputs
377718334Speter	 exactly 32 bits of it into each of l[0] and l[1] --
377850503Sobrien	 not necessarily BITS_PER_WORD bits.  */
377918334Speter      REAL_VALUE_TO_TARGET_DOUBLE (r, l);
378018334Speter
378152515Sobrien      /* If 32 bits is an entire word for the target, but not for the host,
378252515Sobrien	 then sign-extend on the host so that the number will look the same
378352515Sobrien	 way on the host that it would on the target.  See for instance
378452515Sobrien	 simplify_unary_operation.  The #if is needed to avoid compiler
378552515Sobrien	 warnings.  */
378652515Sobrien
378752515Sobrien#if HOST_BITS_PER_LONG > 32
378852515Sobrien      if (BITS_PER_WORD < HOST_BITS_PER_LONG && BITS_PER_WORD == 32)
378952515Sobrien	{
379052515Sobrien	  if (l[0] & ((long) 1 << 31))
379152515Sobrien	    l[0] |= ((long) (-1) << 32);
379252515Sobrien	  if (l[1] & ((long) 1 << 31))
379352515Sobrien	    l[1] |= ((long) (-1) << 32);
379452515Sobrien	}
379552515Sobrien#endif
379652515Sobrien
379718334Speter      *first = GEN_INT ((HOST_WIDE_INT) l[0]);
379818334Speter      *second = GEN_INT ((HOST_WIDE_INT) l[1]);
379918334Speter#else
380018334Speter      if ((HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
380118334Speter	   || HOST_BITS_PER_WIDE_INT != BITS_PER_WORD)
380218334Speter	  && ! flag_pretend_float)
380390087Sobrien	abort ();
380418334Speter
380518334Speter      if (
380618334Speter#ifdef HOST_WORDS_BIG_ENDIAN
380718334Speter	  WORDS_BIG_ENDIAN
380818334Speter#else
380918334Speter	  ! WORDS_BIG_ENDIAN
381018334Speter#endif
381118334Speter	  )
381218334Speter	{
381318334Speter	  /* Host and target agree => no need to swap.  */
381418334Speter	  *first = GEN_INT (CONST_DOUBLE_LOW (value));
381518334Speter	  *second = GEN_INT (CONST_DOUBLE_HIGH (value));
381618334Speter	}
381718334Speter      else
381818334Speter	{
381918334Speter	  *second = GEN_INT (CONST_DOUBLE_LOW (value));
382018334Speter	  *first = GEN_INT (CONST_DOUBLE_HIGH (value));
382118334Speter	}
382218334Speter#endif /* no REAL_ARITHMETIC */
382318334Speter    }
382418334Speter}
382518334Speter
382618334Speter/* Return nonzero if this function has no function calls.  */
382718334Speter
382818334Speterint
382918334Speterleaf_function_p ()
383018334Speter{
383118334Speter  rtx insn;
383290087Sobrien  rtx link;
383318334Speter
383490087Sobrien  if (current_function_profile || profile_arc_flag)
383518334Speter    return 0;
383618334Speter
383718334Speter  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
383818334Speter    {
383990087Sobrien      if (GET_CODE (insn) == CALL_INSN
384090087Sobrien	  && ! SIBLING_CALL_P (insn))
384118334Speter	return 0;
384218334Speter      if (GET_CODE (insn) == INSN
384318334Speter	  && GET_CODE (PATTERN (insn)) == SEQUENCE
384490087Sobrien	  && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN
384590087Sobrien	  && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0)))
384618334Speter	return 0;
384718334Speter    }
384890087Sobrien  for (link = current_function_epilogue_delay_list;
384990087Sobrien       link;
385090087Sobrien       link = XEXP (link, 1))
385118334Speter    {
385290087Sobrien      insn = XEXP (link, 0);
385390087Sobrien
385490087Sobrien      if (GET_CODE (insn) == CALL_INSN
385590087Sobrien	  && ! SIBLING_CALL_P (insn))
385618334Speter	return 0;
385790087Sobrien      if (GET_CODE (insn) == INSN
385890087Sobrien	  && GET_CODE (PATTERN (insn)) == SEQUENCE
385990087Sobrien	  && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == CALL_INSN
386090087Sobrien	  && ! SIBLING_CALL_P (XVECEXP (PATTERN (insn), 0, 0)))
386118334Speter	return 0;
386218334Speter    }
386318334Speter
386418334Speter  return 1;
386518334Speter}
386618334Speter
386790087Sobrien/* Return 1 if branch is an forward branch.
386890087Sobrien   Uses insn_shuid array, so it works only in the final pass.  May be used by
386990087Sobrien   output templates to customary add branch prediction hints.
387090087Sobrien */
387190087Sobrienint
387290087Sobrienfinal_forward_branch_p (insn)
387390087Sobrien     rtx insn;
387490087Sobrien{
387590087Sobrien  int insn_id, label_id;
387690087Sobrien  if (!uid_shuid)
387790087Sobrien    abort ();
387890087Sobrien  insn_id = INSN_SHUID (insn);
387990087Sobrien  label_id = INSN_SHUID (JUMP_LABEL (insn));
388090087Sobrien  /* We've hit some insns that does not have id information available.  */
388190087Sobrien  if (!insn_id || !label_id)
388290087Sobrien    abort ();
388390087Sobrien  return insn_id < label_id;
388490087Sobrien}
388590087Sobrien
388618334Speter/* On some machines, a function with no call insns
388718334Speter   can run faster if it doesn't create its own register window.
388818334Speter   When output, the leaf function should use only the "output"
388918334Speter   registers.  Ordinarily, the function would be compiled to use
389018334Speter   the "input" registers to find its arguments; it is a candidate
389118334Speter   for leaf treatment if it uses only the "input" registers.
389218334Speter   Leaf function treatment means renumbering so the function
389318334Speter   uses the "output" registers instead.  */
389418334Speter
389518334Speter#ifdef LEAF_REGISTERS
389618334Speter
389718334Speter/* Return 1 if this function uses only the registers that can be
389818334Speter   safely renumbered.  */
389918334Speter
390018334Speterint
390118334Speteronly_leaf_regs_used ()
390218334Speter{
390318334Speter  int i;
390490087Sobrien  char *permitted_reg_in_leaf_functions = LEAF_REGISTERS;
390518334Speter
390618334Speter  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
390750503Sobrien    if ((regs_ever_live[i] || global_regs[i])
390850503Sobrien	&& ! permitted_reg_in_leaf_functions[i])
390950503Sobrien      return 0;
391050503Sobrien
391150503Sobrien  if (current_function_uses_pic_offset_table
391250503Sobrien      && pic_offset_table_rtx != 0
391350503Sobrien      && GET_CODE (pic_offset_table_rtx) == REG
391450503Sobrien      && ! permitted_reg_in_leaf_functions[REGNO (pic_offset_table_rtx)])
391550503Sobrien    return 0;
391650503Sobrien
391718334Speter  return 1;
391818334Speter}
391918334Speter
392018334Speter/* Scan all instructions and renumber all registers into those
392118334Speter   available in leaf functions.  */
392218334Speter
392318334Speterstatic void
392418334Speterleaf_renumber_regs (first)
392518334Speter     rtx first;
392618334Speter{
392718334Speter  rtx insn;
392818334Speter
392918334Speter  /* Renumber only the actual patterns.
393018334Speter     The reg-notes can contain frame pointer refs,
393118334Speter     and renumbering them could crash, and should not be needed.  */
393218334Speter  for (insn = first; insn; insn = NEXT_INSN (insn))
393390087Sobrien    if (INSN_P (insn))
393418334Speter      leaf_renumber_regs_insn (PATTERN (insn));
393590087Sobrien  for (insn = current_function_epilogue_delay_list;
393690087Sobrien       insn;
393790087Sobrien       insn = XEXP (insn, 1))
393890087Sobrien    if (INSN_P (XEXP (insn, 0)))
393918334Speter      leaf_renumber_regs_insn (PATTERN (XEXP (insn, 0)));
394018334Speter}
394118334Speter
394218334Speter/* Scan IN_RTX and its subexpressions, and renumber all regs into those
394318334Speter   available in leaf functions.  */
394418334Speter
394518334Spetervoid
394618334Speterleaf_renumber_regs_insn (in_rtx)
394790087Sobrien     rtx in_rtx;
394818334Speter{
394990087Sobrien  int i, j;
395090087Sobrien  const char *format_ptr;
395118334Speter
395218334Speter  if (in_rtx == 0)
395318334Speter    return;
395418334Speter
395518334Speter  /* Renumber all input-registers into output-registers.
395618334Speter     renumbered_regs would be 1 for an output-register;
395718334Speter     they  */
395818334Speter
395918334Speter  if (GET_CODE (in_rtx) == REG)
396018334Speter    {
396118334Speter      int newreg;
396218334Speter
396318334Speter      /* Don't renumber the same reg twice.  */
396418334Speter      if (in_rtx->used)
396518334Speter	return;
396618334Speter
396718334Speter      newreg = REGNO (in_rtx);
396818334Speter      /* Don't try to renumber pseudo regs.  It is possible for a pseudo reg
396918334Speter	 to reach here as part of a REG_NOTE.  */
397018334Speter      if (newreg >= FIRST_PSEUDO_REGISTER)
397118334Speter	{
397218334Speter	  in_rtx->used = 1;
397318334Speter	  return;
397418334Speter	}
397518334Speter      newreg = LEAF_REG_REMAP (newreg);
397618334Speter      if (newreg < 0)
397718334Speter	abort ();
397818334Speter      regs_ever_live[REGNO (in_rtx)] = 0;
397918334Speter      regs_ever_live[newreg] = 1;
398018334Speter      REGNO (in_rtx) = newreg;
398118334Speter      in_rtx->used = 1;
398218334Speter    }
398318334Speter
398490087Sobrien  if (INSN_P (in_rtx))
398518334Speter    {
398618334Speter      /* Inside a SEQUENCE, we find insns.
398718334Speter	 Renumber just the patterns of these insns,
398818334Speter	 just as we do for the top-level insns.  */
398918334Speter      leaf_renumber_regs_insn (PATTERN (in_rtx));
399018334Speter      return;
399118334Speter    }
399218334Speter
399318334Speter  format_ptr = GET_RTX_FORMAT (GET_CODE (in_rtx));
399418334Speter
399518334Speter  for (i = 0; i < GET_RTX_LENGTH (GET_CODE (in_rtx)); i++)
399618334Speter    switch (*format_ptr++)
399718334Speter      {
399818334Speter      case 'e':
399918334Speter	leaf_renumber_regs_insn (XEXP (in_rtx, i));
400018334Speter	break;
400118334Speter
400218334Speter      case 'E':
400318334Speter	if (NULL != XVEC (in_rtx, i))
400418334Speter	  {
400518334Speter	    for (j = 0; j < XVECLEN (in_rtx, i); j++)
400618334Speter	      leaf_renumber_regs_insn (XVECEXP (in_rtx, i, j));
400718334Speter	  }
400818334Speter	break;
400918334Speter
401018334Speter      case 'S':
401118334Speter      case 's':
401218334Speter      case '0':
401318334Speter      case 'i':
401418334Speter      case 'w':
401518334Speter      case 'n':
401618334Speter      case 'u':
401718334Speter	break;
401818334Speter
401918334Speter      default:
402018334Speter	abort ();
402118334Speter      }
402218334Speter}
402318334Speter#endif
4024